Skip to main content

RiskEngineXStocks

Source reference for public revision e3b9d12. For deployed configuration, select the pool's engine on the parameter page.

Git Source

Title: Panoptic Risk Engine: The central risk assessment and solvency calculator for the Panoptic Protocol.

Author: Axicon Labs Limited

This contract serves as the central logic hub for calculating collateral requirements, account solvency, and liquidation parameters.

This contract does not hold funds or state regarding user balances. Instead, it provides the mathematical framework to:

  1. Calculate collateral requirements for complex option strategies (Spreads, Strangles, Synthetic positions).
  2. Manage the internal pricing Oracle, utilizing volatility safeguards, EMAs, and median filters to prevent manipulation.
  3. Compute the Adaptive Interest Rate based on pool utilization (PID controller logic). Key responsibilities:
  • Verifying if an account is solvent (isAccountSolvent).
  • Calculating the cost to force-exercise a position (exerciseCost).
  • Determining liquidation bonuses (getLiquidationBonus).
  • Calculating dynamic collateral ratios based on pool utilization.

PARAMETER-ONLY FORK of RiskEngine.sol with more conservative ("xstocks") risk parameters (SELLER/BUYER_COLLATERAL_RATIO, MAINT_MARGIN_RATE, MAX_TICKS_DELTA, EMA_PERIODS). All non-parameter logic MUST be kept in sync with RiskEngine.sol.

State Variables
​

DECIMALS
​

Decimals for computation (1 millitick (1/1000th of a basis point) precision: 1e-7 = 0.00001%).

uint type for composability with unsigned integer based mathematical operations.

uint256 public constant DECIMALS = 10_000_000

MAX_UTILIZATION
​

int16 internal constant MAX_UTILIZATION = 10_000

LN2_SCALED
​

uint256 internal constant LN2_SCALED = 6931472

ONE_BPS
​

uint256 internal constant ONE_BPS = 1000

TEN_BPS
​

uint256 internal constant TEN_BPS = 10000

EMA_PERIODS
​

uint96 public constant EMA_PERIODS = uint96(120 + (240 << 24) + (480 << 48) + (1920 << 72))

MAX_TICKS_DELTA
​

The maximum allowed cumulative delta between the fast & slow oracle tick, the current & slow oracle tick, and the last-observed & slow oracle tick.

Falls back on the more conservative (less solvent) tick during times of extreme volatility, where the price moves ~10% in <4 minutes.

int256 public constant MAX_TICKS_DELTA = 953

MAX_TWAP_DELTA_DISPATCH
​

The maximum allowed delta between the currentTick and the TWAP tick during a dispatch/dispatchFrom call (~5% down, ~5.26% up).

Mitigates manipulation of the currentTick that causes positions to be force exercised at a less favorable price.

uint16 public constant MAX_TWAP_DELTA_DISPATCH = 513

MAX_SPREAD
​

The maximum allowed ratio for a single chunk, defined as removedLiquidity / netLiquidity.

The long premium spread multiplier that corresponds with the MAX_SPREAD value depends on VEGOID, which can be explored in this calculator: https://www.desmos.com/calculator/mdeqob2m04.

uint24 public constant MAX_SPREAD = 90_000

BP_DECREASE_BUFFER
​

Multiplier in basis points for the collateral requirement in the event of a buying power decrease, such as minting or force exercising another user.

must fit inside a uint26

uint32 public constant BP_DECREASE_BUFFER = 10_666_667

WAD
​

Decimals for WAD calculations.

int256 internal constant WAD = 1e18

IRM_MAX_ELAPSED_TIME
​

Constant, in seconds, used to determine the max elapsed time between adaptive interest rate updates.

the time elapsed will be capped at IRM_MAX_ELAPSED_TIME

int256 public constant IRM_MAX_ELAPSED_TIME = 16384

MAX_CLAMP_DELTA
​

The maximum amount of change, in ticks, permitted between internal median updates.

int24 public constant MAX_CLAMP_DELTA = 149

VEGOID
​

Parameter used to modify the equation of the utilization-based multiplier for long premium.

uint8 public constant VEGOID = 8

NOTIONAL_FEE
​

The notional fee, in basis points, collected from PLPs at option mint.

can never exceed 10000, so this value must fit inside a uint14 due to RiskParameters packing

uint16 public constant NOTIONAL_FEE = 3

PREMIUM_FEE
​

The premium fee, in basis points, collected from the premium paid/received.

can never exceed 10000, so this value must fit inside a uint14 due to RiskParameters packing

uint16 public constant PREMIUM_FEE = 250

PROTOCOL_SPLIT
​

The protocol split, in basis points, when a builder code is present.

can never exceed 10000, so this value must fit inside a uint14 due to RiskParameters packing

uint16 public constant PROTOCOL_SPLIT = 5_000

BUILDER_SPLIT
​

The builder split, in basis points, when a builder code is present

can never exceed 10000, so this value must fit inside a uint14 due to RiskParameters packing

uint16 public constant BUILDER_SPLIT = 4_000

SELLER_COLLATERAL_RATIO
​

