Skip to main content

PanopticMath

Git Source

Author: Axicon Labs Limited

Contains Panoptic-specific helpers and math functions.

State Variables

MAX_UINT256

This is equivalent to type(uint256).max — used in assembly blocks as a replacement.

uint256 internal constant MAX_UINT256 = 2 ** 256 - 1;

TICKSPACING_MASK

Masks 16-bit tickSpacing out of 64-bit [16-bit tickspacing][48-bit poolPattern] format poolId

uint64 internal constant TICKSPACING_MASK = 0xFFFF000000000000;

Functions

getPoolId

Given a 256-bit Uniswap V4 pool ID (hash) and the corresponding tickSpacing, return its 64-bit ID as used in the TokenId of Panoptic.

function getPoolId(PoolId idV4, int24 tickSpacing) internal pure returns (uint64);

Parameters

NameTypeDescription
idV4PoolIdThe 256-bit Uniswap V4 pool ID
tickSpacingint24The tick spacing of the Uniswap V4 pool identified by idV4

Returns

NameTypeDescription
<none>uint64A fingerprint representing the Uniswap V4 pool

incrementPoolPattern

Increments the pool pattern (first 48 bits) of a poolId by 1.

function incrementPoolPattern(uint64 poolId) internal pure returns (uint64);

Parameters

NameTypeDescription
poolIduint64The 64-bit pool ID

Returns

NameTypeDescription
<none>uint64The provided poolId with its pool pattern slot incremented by 1

numberOfLeadingHexZeros

Get the number of leading hex characters in an address.

function numberOfLeadingHexZeros(address addr) external pure returns (uint256);

Parameters

NameTypeDescription
addraddressThe address to get the number of leading zero hex characters for

Returns

NameTypeDescription
<none>uint256The number of leading zero hex characters in the address

safeERC20Symbol

Returns ERC20 symbol of asset.

function safeERC20Symbol(address asset) external view returns (string memory);

Parameters

NameTypeDescription
assetaddressThe address of the asset to get the symbol of (address(0) = native asset)

Returns

NameTypeDescription
<none>stringThe symbol of asset or "???" if not supported

uniswapFeeToString

Converts fee to a string with "bps" appended, or DYNAMIC if "fee" is equivalent to 0x800000.

The lowest supported value of fee is 1 (="0.01bps").

function uniswapFeeToString(uint24 fee) internal pure returns (string memory);

Parameters

NameTypeDescription
feeuint24The fee to convert to a string (in hundredths of basis points)

Returns

NameTypeDescription
<none>stringStringified version of fee with "bps" appended

updatePositionsHash

Update an existing account's "positions hash" with a new tokenId.

The positions hash contains a fingerprint of all open positions created by an account/user and a count of those positions.

The "fingerprint" portion of the hash is given by XORing the hashed tokenId of each position the user has open together.

function updatePositionsHash(uint256 existingHash, TokenId tokenId, bool addFlag) internal pure returns (uint256);

Parameters

NameTypeDescription
existingHashuint256The existing position hash containing all historical N positions created and the count of the positions
tokenIdTokenIdThe new position to add to the existing hash: existingHash = uint248(existingHash) ^ hashOf(tokenId)
addFlagboolWhether to mint (add) the tokenId to the count of positions or burn (subtract) it from the count (existingHash >> 248) +/- 1

Returns

NameTypeDescription
<none>uint256newHash The new positionHash with the updated hash

getOracleTicks

Computes various oracle prices corresponding to a Uniswap pool.

function getOracleTicks(IV3CompatibleOracle oracleContract, uint256 miniMedian)
external
view
returns (int24 fastOracleTick, int24 slowOracleTick, int24 latestObservation, uint256 medianData);

Parameters

NameTypeDescription
oracleContractIV3CompatibleOracleThe external oracle contract to retrieve observations from
miniMedianuint256The packed structure representing the sorted 8-slot queue of internal median observations

Returns

NameTypeDescription
fastOracleTickint24The fast oracle tick computed as the median of the past N observations in the Uniswap Pool
slowOracleTickint24The slow oracle tick as tracked by s_miniMedian
latestObservationint24The latest observation from the Uniswap pool (price at the end of the last block)
medianDatauint256The updated value for s_miniMedian (returns 0 if not enough time has passed since last observation)

computeMedianObservedPrice

Returns the median of the last cardinality average prices over period observations from oracleContract.

Used when we need a manipulation-resistant TWAP price.

oracle observations snapshot the closing price of the last block before the first interaction of a given block.

