Skip to content

Commit

Permalink
feat: panoptic v1.1
Browse files Browse the repository at this point in the history
  • Loading branch information
dyedm1 committed Oct 10, 2024
1 parent 0a333bc commit 58bc7f2
Show file tree
Hide file tree
Showing 39 changed files with 4,174 additions and 4,706 deletions.
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,9 @@
[submodule "lib/solady"]
path = lib/solady
url = https://github.com/vectorized/solady
[submodule "lib/v4-core"]
path = lib/v4-core
url = https://github.com/Uniswap/v4-core.git
[submodule "lib/clones-with-immutable-args"]
path = lib/clones-with-immutable-args
url = https://github.com/wighawag/clones-with-immutable-args
343 changes: 185 additions & 158 deletions contracts/CollateralTracker.sol

Large diffs are not rendered by default.

269 changes: 162 additions & 107 deletions contracts/PanopticFactory.sol

Large diffs are not rendered by default.

310 changes: 158 additions & 152 deletions contracts/PanopticPool.sol

Large diffs are not rendered by default.

851 changes: 317 additions & 534 deletions contracts/SemiFungiblePositionManager.sol

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions contracts/base/FactoryNFT.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pragma solidity ^0.8.24;
import {PanopticMath} from "@libraries/PanopticMath.sol";
import {PanopticPool} from "@contracts/PanopticPool.sol";
// Inherited implementations
import {ERC721} from "solmate/tokens/ERC721.sol";
import {ERC721} from "solmate/src/tokens/ERC721.sol";
import {MetadataStore} from "@base/MetadataStore.sol";
// Custom types
import {Pointer} from "@types/Pointer.sol";
Expand All @@ -30,7 +30,7 @@ contract FactoryNFT is MetadataStore, ERC721 {
Pointer[][] memory pointers
)
MetadataStore(properties, indices, pointers)
ERC721("Panoptic V1 Factory Deployer NFTs", "PANOPTIC-NFT")
ERC721("Panoptic V1.1 Factory Deployer NFTs", "PANOPTIC-NFT")
{}

/// @notice Returns the metadata URI for a given `tokenId`.
Expand All @@ -44,9 +44,9 @@ contract FactoryNFT is MetadataStore, ERC721 {
return
constructMetadata(
panopticPool,
PanopticMath.safeERC20Symbol(PanopticPool(panopticPool).univ3pool().token0()),
PanopticMath.safeERC20Symbol(PanopticPool(panopticPool).univ3pool().token1()),
PanopticPool(panopticPool).univ3pool().fee()
PanopticMath.safeERC20Symbol(PanopticPool(panopticPool).collateralToken0().asset()),
PanopticMath.safeERC20Symbol(PanopticPool(panopticPool).collateralToken1().asset()),
PanopticPool(panopticPool).poolKey().fee
);
}

Expand Down
71 changes: 71 additions & 0 deletions contracts/interfaces/IV3CompatibleOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Interface defining the oracle contract used by Panoptic, which may be a Uniswap V3 pool or custom implementation
/// @author Axicon Labs Inc, credit to Uniswap Labs [https://github.com/Uniswap/v3-core](https://github.com/Uniswap/v3-core) under GPL-2.0 license
/// @notice This interface defines the set of functions called by Panoptic on its external oracle contract.
/// @dev The interface is compatible with Uniswap V3 pools, but can also be implemented by a custom oracle contract.
interface IV3CompatibleOracle {
/// @notice The 0th storage slot in the oracle stores many values, and is exposed as a single method to save gas
/// when accessed externally.
/// @return sqrtPriceX96 The current price of the oracle as a sqrt(token1/token0) Q64.96 value
/// @return tick The current tick of the oracle, i.e. according to the last tick transition that was run.
/// This value may not always be equal to SqrtTickMath.getTickAtSqrtRatio(sqrtPriceX96) if the price is on a tick
/// boundary
/// @return observationIndex The index of the last oracle observation that was written
/// @return observationCardinality The current maximum number of observations stored in the oracle
function slot0()
external
view
returns (
uint160 sqrtPriceX96,
int24 tick,
uint16 observationIndex,
uint16 observationCardinality,
uint16,
uint8,
bool
);

/// @notice Returns data about a specific observation index
/// @param index The element of the observations array to fetch
/// @return blockTimestamp The timestamp of the observation
/// @return tickCumulative The tick multiplied by seconds elapsed for the life of the pool as of the observation timestamp
/// @return secondsPerLiquidityCumulativeX128 The seconds per in range liquidity for the life of the pool as of the observation timestamp
/// @return initialized Whether the observation has been initialized and the values are safe to use
function observations(
uint256 index
)
external
view
returns (
uint32 blockTimestamp,
int56 tickCumulative,
uint160 secondsPerLiquidityCumulativeX128,
bool initialized
);

/// @notice Returns the cumulative tick and liquidity as of each timestamp `secondsAgo` from the current block timestamp
/// @dev To get a time weighted average tick or liquidity-in-range, you must call this with two values, one representing
/// the beginning of the period and another for the end of the period. E.g., to get the last hour time-weighted average tick,
/// you must call it with secondsAgos = [3600, 0].
/// @dev The time weighted average tick represents the geometric time weighted average price of the pool, in
/// log base sqrt(1.0001) of token1 / token0. The TickMath library can be used to go from a tick value to a ratio.
/// @param secondsAgos From how long ago each cumulative tick and liquidity value should be returned
/// @return tickCumulatives Cumulative tick values as of each `secondsAgos` from the current block timestamp
/// @return secondsPerLiquidityCumulativeX128s Cumulative seconds per liquidity-in-range value as of each `secondsAgos` from the current block
/// timestamp
function observe(
uint32[] calldata secondsAgos
)
external
view
returns (
int56[] memory tickCumulatives,
uint160[] memory secondsPerLiquidityCumulativeX128s
);

/// @notice Increase the maximum number of price and liquidity observations that this oracle will store
/// @param observationCardinalityNext The desired minimum number of observations for the oracle to store
function increaseObservationCardinalityNext(uint16 observationCardinalityNext) external;
}
39 changes: 0 additions & 39 deletions contracts/libraries/CallbackLib.sol