Required collateral ratios for selling options, fraction of 1, scaled by 10_000_000.

i.e 20% -> 0.2 * 10_000_000 = 2_000_000.

uint256 public constant SELLER_COLLATERAL_RATIO = 3_300_000

BUYER_COLLATERAL_RATIO
​

Required collateral ratios for buying options, fraction of 1, scaled by 10_000_000.

i.e 10% -> 0.1 * 10_000_000 = 1_000_000.

uint256 public constant BUYER_COLLATERAL_RATIO = 1_500_000

MAINT_MARGIN_RATE
​

Required collateral margin for loans in excess of notional, fraction of 1, scaled by 10_000_000.

uint256 public constant MAINT_MARGIN_RATE = 2_500_000

FORCE_EXERCISE_COST
​

Basal cost (in bps of notional) applied by exerciseCost() when at least one long leg is in-range; fully out-of-the-money positions use ONE_BPS instead. 30bps

uint256 public constant FORCE_EXERCISE_COST = 30_000

TARGET_POOL_UTIL
​

Target pool utilization below which buying+selling is optimal, fraction of 1, scaled by 10_000_000.

i.e 50% -> 0.5 * 10_000_000 = 5_000_000.

uint256 public constant TARGET_POOL_UTIL = 6_666_667

SATURATED_POOL_UTIL
​

Pool utilization above which selling is 100% collateral backed, fraction of 1, scaled by 10_000_000.

i.e 90% -> 0.9 * 10_000_000 = 9_000_000.

uint256 public constant SATURATED_POOL_UTIL = 9_000_000

CROSS_BUFFER_0
​

Cross buffer parameter for token0.

uint256 public immutable CROSS_BUFFER_0

CROSS_BUFFER_1
​

Cross buffer parameter for token1.

uint256 public immutable CROSS_BUFFER_1

BUILDER_FACTORY
​

address public immutable BUILDER_FACTORY

BUILDER_INIT_CODE_HASH
​

bytes32 immutable BUILDER_INIT_CODE_HASH

MAX_OPEN_LEGS
​

Maximum number of open legs allowed.

uint256 public constant MAX_OPEN_LEGS = 26

MAX_BONUS
​

Max raw per-token bonus rate during liquidations (currently 20% of required)

The raw candidate is min(MAX_BONUS * required / DECIMALS, max(required - balance, 0)); getLiquidationBonus may shift it across tokens and caps positive realized bonuses at the liquidatee's backable collateral.

uint256 public constant MAX_BONUS = 2_000_000

CURVE_STEEPNESS
​

Curve steepness (scaled by WAD).

Curve steepness = 4.

int256 public constant CURVE_STEEPNESS = 4 ether

MIN_RATE_AT_TARGET
​

Minimum rate at target per second (scaled by WAD).

Minimum rate at target = 0.1% (minimum rate = 0.025%).

int256 public constant MIN_RATE_AT_TARGET = 0.001 ether / int256(365 days)

MAX_RATE_AT_TARGET
​

Maximum rate at target per second (scaled by WAD).

Maximum rate at target = 200% (maximum rate = 800%).

int256 public constant MAX_RATE_AT_TARGET = 2.0 ether / int256(365 days)

TARGET_UTILIZATION
​

Target utilization (scaled by WAD).

Target utilization = 66%.

int256 public constant TARGET_UTILIZATION = 2 ether / int256(3)

INITIAL_RATE_AT_TARGET
​

Initial rate at target per second (scaled by WAD).

Initial rate at target = 4% (rate between 1% and 16%).

int256 public constant INITIAL_RATE_AT_TARGET = 0.04 ether / int256(365 days)

ADJUSTMENT_SPEED
​

Adjustment speed per second (scaled by WAD).

The speed is per second, so the rate moves at a speed of ADJUSTMENT_SPEED * err each second (while being continuously compounded).

Adjustment speed = 50/year.

int256 public constant ADJUSTMENT_SPEED = 50 ether / int256(365 days)

GUARDIAN
​

Address allowed to override the automatically computed safe mode.

Guardian can only increase the effective safe mode, never relax it.

address public immutable GUARDIAN

Functions
​

constructor
​

Set immutable parameters for the Collateral Tracker.

constructor(uint256 _crossBuffer0, uint256 _crossBuffer1, address _guardian, address _builderFactory) ;

onlyGuardian
​

Restricts a function to be callable only by the guardian address.

modifier onlyGuardian() ;

_onlyGuardian
​

Reverts unless the caller is the guardian.

function _onlyGuardian() internal view;

lockPool
​

Forces a PanopticPool into locked safe mode.

Sets the pool’s internal oracle pack into permanent safe-mode override until explicitly unlocked by the guardian.

function lockPool(PanopticPoolV2 pool) external onlyGuardian;

Parameters

NameTypeDescription
poolPanopticPoolV2The PanopticPool to lock.

unlockPool
​

Removes the forced safe-mode lock on a PanopticPool.

Restores the pool to using only the automatically computed safe-mode level.

function unlockPool(PanopticPoolV2 pool) external onlyGuardian;

Parameters

NameTypeDescription
poolPanopticPoolV2The PanopticPool to unlock.

