Skip to content
Merged

PMRM2 #362

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 1 addition & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,6 @@ jobs:

- name: Check format
run: forge fmt --check

- name: Run tests
run: forge test -vvv

- name: Run Coverage
run: forge coverage --report lcov

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
directory: .
env_vars: OS,PYTHON
fail_ci_if_error: true
files: ./lcov.info
name: lyra-v2
verbose: true
run: forge coverage --report summary
21 changes: 13 additions & 8 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,23 @@ License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.

Parameters

Licensor: Lyra Foundation
Licensor:
Lyra Foundation

Licensed Work: Lyra V2 Core
The Licensed Work is (c) 2023 Lyra Foundation
Licensed Work:
Lyra V2 Core The Licensed Work is (c) 2023-2025 Lyra Foundation

Additional Use Grant: Any uses listed and defined at
v2-core-license-grants.lyra.eth
Additional Use Grant:
Any uses listed and defined at v2-core-license-grants.lyra.eth

Change Date: The earlier of 2025-11-16 or a date specified at
v2-core-license-date.lyra.eth
Change Date:
- For code released before 2025-02-17:
The earlier of 2025-11-16 or a date specified at v2-core-license-date.lyra.eth
- For code released on or after 2025-02-17:
The earlier of 2029-03-20 or a date specified at v2-core-license-date.lyra.eth

Change License: GNU General Public License v3.0 or later
Change License:
GNU General Public License v3.0 or later

-----------------------------------------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion codecov.yaml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
ignore:
- "test"
- "test"
2 changes: 1 addition & 1 deletion foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ src = 'src'
out = 'out'

optimizer = true
optimizer_runs = 800
optimizer_runs = 100
fs_permissions = [{ access = "read-write", path = "./"}]