This file was deleted.

26 changes: 13 additions & 13 deletions contracts/libraries/Constants.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,38 @@ library Constants {
/// @notice Fixed point multiplier: 2**96
uint256 internal constant FP96 = 0x1000000000000000000000000;

/// @notice Minimum possible price tick in a Uniswap V3 pool
int24 internal constant MIN_V3POOL_TICK = -887272;
/// @notice Minimum possible price tick in a Uniswap V4 pool
int24 internal constant MIN_V4POOL_TICK = -887272;

/// @notice Maximum possible price tick in a Uniswap V3 pool
int24 internal constant MAX_V3POOL_TICK = 887272;
/// @notice Maximum possible price tick in a Uniswap V4 pool
int24 internal constant MAX_V4POOL_TICK = 887272;

/// @notice Minimum possible sqrtPriceX96 in a Uniswap V3 pool
uint160 internal constant MIN_V3POOL_SQRT_RATIO = 4295128739;
/// @notice Minimum possible sqrtPriceX96 in a Uniswap V4 pool
uint160 internal constant MIN_V4POOL_SQRT_RATIO = 4295128739;

/// @notice Maximum possible sqrtPriceX96 in a Uniswap V3 pool
uint160 internal constant MAX_V3POOL_SQRT_RATIO =
/// @notice Maximum possible sqrtPriceX96 in a Uniswap V4 pool
uint160 internal constant MAX_V4POOL_SQRT_RATIO =
1461446703485210103287273052203988822378723970342;

/// @notice Parameter that determines which oracle type to use for the "slow" oracle price on non-liquidation solvency checks.
/// @dev If false, an 8-slot internal median array is used to compute the "slow" oracle price.
/// @dev This oracle is updated with the last Uniswap observation during `mintOptions` if MEDIAN_PERIOD has elapsed past the last observation.
/// @dev If true, the "slow" oracle price is instead computed on-the-fly from 9 Uniswap observations (spaced 5 observations apart) irrespective of the frequency of `mintOptions` calls.
/// @dev This oracle is updated with the last oracle observation during `mintOptions` if MEDIAN_PERIOD has elapsed past the last observation.
/// @dev If true, the "slow" oracle price is instead computed on-the-fly from 9 oracle observations (spaced 5 observations apart) irrespective of the frequency of `mintOptions` calls.
bool internal constant SLOW_ORACLE_UNISWAP_MODE = false;

/// @notice The minimum amount of time, in seconds, permitted between internal TWAP updates.
uint256 internal constant MEDIAN_PERIOD = 60;

/// @notice Amount of Uniswap observations to include in the "fast" oracle price.
/// @notice Amount of oracle observations to include in the "fast" oracle price.
uint256 internal constant FAST_ORACLE_CARDINALITY = 3;

/// @dev Amount of observation indices to skip in between each observation for the "fast" oracle price.
/// @dev Note that the *minimum* total observation time is determined by the blocktime and may need to be adjusted by chain.
/// @dev Uniswap observations snapshot the last block's closing price at the first interaction with the pool in a block.
/// @dev oracle observations snapshot the last block's closing price at the first interaction with the pool in a block.
/// @dev In this case, if there is an interaction every block, the "fast" oracle can consider 3 consecutive block end prices (min=36 seconds on Ethereum).
uint256 internal constant FAST_ORACLE_PERIOD = 1;

/// @notice Amount of Uniswap observations to include in the "slow" oracle price (in Uniswap mode).
/// @notice Amount of oracle observations to include in the "slow" oracle price (in Uniswap mode).
uint256 internal constant SLOW_ORACLE_CARDINALITY = 9;

/// @notice Amount of observation indices to skip in between each observation for the "slow" oracle price.
Expand Down
4 changes: 2 additions & 2 deletions contracts/libraries/Errors.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ library Errors {
/// @param parameterType poolId=0, ratio=1, tokenType=2, risk_partner=3, strike=4, width=5, two identical strike/width/tokenType chunks=6
error InvalidTokenIdParameter(uint256 parameterType);

/// @notice A mint or swap callback was attempted from an address that did not match the canonical Uniswap V3 pool with the claimed features
error InvalidUniswapCallback();
/// @notice An unlock callback was attempted from an address other than the canonical Uniswap V4 pool manager
error UnauthorizedUniswapCallback();

/// @notice PanopticPool: None of the legs in a position are force-exercisable (they are all either short or ATM long)
error NoLegsExercisable();
Expand Down
2 changes: 1 addition & 1 deletion contracts/libraries/Math.sol
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ library Math {
function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160) {
unchecked {
uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
if (absTick > uint256(int256(Constants.MAX_V3POOL_TICK))) revert Errors.InvalidTick();
if (absTick > uint256(int256(Constants.MAX_V4POOL_TICK))) revert Errors.InvalidTick();

// sqrt(1.0001^(-absTick)) = ∏ sqrt(1.0001^(-bit_i))
// ex: absTick = 100 = binary 1100100, so sqrt(1.0001^-100) = sqrt(1.0001^-64) * sqrt(1.0001^-32) * sqrt(1.0001^-4)
Expand Down
Loading

0 comments on commit 58bc7f2

Please sign in to comment.