_computeBuilderWallet
​

Computes the deterministic address of a builder wallet using CREATE2

Returns zero address if builderCode is zero. Uses keccak256 hash of factory, salt, and init code hash

function _computeBuilderWallet(uint256 builderCode) internal view returns (address wallet);

Parameters

NameTypeDescription
builderCodeuint256The builder code used as the CREATE2 salt

Returns

NameTypeDescription
walletaddressThe computed address of the builder wallet

collect
​

Collects a specific amount of tokens from this contract

function collect(address token, address recipient, uint256 amount) public onlyGuardian;

Parameters

NameTypeDescription
tokenaddressThe address of the ERC20 token to collect
recipientaddressThe address to send the tokens to
amountuint256The amount of tokens to collect

collect
​

Collects all available tokens of a specific type from this contract

function collect(address token, address recipient) external onlyGuardian;

Parameters

NameTypeDescription
tokenaddressThe address of the ERC20 token to collect
recipientaddressThe address to send the tokens to

getRefundAmounts
​

Substitutes surplus tokens to a caller in exchange for any potential token shortages prior to revoking virtual shares from a payor.

function getRefundAmounts(
address payor,
LeftRightSigned fees,
int24 atTick,
CollateralTrackerV2 ct0,
CollateralTrackerV2 ct1
) external view returns (LeftRightSigned);

Parameters

NameTypeDescription
payoraddressThe address of the user being exercised/settled
feesLeftRightSignedIf applicable, fees to debit from caller (rightSlot = currency0 left = currency1), 0 for settleLongPremium
atTickint24The tick at which to convert between currency0/currency1 when redistributing the surplus tokens
ct0CollateralTrackerV2The collateral tracker for currency0
ct1CollateralTrackerV2The collateral tracker for currency1

Returns

NameTypeDescription
<none>LeftRightSignedThe LeftRight-packed deltas for currency0/currency1 to move from the caller to the payor

exerciseCost
​

Get the cost of exercising an option. Used during a forced exercise.

This one computes the cost of calling the forceExercise function on a position:

  • The forceExercisor will have to pay the exercisee because their position will be closed "against their will"
  • The cost must be larger when the position is in-range, and should be minimal when it is out of range
function exerciseCost(int24 currentTick, int24 oracleTick, TokenId tokenId, PositionBalance positionBalance)
external
pure
returns (LeftRightSigned exerciseFees);

Parameters

NameTypeDescription
currentTickint24The current price tick
oracleTickint24The price oracle tick
tokenIdTokenIdThe position to be exercised
positionBalancePositionBalanceThe position data of the position to be exercised

Returns

NameTypeDescription
exerciseFeesLeftRightSignedThe fees for exercising the option position

getLiquidationBonus
​

Compute the pre-haircut liquidation bonuses to be paid to the liquidator and the protocol loss caused by the liquidation (pre-haircut).

function getLiquidationBonus(
LeftRightUnsigned tokenData0,
LeftRightUnsigned tokenData1,
uint160 atSqrtPriceX96,
LeftRightSigned netPaid,
LeftRightUnsigned shortPremium,
LeftRightUnsigned creditAmounts
) external pure returns (LeftRightSigned, LeftRightSigned);

Parameters

NameTypeDescription
tokenData0LeftRightUnsignedLeftRight encoded word with balance of token0 in the right slot, and required balance in left slot
tokenData1LeftRightUnsignedLeftRight encoded word with balance of token1 in the right slot, and required balance in left slot
atSqrtPriceX96uint160The oracle price used to swap tokens between the liquidator/liquidatee and determine solvency for the liquidatee
netPaidLeftRightSignedThe net amount of tokens paid/received by the liquidatee to close their portfolio of positions
shortPremiumLeftRightUnsignedTotal owed premium (prorated by available settled tokens) across all short legs being liquidated
creditAmountsLeftRightUnsignedThe net credit amounts. Used to make adjustments to the balance amount to avoid double-counting credits

Returns

NameTypeDescription
<none>LeftRightSignedThe LeftRight-packed bonus amounts to be paid to the liquidator for both tokens (may be negative)
<none>LeftRightSignedThe LeftRight-packed collateral remaining after liquidation costs and bonus; negative slots represent protocol loss before premia haircut

_scaleFloorsToBackable
​

Scales the bonus floors down proportionally if their combined value exceeds the liquidatee's total backable collateral. See the call site for why this is global.

Denominate cap and value in the lower-priced token (token0 when price < 1, else token1). The cap/value ratio is the same in either token, but down-scaling sheds low bits, so we pick the side that multiplies up -- matching _isAccountSolvent. The two branches are exact token0<->token1 mirrors (invariant C5). Both conversions round the magnitude up, so the scale factor errs in the protocol's favor. value > cap >= 0 means value > 0, so the mulDiv can't divide by zero; floors are non-negative, so it's unsigned-safe.

function _scaleFloorsToBackable(int256 bonus0, int256 bonus1, int256 mb0, int256 mb1, uint160 atSqrtPriceX96)
internal
pure
returns (int256, int256);