The maximum frequency of observations is 1 per block, but there is no guarantee that the pool will be observed at every block.

Each period has a minimum length of blocktime period, but may be longer if the Uniswap pool is relatively inactive.*

The final price used in the array (of length cardinality) is the average of all observations comprising period (which is itself a number of observations).

Thus, the minimum total time window is cardinality period blocktime.

function computeMedianObservedPrice(
IV3CompatibleOracle oracleContract,
uint256 observationIndex,
uint256 observationCardinality,
uint256 cardinality,
uint256 period
) internal view returns (int24, int24);

Parameters

NameTypeDescription
oracleContractIV3CompatibleOracleThe external oracle contract to retrieve observations from
observationIndexuint256The index of the last observation in the pool
observationCardinalityuint256The number of observations in the pool
cardinalityuint256The number of periods to in the median price array, should be odd
perioduint256The number of observations to average to compute one entry in the median price array

Returns

NameTypeDescription
<none>int24The median of cardinality observations spaced by period in the Uniswap pool
<none>int24The latest observation in the Uniswap pool

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 oracle observation into the buffer, resorts, and returns if the last entry is at least period seconds old.

function computeInternalMedian(
uint256 observationIndex,
uint256 observationCardinality,
uint256 period,
uint256 medianData,
IV3CompatibleOracle oracleContract
) public view returns (int24 medianTick, uint256 updatedMedianData);

Parameters

NameTypeDescription
observationIndexuint256The index of the last observation in the Uniswap pool
observationCardinalityuint256The number of observations in the Uniswap pool
perioduint256The minimum time in seconds that must have passed since the last observation was inserted into the buffer
medianDatauint256The packed structure representing the sorted 8-slot queue of ticks
oracleContractIV3CompatibleOracleThe external oracle contract to retrieve observations from

Returns

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

twapFilter

Computes a TWAP price over twapWindow on a Uniswap V3-style observation oracle.

Note that our definition of TWAP differs from a typical mean of prices over a time window.

We instead observe the average price over a series of time intervals, and define the TWAP as the median of those averages.

function twapFilter(IV3CompatibleOracle oracleContract, uint32 twapWindow) external view returns (int24);

Parameters

NameTypeDescription
oracleContractIV3CompatibleOracleThe external oracle contract to retrieve observations from
twapWindowuint32The time window to compute the TWAP over

Returns

NameTypeDescription
<none>int24The final calculated TWAP tick

getLiquidityChunk

For a given option position (tokenId), leg index within that position (legIndex), and positionSize get the tick range spanned and its liquidity (share ownership) in the Uniswap V4 pool; this is a liquidity chunk.

function getLiquidityChunk(TokenId tokenId, uint256 legIndex, uint128 positionSize)
internal
pure
returns (LiquidityChunk);

Parameters

NameTypeDescription
tokenIdTokenIdThe option position id
legIndexuint256The leg index of the option position, can be {0,1,2,3}
positionSizeuint128The number of contracts held by this leg

Returns

NameTypeDescription
<none>LiquidityChunkA LiquidityChunk with tickLower, tickUpper, and liquidity

getTicks

Extract the tick range specified by strike and width for the given tickSpacing.

function getTicks(int24 strike, int24 width, int24 tickSpacing) internal pure returns (int24, int24);

Parameters

NameTypeDescription
strikeint24The strike price of the option
widthint24The width of the option
tickSpacingint24The tick spacing of the underlying Uniswap V4 pool

Returns

NameTypeDescription
<none>int24The lower tick of the liquidity chunk
<none>int24The upper tick of the liquidity chunk

getRangesFromStrike

Returns the distances of the upper and lower ticks from the strike for a position with the given width and tickSpacing.

Given `r = (width tickSpacing) / 2, tickLower = strike - floor(r)andtickUpper = strike + ceil(r)`.*

function getRangesFromStrike(int24 width, int24 tickSpacing) internal pure returns (int24, int24);

Parameters

NameTypeDescription
widthint24The width of the leg
tickSpacingint24The tick spacing of the underlying pool

Returns

NameTypeDescription
<none>int24The lower tick of the range
<none>int24The upper tick of the range

computeExercisedAmounts

Compute the amount of notional value underlying this option position.

function computeExercisedAmounts(TokenId tokenId, uint128 positionSize)
internal
pure
returns (LeftRightSigned longAmounts, LeftRightSigned shortAmounts);

Parameters

NameTypeDescription
tokenIdTokenIdThe option position id
positionSizeuint128The number of contracts of this option