solc_version = "0.8.27"
Expand Down
3 changes: 1 addition & 2 deletions src/feeds/static/LyraRateFeedStatic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@ contract LyraRateFeedStatic is Ownable2Step, IInterestRateFeed {
int64 public rate;
uint64 public confidence;

constructor() Ownable(msg.sender) {}

////////////////////////
// Public Functions //
////////////////////////
constructor() Ownable(msg.sender) {}

function setRate(int64 _rate, uint64 _confidence) external onlyOwner {
if (_rate > 1e18 || _rate < -1e18) revert LRFS_StaticRateOutOfRange();
Expand Down
141 changes: 141 additions & 0 deletions src/interfaces/IPMRMLib_2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

import {IPMRM_2} from "./IPMRM_2.sol";

interface IPMRMLib_2 {
struct VolShockParameters {
/// @dev Multiplicative factor for up vol shocks
uint volRangeUp;
/// @dev Multiplicative factor for down vol shocks
uint volRangeDown;
/// @dev exponential used for scaling the vol shock for shorter dated expiries (<30dte)
int shortTermPower;
/// @dev exponential used for scaling the vol shock for longer dated expiries (>30dte)
int longTermPower;
/// @dev Minimum DTE used for scaling the vol shock
uint dteFloor;
/// @dev Minimum vol shock applied in vol up scenarios (i.e. use max(shocked vol, minVolUpShock))
uint minVolUpShock;
}

struct MarginParameters {
/// @dev Multiplicative factor used to scale the minSPAN to get IM
uint imFactor;
/// @dev Multiplicative factor used to scale the minSPAN to get MM
uint mmFactor;
/// @dev Multiplicative factor for static discount calculation, for negative expiry MtM discounting
uint shortRateMultScale;
/// @dev Multiplicative factor for static discount calculation, for positive expiry MtM discounting
uint longRateMultScale;
/// @dev Additive factor for static discount calculation, for negative expiry MtM discounting
uint shortRateAddScale;
/// @dev Additive factor for static discount calculation, for positive expiry MtM discounting
uint longRateAddScale;
/// @dev The baseStaticDiscount for computing static discount for negative expiry MtM discounting
uint shortBaseStaticDiscount;
/// @dev The baseStaticDiscount for computing static discount for positive expiry MtM discounting
uint longBaseStaticDiscount;
}

struct BasisContingencyParameters {
/// @dev the spot shock used for the up scenario for basis contingency
uint scenarioSpotUp;
/// @dev the spot shock used for the down scenario for basis contingency
uint scenarioSpotDown;
/// @dev factor used in conjunction with mult factor to scale the basis contingency
uint basisContAddFactor;
/// @dev factor used in conjunction with add factor to scale the basis contingency
uint basisContMultFactor;
}

struct OtherContingencyParameters {
/// @dev Below this threshold, we consider the stable asset de-pegged, so we add additional contingency
uint pegLossThreshold;
/// @dev If below the peg loss threshold, we add this contingency
uint pegLossFactor;
/// @dev Below this threshold, IM is affected by confidence contingency
uint confThreshold;
/// @dev Percentage of spot used for confidence contingency, scales with the minimum contingency seen.
uint confMargin;
/// @dev Contingency applied to perps held in the portfolio, multiplied by spot
uint MMPerpPercent;
/// @dev Contingency applied to perps held in the portfolio, multiplied by spot, added on top of MMPerpPercent
uint IMPerpPercent;
/// @dev Factor for multiplying number of naked shorts (per strike) in the portfolio, multiplied by spot.
uint MMOptionPercent;
/// @dev Factor for multiplying number of naked shorts (per strike) in the portfolio, multiplied by spot,
/// added on top of MMOptionPercent for IM
uint IMOptionPercent;
}

/// @dev A collection of parameters used within the abs/linear skew shock scenario calculations
struct SkewShockParameters {
uint linearBaseCap;
uint absBaseCap;
int linearCBase;
int absCBase;
int minKStar;
int widthScale;
int volParamStatic;
int volParamScale;
}

// Defined once per collateral
struct CollateralParameters {
bool isEnabled;
bool isRiskCancelling;
/// @dev % value of collateral to subtract from MM. Must be <= 1
uint MMHaircut;
/// @dev % value of collateral to subtract from IM. Added on top of MMHaircut. Must be <= 1
uint IMHaircut;
}

function getMarginAndMarkToMarket(
IPMRM_2.Portfolio memory portfolio,
bool isInitial,
IPMRM_2.Scenario[] memory scenarios
) external view returns (int margin, int markToMarket, uint worstScenario);

function getScenarioPnL(IPMRM_2.Portfolio memory portfolio, IPMRM_2.Scenario memory scenario)
external
view
returns (int scenarioMtM);

function addPrecomputes(IPMRM_2.Portfolio memory portfolio) external view returns (IPMRM_2.Portfolio memory);

function getBasisContingencyScenarios() external view returns (IPMRM_2.Scenario[] memory);

function getCollateralParameters(address collateral) external view returns (CollateralParameters memory);

////////////
// Events //
////////////
event BasisContingencyParamsUpdated(IPMRMLib_2.BasisContingencyParameters basisContParams);
event OtherContingencyParamsUpdated(IPMRMLib_2.OtherContingencyParameters otherContParams);
event MarginParamsUpdated(IPMRMLib_2.MarginParameters marginParams);
event VolShockParamsUpdated(IPMRMLib_2.VolShockParameters volShockParams);
event SkewShockParamsUpdated(IPMRMLib_2.SkewShockParameters skewShockParams);
event CollateralParametersUpdated(address asset, IPMRMLib_2.CollateralParameters params);

////////////
// Errors //
////////////

/// @dev emitted when provided forward contingency parameters are invalid
error PMRML2_InvalidBasisContingencyParameters();
/// @dev emitted when provided other contingency parameters are invalid
error PMRML2_InvalidOtherContingencyParameters();
/// @dev emitted when provided static discount parameters are invalid
error PMRML2_InvalidMarginParameters();
/// @dev emitted when provided vol shock parameters are invalid
error PMRML2_InvalidVolShockParameters();
/// @dev emitted when provided skew shock parameters are invalid
error PMRML2_InvalidSkewShockParameters();
/// @dev emitted when provided collateral parameters are invalid
error PMRML2_InvalidCollateralParameters();
/// @dev emitted when invalid parameters passed into _getMarginAndMarkToMarket
error PMRML2_InvalidGetMarginState();
/// @dev emitted when doing a risk check on a disabled collateral
error PMRML2_CollateralDisabled();
}
121 changes: 121 additions & 0 deletions src/interfaces/IPMRM_2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.18;

import {ISpotFeed} from "./ISpotFeed.sol";
import {IForwardFeed} from "./IForwardFeed.sol";
import {IInterestRateFeed} from "./IInterestRateFeed.sol";
import {IVolFeed} from "./IVolFeed.sol";

interface IPMRM_2 {
enum VolShockDirection {
None,
Up,
Down,
Linear,
Abs
}

struct Feeds {
ISpotFeed spotFeed;
ISpotFeed stableFeed;
IForwardFeed forwardFeed;
IInterestRateFeed interestRateFeed;
IVolFeed volFeed;
}

struct Portfolio {
uint spotPrice;
uint perpPrice;
uint stablePrice;
/// cash amount or debt
int cash;
/// option holdings per expiry
ExpiryHoldings[] expiries;
CollateralHoldings[] collaterals;
int perpPosition;
int totalMtM;
// Calculated values
int basisContingency;
// option + base + perp; excludes fwd/oracle
uint MMContingency;
uint IMContingency;
uint minConfidence;
int perpValue;
}

struct CollateralHoldings {
address asset;
uint value;
uint minConfidence;
}

struct ExpiryHoldings {
// used as key
uint expiry;
uint secToExpiry;
StrikeHolding[] options;
// portion unaffected by spot shocks
uint forwardFixedPortion;
// portion affected by spot shocks
uint forwardVariablePortion;
// We always assume the rate is >= 0
uint rate;
uint64 discount;
uint minConfidence;
uint netOptions;
int mtm;
int basisScenarioUpMtM;
int basisScenarioDownMtM;
uint volShockUp;
uint volShockDown;
uint staticDiscountPos;
uint staticDiscountNeg;
}

struct StrikeHolding {
/// strike price of held options
uint strike;
uint vol;
int amount;
bool isCall;
bool seenInFilter;
}

struct PortfolioExpiryData {
uint64 expiry;
uint optionCount;
}

struct Scenario {
uint spotShock; // i.e. 1.2e18 = 20% spot shock up
VolShockDirection volShock; // i.e. [None, Up, Down, Linear, Abs]
// Multiply the result by this percentage. Can be > 1
uint dampeningFactor;
}

////////////////
// Events //
////////////////
event MaxExpiriesUpdated(uint maxExpiries);
event InterestRateFeedUpdated(IInterestRateFeed interestRateFeed);
event VolFeedUpdated(IVolFeed volFeed);
event SpotFeedUpdated(ISpotFeed spotFeed);
event StableFeedUpdated(ISpotFeed stableFeed);
event ForwardFeedUpdated(IForwardFeed forwardFeed);
event CollateralSpotFeedUpdated(address asset, ISpotFeed feed);
event ScenariosUpdated(Scenario[] scenarios);

////////////
// Errors //
////////////
error PMRM_2_InvalidSpotShock();
error PMRM_2_UnsupportedAsset();
error PMRM_2_InsufficientMargin();
error PMRM_2_InvalidScenarios();
error PMRM_2_InvalidMaxExpiries();
error PMRM_2_FindInArrayError();
error PMRM_2_OptionExpired();
error PMRM_2_TooManyExpiries();
error PMRM_2_TooManyAssets();
error PMRM_2_InvalidCollateralAsset();
}
Loading
Loading