Parameters

NameTypeDescription
bonus0int256The token0 bonus floor (>= 0)
bonus1int256The token1 bonus floor (>= 0)
mb0int256Signed backable in token0 (balance0 - netPaid0 - credits0)
mb1int256Signed backable in token1 (balance1 - netPaid1 - credits1)
atSqrtPriceX96uint160The oracle price used to value the cross-token cap

Returns

NameTypeDescription
<none>int256The scaled (bonus0, bonus1)
<none>int256

haircutPremia
​

Haircut/clawback any premium paid by liquidatee on positionIdList over the protocol loss threshold during a liquidation.

function haircutPremia(
TokenId[] memory positionIdList,
LeftRightSigned[4][] memory premiasByLeg,
LeftRightSigned collateralRemaining,
uint160 atSqrtPriceX96
)
external
pure
returns (LeftRightSigned bonusDeltas, LeftRightUnsigned haircutTotal, LeftRightSigned[4][] memory haircutPerLeg);

Parameters

NameTypeDescription
positionIdListTokenId[]The list of position ids being liquidated
premiasByLegLeftRightSigned[4][]The premium paid (or received) by the liquidatee for each leg of each position
collateralRemainingLeftRightSignedThe remaining collateral after the liquidation (negative if protocol loss)
atSqrtPriceX96uint160The oracle price used to swap tokens between the liquidator/liquidatee and determine solvency for the liquidatee

Returns

NameTypeDescription
bonusDeltasLeftRightSignedThe delta, if any, to apply to the existing liquidation bonus
haircutTotalLeftRightUnsignedTotal premium clawed back from the liquidatee
haircutPerLegLeftRightSigned[4][]Per-position/per-leg haircut amounts

getOracleTicks
​

Computes and returns all oracle ticks.

function getOracleTicks(int24 currentTick, OraclePack _oraclePack)
external
view
returns (int24 spotTick, int24 medianTick, int24 latestTick, OraclePack oraclePack);

Parameters

NameTypeDescription
currentTickint24The current tick in the Uniswap pool
_oraclePackOraclePackThe packed s_oraclePack storage slot containing the oracle's state,

Returns

NameTypeDescription
spotTickint24The spot oracle tick, sourced from the shortest EMA.
medianTickint24The median tick, calculated as the median of the 8 stored price points in the internal oracle.
latestTickint24The reconstructed absolute tick of the latest observation stored in the internal oracle.
oraclePackOraclePackThe current value of the 8-slot internal observation queue (s_oraclePack)

twapEMA
​

Calculates a slow-moving, weighted average price from the on-chain EMAs.

Extracts the fast, slow, and eons EMA tick values from the packed oraclePack structure. It then computes and returns a blended average with a 60/30/10 weighting respectively. This heavily smoothed value is designed to be highly resistant to manipulation and serves as a robust price feed for critical system functions like solvency checks.

function twapEMA(OraclePack oraclePack) external pure returns (int24);

Parameters

NameTypeDescription
oraclePackOraclePackThe packed s_oraclePack storage slot containing the oracle's state, including the on-chain EMAs.

Returns

NameTypeDescription
<none>int24The blended time-weighted average price, represented as an int24 tick.

computeInternalMedian
​

Takes a packed structure representing a sorted 8-slot queue of ticks and returns the median of those values and an updated queue if another observation is warranted.

Also inserts the latest Uniswap observation into the buffer, resorts, and returns if the last entry is at least period seconds old.

function computeInternalMedian(OraclePack oraclePack, int24 currentTick)
external
view
returns (int24 medianTick, OraclePack updatedOraclePack);

Parameters

NameTypeDescription
oraclePackOraclePackThe packed structure representing the sorted 8-slot queue of ticks
currentTickint24The current tick as return from slot0

Returns

NameTypeDescription
medianTickint24The median of the provided 8-slot queue of ticks in oraclePack
updatedOraclePackOraclePackThe updated 8-slot queue of ticks with the latest observation inserted if the last entry is at least period seconds old (returns 0 otherwise)

getRiskParameters
​

Computes and returns the risk parameters for the pool

function getRiskParameters(int24 currentTick, OraclePack oraclePack, uint256 builderCode)
external
view
returns (RiskParameters);

Parameters

NameTypeDescription
currentTickint24The current tick of the pool
oraclePackOraclePackThe oracle pack containing historical price data
builderCodeuint256The builder code for determining fee recipient

Returns

NameTypeDescription
<none>RiskParametersThe computed risk parameters including safe mode status and fee configuration

getFeeRecipient
​

Computes the fee recipient address from a builder code

function getFeeRecipient(uint256 builderCode) external view returns (address feeRecipient);

Parameters

NameTypeDescription
builderCodeuint256The builder code to compute the fee recipient from

Returns

NameTypeDescription
feeRecipientaddressThe computed fee recipient address

isSafeMode
​

Checks for significant oracle deviation to determine if Safe Mode should be active.

Safe Mode is triggered if ANY of three conditions are met:

  1. "External Shock": The live spot price deviates too far from the responsive spot EMA
  2. "Internal Disagreement": The fast EMA deviates too far from the more stable slow EMA, indicating high volatility
  3. "High Divergence": The EMAs show significant divergence from each other