Returns

NameTypeDescription
longAmountsLeftRightSignedLeft-right packed word where rightSlot = currency0 and leftSlot = currency1 held against borrowed Uniswap liquidity for long legs
shortAmountsLeftRightSignedLeft-right packed word where where rightSlot = currency0 and leftSlot = currency1 borrowed to create short legs

convert0to1

Convert an amount of currency0 into an amount of currency1 given the sqrtPriceX96 in a Uniswap pool defined as sqrt(1/0)*2^96.

Uses reduced precision after tick 443636 in order to accommodate the full range of ticks

function convert0to1(uint256 amount, uint160 sqrtPriceX96) internal pure returns (uint256);

Parameters

NameTypeDescription
amountuint256The amount of currency0 to convert into currency1
sqrtPriceX96uint160The square root of the price at which to convert amount of currency0 into currency1

Returns

NameTypeDescription
<none>uint256The converted amount of currency0 represented in terms of currency1

convert0to1RoundingUp

Convert an amount of currency0 into an amount of currency1 given the sqrtPriceX96 in a Uniswap pool defined as sqrt(1/0)*2^96.

Uses reduced precision after tick 443636 in order to accommodate the full range of ticks

function convert0to1RoundingUp(uint256 amount, uint160 sqrtPriceX96) internal pure returns (uint256);

Parameters

NameTypeDescription
amountuint256The amount of currency0 to convert into currency1
sqrtPriceX96uint160The square root of the price at which to convert amount of currency0 into currency1

Returns

NameTypeDescription
<none>uint256The converted amount of currency0 represented in terms of currency1

convert1to0

Convert an amount of currency1 into an amount of currency0 given the sqrtPriceX96 in a Uniswap pool defined as sqrt(1/0)*2^96.

Uses reduced precision after tick 443636 in order to accommodate the full range of ticks.

function convert1to0(uint256 amount, uint160 sqrtPriceX96) internal pure returns (uint256);

Parameters

NameTypeDescription
amountuint256The amount of currency1 to convert into currency0
sqrtPriceX96uint160The square root of the price at which to convert amount of currency1 into currency0

Returns

NameTypeDescription
<none>uint256The converted amount of currency1 represented in terms of currency0

convert1to0RoundingUp

Convert an amount of currency1 into an amount of currency0 given the sqrtPriceX96 in a Uniswap pool defined as sqrt(1/0)*2^96.

Uses reduced precision after tick 443636 in order to accommodate the full range of ticks.

function convert1to0RoundingUp(uint256 amount, uint160 sqrtPriceX96) internal pure returns (uint256);

Parameters

NameTypeDescription
amountuint256The amount of currency1 to convert into currency0
sqrtPriceX96uint160The square root of the price at which to convert amount of currency1 into currency0

Returns

NameTypeDescription
<none>uint256The converted amount of currency1 represented in terms of currency0

convert0to1

Convert an amount of currency0 into an amount of currency1 given the sqrtPriceX96 in a Uniswap pool defined as sqrt(1/0)*2^96.

Uses reduced precision after tick 443636 in order to accommodate the full range of ticks.

function convert0to1(int256 amount, uint160 sqrtPriceX96) internal pure returns (int256);

Parameters

NameTypeDescription
amountint256The amount of currency0 to convert into currency1
sqrtPriceX96uint160The square root of the price at which to convert amount of currency0 into currency1

Returns

NameTypeDescription
<none>int256The converted amount of currency0 represented in terms of currency1

convert1to0

Convert an amount of currency1 into an amount of currency0 given the sqrtPriceX96 in a Uniswap pool defined as sqrt(1/0)*2^96.

Uses reduced precision after tick 443636 in order to accommodate the full range of ticks.

function convert1to0(int256 amount, uint160 sqrtPriceX96) internal pure returns (int256);

Parameters

NameTypeDescription
amountint256The amount of currency1 to convert into currency0
sqrtPriceX96uint160The square root of the price at which to convert amount of currency1 into currency0

Returns

NameTypeDescription
<none>int256The converted amount of currency1 represented in terms of currency0

getCrossBalances

Get a single collateral balance and requirement in terms of the lowest-priced token for a given set of (currency0/currency1) collateral balances and requirements.

function getCrossBalances(LeftRightUnsigned tokenData0, LeftRightUnsigned tokenData1, uint160 sqrtPriceX96)
internal
pure
returns (uint256, uint256);

Parameters