function isSafeMode(int24 currentTick, OraclePack oraclePack) public pure returns (uint8 safeMode);

Parameters

NameTypeDescription
currentTickint24The current tick of the pool
oraclePackOraclePackThe oracle pack containing historical price data

Returns

NameTypeDescription
safeModeuint8A number representing whether the protocol is in Safe Mode.

getSolvencyTicks
​

Determines which ticks to check for solvency based on market volatility

function getSolvencyTicks(int24 currentTick, OraclePack _oraclePack, uint8 safeMode)
external
view
returns (int24[] memory, OraclePack);

Parameters

NameTypeDescription
currentTickint24The current tick of the pool
_oraclePackOraclePackThe oracle pack containing historical price data
safeModeuint8A number representing whether the protocol is in Safe Mode.

Returns

NameTypeDescription
<none>int24[]atTicks Array of ticks at which to check solvency
<none>OraclePackoraclePack The oracle pack (potentially updated)

isAccountSolvent
​

Get the collateral status/margin details of an account/user.

NOTE: It's up to the caller to confirm from the returned result that the account has enough collateral.

This can be used to check the health: how many tokens a user has compared to the margin threshold.

function isAccountSolvent(
PositionBalance[] calldata positionBalanceArray,
TokenId[] calldata positionIdList,
int24 atTick,
address user,
LeftRightUnsigned shortPremia,
LeftRightUnsigned longPremia,
CollateralTrackerV2 ct0,
CollateralTrackerV2 ct1,
uint256 buffer
) external view returns (bool);

Parameters

NameTypeDescription
positionBalanceArrayPositionBalance[]The list of all open positions held by the optionOwner, stored as [balance/poolUtilizationAtMint, ...]
positionIdListTokenId[]The list of all option positions held by user
atTickint24The tick at which to evaluate the account's positions
useraddressThe account to check collateral/margin health for
shortPremiaLeftRightUnsignedThe total amount of premium (prorated by available settled tokens) owed to the short legs of user
longPremiaLeftRightUnsignedThe total amount of premium owed by the long legs of user
ct0CollateralTrackerV2The Address of the CollateralTracker for token0
ct1CollateralTrackerV2The Address of the CollateralTracker for token1
bufferuint256The buffer to apply to the collateral requirement

Returns

NameTypeDescription
<none>boolWhether the account is solvent at the given tick

getMargin
​

Compute margin inputs for a user at a given tick.

Purely informational: does not make a solvency decision. Returns per-asset maintenance requirement (left slot) and available balance including settled premia (right slot). Units:

  • Requirements are in raw token units
  • Balances are in raw token units
  • Ratios elsewhere in the engine use DECIMALS = 10_000_000
function getMargin(
PositionBalance[] calldata positionBalanceArray,
int24 atTick,
address user,
TokenId[] calldata positionIdList,
LeftRightUnsigned shortPremia,
LeftRightUnsigned longPremia,
CollateralTrackerV2 ct0,
CollateralTrackerV2 ct1
)
external
view
returns (LeftRightUnsigned tokenData0, LeftRightUnsigned tokenData1, PositionBalance globalUtilizations);

Parameters

NameTypeDescription
positionBalanceArrayPositionBalance[]Array of [balanceOrUtilAtMint] for all open positions of user
atTickint24Tick at which exposures are valued
useraddressAccount to evaluate
positionIdListTokenId[]The list of all option positions held by user
shortPremiaLeftRightUnsignedTotal short premia owed to user (right slot = token0 credit, left slot = token1 credit)
longPremiaLeftRightUnsignedTotal long premia owed by user (right slot = token0 debit, left slot = token1 debit)
ct0CollateralTrackerV2CollateralTracker for token0
ct1CollateralTrackerV2CollateralTracker for token1

Returns

NameTypeDescription
tokenData0LeftRightUnsignedLeftRightUnsigned for token0 with left = maintenance requirement, right = available balance
tokenData1LeftRightUnsignedLeftRightUnsigned for token1 with left = maintenance requirement, right = available balance
globalUtilizationsPositionBalance

_getMargin
​

Internal workhorse for margin computation.

Aggregates balances, accrued interest, and per-position requirements to produce LeftRightUnsigned pairs for token0 and token1 where:

  • left slot = total maintenance requirement in that token
  • right slot = total available balance in that token including settled short premia Caller is responsible for any cross-asset conversion, haircuts, and final solvency logic.
function _getMargin(
PositionBalance[] calldata positionBalanceArray,
TokenId[] calldata positionIdList,
int24 atTick,
address user,
LeftRightUnsigned shortPremia,
LeftRightUnsigned longPremia,
CollateralTrackerV2 ct0,
CollateralTrackerV2 ct1
)
internal
view
returns (LeftRightUnsigned tokenData0, LeftRightUnsigned tokenData1, PositionBalance globalUtilizations);

Parameters

NameTypeDescription
positionBalanceArrayPositionBalance[]Array of [balanceOrUtilAtMint] for all open positions of user
positionIdListTokenId[]The list of all option positions held by user
atTickint24Tick at which exposures are valued
useraddressAccount to evaluate
shortPremiaLeftRightUnsignedTotal short premia owed to user (right slot = token0 credit, left slot = token1 credit)
longPremiaLeftRightUnsignedTotal long premia owed by user (right slot = token0 debit, left slot = token1 debit)
ct0CollateralTrackerV2CollateralTracker for token0
ct1CollateralTrackerV2CollateralTracker for token1

Returns

NameTypeDescription
tokenData0LeftRightUnsignedLeftRightUnsigned for token0 with left = maintenance requirement, right = available balance
tokenData1LeftRightUnsignedLeftRightUnsigned for token1 with left = maintenance requirement, right = available balance
globalUtilizationsPositionBalance

_getGlobalUtilization
​

Gets the highest pool utilization (for token0 and token1) from an array of positions.

Iterates through all of a user's positions to find the maximum utilization0 and maximum utilization1 recorded at the time of minting. These "global" max utilizations are then used for portfolio-level margin calculations, ensuring a more conservative risk assessment.

function _getGlobalUtilization(PositionBalance[] calldata positionBalanceArray)
internal
pure
returns (PositionBalance globalUtilizations);

Parameters

NameTypeDescription
positionBalanceArrayPositionBalance[]The array of a user's PositionBalance structs.

Returns

NameTypeDescription
globalUtilizationsPositionBalanceA packed PositionBalance that contains only the utilization data, recoverable as .utilization0() and .utilization1()

getPerPositionCollateralRequirements
​

Get the collateral requirement for each individual position in a list.

Returns net collateral requirements (required - credits) per position, packed as LeftRightUnsigned (token0: right, token1: left).

function getPerPositionCollateralRequirements(
PositionBalance[] calldata positionBalanceArray,
TokenId[] calldata positionIdList,
int24 atTick
) external pure returns (LeftRightUnsigned[] memory collateralRequirements);

Parameters

NameTypeDescription
positionBalanceArrayPositionBalance[]The list of all open positions, stored as [balance/poolUtilizationAtMint, ...]
positionIdListTokenId[]The list of all option positions
atTickint24The tick at which to evaluate positions

Returns

NameTypeDescription
collateralRequirementsLeftRightUnsigned[]Net collateral required per position [requirement_0, requirement_1, ...]

_getTotalRequiredCollateral
​

Get the total required amount of collateral tokens of a user/account across all active positions to stay above the margin requirement.

Returns the token amounts required for the entire account with active positions in positionIdList (list of tokenIds).

function _getTotalRequiredCollateral(
PositionBalance[] calldata positionBalanceArray,
TokenId[] calldata positionIdList,
int24 atTick,
LeftRightUnsigned longPremia
)
internal
pure
returns (LeftRightUnsigned tokensRequired, LeftRightUnsigned creditAmounts, PositionBalance globalUtilizations);

Parameters

NameTypeDescription
positionBalanceArrayPositionBalance[]The list of all open positions held by the optionOwner, stored as [balance/poolUtilizationAtMint, ...]
positionIdListTokenId[]The list of all option positions held by owner
atTickint24The tick at which to evaluate the account's positions
longPremiaLeftRightUnsigned

Returns

NameTypeDescription
tokensRequiredLeftRightUnsignedThe amount of token0 (right) and token1 (left) required to stay above the margin threshold for all active positions of user
creditAmountsLeftRightUnsignedThe amount of credit token0 (right) and token1 (left) in the user's portfolio
globalUtilizationsPositionBalance

_getRequiredCollateralAtTickSinglePosition
​

Get the required amount of collateral tokens corresponding to a specific single position tokenId at a price atTick.

function _getRequiredCollateralAtTickSinglePosition(
TokenId tokenId,
uint128 positionSize,
int24 atTick,
int16 poolUtilization,
bool underlyingIsToken0
) internal pure returns (uint256 tokenRequired, uint256 credits);

Parameters

NameTypeDescription
tokenIdTokenIdThe option position
positionSizeuint128The size of the option position
atTickint24The tick at which to evaluate the account's positions
poolUtilizationint16The utilization of the collateral vault (balance of buying and selling)
underlyingIsToken0boolCached s_underlyingIsToken0 value for this CollateralTracker instance

Returns

NameTypeDescription
tokenRequireduint256Total required tokens for all legs of the specified tokenId.
creditsuint256

_getRequiredCollateralSingleLeg
​

Calculate the required amount of collateral for a single leg index of position tokenId.

function _getRequiredCollateralSingleLeg(
TokenId tokenId,
uint256 index,
uint128 positionSize,
int24 atTick,
int16 poolUtilization
) internal pure returns (uint256 required);

Parameters

NameTypeDescription
tokenIdTokenIdThe option position
indexuint256The leg index (associated with a liquidity chunk) to compute the required collateral for
positionSizeuint128The size of the position
atTickint24The tick at which to evaluate the account's positions
poolUtilizationint16The pool utilization: how much funds are in the Panoptic pool versus the AMM pool

Returns