NameTypeDescription
tokenData0LeftRightUnsignedLeftRight encoded word with balance of currency0 in the right slot, and required balance in left slot
tokenData1LeftRightUnsignedLeftRight encoded word with balance of currency1 in the right slot, and required balance in left slot
sqrtPriceX96uint160The price at which to compute the collateral value and requirements

Returns

NameTypeDescription
<none>uint256The combined collateral balance of tokenData0 and tokenData1 in terms of (currency0 if price(currency1/currency0) < 1 and vice versa)
<none>uint256The combined required collateral threshold of tokenData0 and tokenData1 in terms of (currency0 if price(currency1/currency0) < 1 and vice versa)

getAmountsMoved

Compute the notional value (for tokenType = 0 and tokenType = 1) represented by a given leg in an option position.

function getAmountsMoved(TokenId tokenId, uint128 positionSize, uint256 legIndex)
internal
pure
returns (LeftRightUnsigned);

Parameters

NameTypeDescription
tokenIdTokenIdThe option position identifier
positionSizeuint128The number of option contracts held in this position (each contract can control multiple tokens)
legIndexuint256The leg index of the option contract, can be {0,1,2,3}

Returns

NameTypeDescription
<none>LeftRightUnsignedA LeftRight encoded variable containing the amount0 and the amount1 value controlled by this option position's leg

_calculateIOAmounts

Compute the amount of funds that are moved to or removed from the Panoptic Pool when tokenId is created.

function _calculateIOAmounts(TokenId tokenId, uint128 positionSize, uint256 legIndex)
internal
pure
returns (LeftRightSigned longs, LeftRightSigned shorts);

Parameters

NameTypeDescription
tokenIdTokenIdThe option position identifier
positionSizeuint128The number of positions minted
legIndexuint256The leg index minted in this position, can be {0,1,2,3}

Returns

NameTypeDescription
longsLeftRightSignedA LeftRight-packed word containing the total amount of long positions
shortsLeftRightSignedA LeftRight-packed word containing the amount of short positions

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
) external pure returns (LeftRightSigned, LeftRightSigned);

Parameters

NameTypeDescription
tokenData0LeftRightUnsignedLeftRight encoded word with balance of currency0 in the right slot, and required balance in left slot
tokenData1LeftRightUnsignedLeftRight encoded word with balance of currency1 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

Returns

NameTypeDescription
<none>LeftRightSignedThe LeftRight-packed bonus amounts to be paid to the liquidator for both tokens (may be negative)
<none>LeftRightSignedThe LeftRight-packed protocol loss (pre-haircut) for both tokens, i.e., the delta between the user's starting balance and expended tokens

haircutPremia

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

Note that the storage mapping provided as the settledTokens parameter WILL be modified on the caller by this function.

function haircutPremia(
address liquidatee,
TokenId[] memory positionIdList,
LeftRightSigned[4][] memory premiasByLeg,
LeftRightSigned collateralRemaining,
CollateralTracker collateral0,
CollateralTracker collateral1,
uint160 atSqrtPriceX96,
mapping(bytes32 chunkKey => LeftRightUnsigned settledTokens) storage settledTokens
) external returns (LeftRightSigned);

Parameters

NameTypeDescription
liquidateeaddressThe address of the user being liquidated
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)
collateral0CollateralTrackerThe collateral tracker for currency0
collateral1CollateralTrackerThe collateral tracker for currency1
atSqrtPriceX96uint160The oracle price used to swap tokens between the liquidator/liquidatee and determine solvency for the liquidatee
settledTokensmapping(bytes32 chunkKey => LeftRightUnsigned settledTokens)The per-chunk accumulator of settled tokens in storage from which to subtract the haircut premium

Returns

NameTypeDescription
<none>LeftRightSignedThe delta, if any, to apply to the existing liquidation bonus

getExerciseDeltas

Redistribute the final exercise fee deltas between tokens if necessary according to the available collateral from the exercised user.

function getExerciseDeltas(
address exercisee,
LeftRightSigned exerciseFees,
int24 atTick,
CollateralTracker ct0,
CollateralTracker ct1
) external view returns (LeftRightSigned);

Parameters

NameTypeDescription
exerciseeaddressThe address of the user being exercised
exerciseFeesLeftRightSignedPre-adjustment exercise fees to debit from exercisor (rightSlot = currency0 left = currency1)
atTickint24The tick at which to convert between currency0/currency1 when redistributing the exercise fees
ct0CollateralTrackerThe collateral tracker for currency0
ct1CollateralTrackerThe collateral tracker for currency1

Returns

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