NameTypeDescription
requireduint256The required amount collateral needed for this leg index

_getRequiredCollateralSingleLegNoPartner
​

Calculate the required amount of collateral for leg index of position tokenId when the leg does not have a risk partner.

function _getRequiredCollateralSingleLegNoPartner(
TokenId tokenId,
uint256 index,
uint128 positionSize,
int24 atTick,
int16 poolUtilization
) internal pure returns (uint256 required);

Parameters

NameTypeDescription
tokenIdTokenIdThe option position
indexuint256The leg index (associated with a liquidity chunk) to consider a partner for
positionSizeuint128The size of the position
atTickint24The tick at which to evaluate the account's positions
poolUtilizationint16The pool utilization: ratio of how much funds are in the Panoptic pool versus the AMM pool

Returns

NameTypeDescription
requireduint256The required amount collateral needed for this leg index

_getRequiredCollateralSingleLegPartner
​

Calculate the required amount of collateral for leg index for position tokenId accounting for its partner leg.

If the two isLong fields are different (i.e., a short leg and a long leg are partnered) but the tokenTypes are the same, this is a spread.

A spread is a defined risk position which has a max loss given by difference between the long and short strikes.

If the two isLong fields are the same but the tokenTypes are different (one is a call, the other a put, e.g.), this is a strangle - a strangle benefits from enhanced capital efficiency because only one side can be ITM at any given time.

function _getRequiredCollateralSingleLegPartner(
TokenId tokenId,
uint256 index,
uint128 positionSize,
int24 atTick,
int16 poolUtilization
) internal pure returns (uint256);

Parameters

NameTypeDescription
tokenIdTokenIdThe option position
indexuint256The leg index (associated with a liquidity chunk) to consider a partner for
positionSizeuint128The size of the position
atTickint24The tick at which to evaluate the account's positions
poolUtilizationint16The pool utilization: how much funds are in the Panoptic pool versus the AMM pool

Returns

NameTypeDescription
<none>uint256required The required amount of collateral needed for this leg index

_getRequiredCollateralAtUtilization
​

Get the base collateral requirement for a position of notional value amount at the current Panoptic pool utilization level.

function _getRequiredCollateralAtUtilization(uint128 amount, uint256 isLong, int16 utilization)
internal
pure
returns (uint256 required, uint256 baseCollateralRatio);

Parameters

NameTypeDescription
amountuint128The amount to multiply by the base collateral ratio
isLonguint256Whether the position is long (=1) or short (=0)
utilizationint16The utilization of the Panoptic pool (balance between sellers and buyers)

Returns

NameTypeDescription
requireduint256The base collateral requirement corresponding to the incoming amount
baseCollateralRatiouint256

_computeSpread
​

Calculates the total collateral requirement for a defined-risk spread position.

A spread's collateral is the minimum of its defined max loss or the sum of its legs' individual (unpartnered) requirements.

This provides capital efficiency, as deep OTM spreads may require less collateral than their max loss due to OTM decay on the long leg.

function _computeSpread(
TokenId tokenId,
uint128 positionSize,
uint256 index,
uint256 partnerIndex,
int24 atTick,
int16 poolUtilization
) internal pure returns (uint256 spreadRequirement);

Parameters

NameTypeDescription
tokenIdTokenIdThe option position
positionSizeuint128The size of the position
indexuint256The leg index of the LONG leg in the spread position
partnerIndexuint256The index of the partnered SHORT leg in the spread position
atTickint24the tick the requirement is evaluated at
poolUtilizationint16The pool utilization: how much funds are in the Panoptic pool versus the AMM pool

Returns

NameTypeDescription
spreadRequirementuint256The required amount of collateral needed for the spread

_computeStrangle
​

Calculate the required amount of collateral for a strangle leg.

The base collateral requirement is halved for short strangles.

A strangle can only have only one of its legs ITM at any given time, so this reduces the total risk and collateral requirement.

function _computeStrangle(TokenId tokenId, uint256 index, uint128 positionSize, int24 atTick, int16 poolUtilization)
internal
pure
returns (uint256 strangleRequired);

Parameters

NameTypeDescription
tokenIdTokenIdThe option position
indexuint256The leg index (associated with a liquidity chunk) to consider a partner for
positionSizeuint128The size of the position
atTickint24The tick at which to evaluate the account's positions
poolUtilizationint16The pool utilization: how much funds are in the Panoptic pool versus the AMM pool

Returns

NameTypeDescription
strangleRequireduint256The required amount of collateral needed for the strangle leg

_computeLoanOptionComposite
​

Computes the required collateral for a composite position with a loan option strategy

Calculates requirements for both the loan leg and its partner, returning the maximum of the two

function _computeLoanOptionComposite(
TokenId tokenId,
uint128 positionSize,
uint256 index,
uint256 partnerIndex,
int24 atTick,
int16 poolUtilization
) internal pure returns (uint256);

Parameters

NameTypeDescription
tokenIdTokenIdThe token ID representing the position
positionSizeuint128The size of the position in contracts
indexuint256The leg index of the loan option
partnerIndexuint256The leg index of the partner to the loan option
atTickint24The tick at which to evaluate the collateral requirement
poolUtilizationint16The current pool utilization percentage

Returns

NameTypeDescription
<none>uint256The required collateral amount for the composite position

_computeCreditOptionComposite
​

Computes the required collateral for a composite position with a credit option strategy

Assumes 100% utilization (cash account requirement) for sold options. Only called when partnerIndex is the credit

function _computeCreditOptionComposite(TokenId tokenId, uint128 positionSize, uint256 index, int24 atTick)
internal
pure
returns (uint256);

Parameters

NameTypeDescription
tokenIdTokenIdThe token ID representing the position
positionSizeuint128The size of the position in contracts
indexuint256The leg index of the option
atTickint24The tick at which to evaluate the collateral requirement

Returns

NameTypeDescription
<none>uint256The required collateral amount for the credit option

_sellCollateralRatio
​

Get the base collateral requirement for a short leg at a given pool utilization.

This is computed at the time the position is minted.

function _sellCollateralRatio(int256 utilization, uint256 minRatio)
internal
pure
returns (uint256 sellCollateralRatio);

Parameters

NameTypeDescription
utilizationint256The pool utilization of this collateral vault at the time the position is minted
minRatiouint256The minimum (base) ratio

Returns

NameTypeDescription
sellCollateralRatiouint256The sell collateral ratio at utilization

_buyCollateralRatio
​

Get the base collateral requirement for a long leg at a given pool utilization.

This is computed at the time the position is minted.

function _buyCollateralRatio() internal pure returns (uint256 buyCollateralRatio);

Returns

NameTypeDescription
buyCollateralRatiouint256The buy collateral ratio at utilization

crossBufferRatio
​

Get the cross buffer ration for a given utilization

This is computed using the global utilization of the user.

function crossBufferRatio(int256 utilization, uint256 crossBuffer) public pure returns (uint256);

Parameters

NameTypeDescription
utilizationint256The pool utilization of this collateral vault at the time the position is minted
crossBufferuint256

Returns

NameTypeDescription
<none>uint256The cross buffer ratio at utilization

interestRate
​

Calculates the current interest rate based on utilization

function interestRate(uint256 utilization, MarketState interestRateAccumulator) external view returns (uint128);

Parameters

NameTypeDescription
utilizationuint256The current pool utilization
interestRateAccumulatorMarketStateThe current state of the interest rate accumulator

Returns

NameTypeDescription
<none>uint128The calculated interest rate per second

updateInterestRate
​

Calculates both the average interest rate and the new rate at target

function updateInterestRate(uint256 utilization, MarketState interestRateAccumulator)
external
view
returns (uint128, uint256);

Parameters

NameTypeDescription
utilizationuint256The current pool utilization
interestRateAccumulatorMarketStateThe current state of the interest rate accumulator

Returns

NameTypeDescription
<none>uint128The average interest rate
<none>uint256The new rate at target

_borrowRate
​

Returns avgRate and endRateAtTarget.

Assumes that the inputs marketParams and id match.

function _borrowRate(uint256 utilization, MarketState interestRateAccumulator)
internal
view
returns (uint256, int256);

_curve
​

Applies a piecewise linear curve to compute the interest rate based on error from target

Formula: r = ((1-1/C)err + 1) rateAtTarget if err < 0, else ((C-1)err + 1) rateAtTarget, where C is curve steepness

function _curve(int256 _rateAtTarget, int256 err) private pure returns (int256);

Parameters

NameTypeDescription
_rateAtTargetint256The base rate at target utilization
errint256The error/deviation from target utilization

Returns

NameTypeDescription
<none>int256The adjusted interest rate after applying the curve

_newRateAtTarget
​

Computes a new rate at target by applying exponential adaptation and bounding the result

Formula: max(min(startRateAtTarget * exp(linearAdaptation), maxRateAtTarget), minRateAtTarget)

function _newRateAtTarget(int256 startRateAtTarget, int256 linearAdaptation) private pure returns (int256);

Parameters

NameTypeDescription
startRateAtTargetint256The starting rate at target utilization
linearAdaptationint256The linear adaptation factor to apply exponentially

Returns

NameTypeDescription
<none>int256newRateAtTarget The new bounded rate at target utilization

vegoid
​

Returns the stored VEGOID parameter

function vegoid() external pure returns (uint8);

Events
​

BorrowRateUpdated
​

Emitted when a borrow rate is updated.

event BorrowRateUpdated(address indexed collateralToken, uint256 avgBorrowRate, uint256 rateAtTarget);

TokensCollected
​

Emitted when tokens are collected from the contract

event TokensCollected(address indexed token, address indexed recipient, uint256 amount);

Parameters

NameTypeDescription
tokenaddressThe address of the token collected
recipientaddressThe address receiving the tokens
amountuint256The amount of tokens collected

GuardianSafeModeUpdated
​

Emitted when the guardian updates the enforced safe mode.

event GuardianSafeModeUpdated(bool lockMode);

Parameters

NameTypeDescription
lockModeboolTrue when safe mode is forcibly locked, false when the lock is lifted.
Table of Contents