Platform: Code4rena
Start Date: 01/04/2024
End Date: 22/04/2024
Period: 21 days
Status: Completed
Pot Size: $120,000 USDC
Participants: 55
Reporter: liveactionllama
Judge: Picodes
Id: 354
League: ETH
0xLogos | 1/55 | $28,226.97 | 2 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
bin2chen | 2/55 | $11,316.21 | 3 | 1 | 0 | 2 | 1 | 0 | 0 | 0 |
rbserver | 3/55 | $8,159.28 | 2 | 0 | 0 | 1 | 1 | - | 0 | 0 |
KupiaSec | 4/55 | $8,159.28 | 2 | 0 | 0 | 1 | 1 | - | 0 | 0 |
Kalogerone | 5/55 | $8,126.32 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
0xdice91 | 6/55 | $8,126.32 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
pkqs90 | 7/55 | $4,146.86 | 2 | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
petro_1912 | 8/55 | $3,656.84 | 1 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
Aymen0909 | 9/55 | $3,564.62 | 3 | 1 | 0 | 1 | 0 | - | 0 | 0 |
0xStalin | 10/55 | $3,402.78 | 3 | 1 | 0 | 1 | 0 | - | 0 | 0 |
Auditor per page
The 4naly3er report can be found here.
Note for C4 wardens: Anything included in this Automated Findings / Publicly Known Issues
section is considered a publicly known issue and is ineligible for awards.
settleLongPremium
if the amount of premium owed is sufficiently small.10, 2_000, 1_000, -128, 5_000, 9_000, 20_000
Panoptic is a permissionless options trading protocol. It enables the trading of perpetual options on top of any Uniswap V3 pool
The Panoptic protocol is noncustodial, has no counterparty risk, offers instantaneous settlement, and is designed to remain fully collateralized at all times.
A gas-efficient alternative to Uniswap’s NonFungiblePositionManager that manages complex, multi-leg Uniswap positions encoded in ERC1155 tokenIds, performs swaps allowing users to mint positions with only one type of token, and, most crucially, supports the minting of both typical LP positions where liquidity is added to Uniswap and “long” positions where Uniswap liquidity is burnt. While the SFPM is enshrined as a core component of the protocol and we consider it to be the “engine” of Panoptic, it is also a public good that we hope savvy Uniswap V3 LPs will grow to find an essential tool and upgrade for managing their liquidity.
An ERC4626 vault where token liquidity from passive Panoptic Liquidity Providers (PLPs) and collateral for option positions are deposited. CollateralTrackers are also responsible for paying out commission fees and options premia, handling payments of intrinsic value for options and distributing P&L, calculating liquidation bonuses, and determining costs for forcefully exercising another user’s options. However, by far the most important functionality of the CollateralTracker is to calculate the collateral requirement for every account and position. Each time positions are minted or burned in Panoptic, the CollateralTracker updates the collateral balances and provides information on the collateral requirement, ensuring that the protocol remains solvent and we retain the ability to liquidate distressed positions when needed.
The Panoptic Pool exposes the core functionality of the protocol. If the SFPM is the “engine” of Panoptic, the Panoptic Pool is the “conductor”. All interactions with the protocol, be it minting or burning positions, liquidating or force exercising distressed accounts, or just checking position balances and accumulating premiums, originate in this contract. It is responsible for orchestrating the required calls to the SFPM to actually create option positions in Uniswap, tracking user balances of and accumulating the premia on those positions, and calling the CollateralTracker with the data it needs to settle position changes.
Each instance of the Panoptic protocol on a Uniswap pool contains:
There are five primary roles assumed by actors in this Panoptic Ecosystem:
Users who deposit tokens into one or both CollateralTracker vaults. The liquidity deposited by these users is borrowed by option sellers to create their positions - their liquidity is what enables undercollateralized positions. In return, they receive commission fees on both the notional and intrinsic values of option positions when they are minted. Note that options buyers and sellers are PLPs too - they must deposit collateral to open their positions. We consider users who deposit collateral but do not trade on Panoptic to be “passive” PLPs
These users deposit liquidity into the Uniswap pool through Panoptic, making it available for options buyers to remove. This role is similar to providing liquidity directly to Uniswap V3, but offers numerous benefits including advanced tools to manage risky, complex positions and a multiplier on the fees/premia generated by their liquidity when it is removed by option buyers. Sold option positions on Panoptic have similar payoffs to traditional options.
These users remove liquidity added by option sellers from the Uniswap Pool and move the tokens back into Panoptic. The premia they pay to sellers for the privilege is equivalent to the fees that would have been generated by the removed liquidity, plus a spread multiplier based on the portion of available liquidity in their Uniswap liquidity chunk that has been removed or utilized.
These users are responsible for liquidating distressed accounts that no longer meet the collateral requirements needed to maintain their positions. They provide the tokens necessary to close all positions in the distressed account and receive a bonus from the remaining collateral. Sometimes, they may also need to buy or sell options to allow lower liquidity positions to be exercised
These are usually options sellers. They provide the required tokens and forcefully exercise long positions (from option buyers) in out-of-range strikes that are no longer generating premia, so the liquidity from those positions is added back to Uniswap and the sellers can exercise their positions (which involves burning that liquidity). They pay a fee to the exercised user for the inconvenience.
All protocol users first onboard by depositing tokens into one or both CollateralTracker vaults and being issued shares (becoming PLPs in the process). Panoptic’s CollateralTracker supports the full ERC4626 interface, making deposits and withdrawals a simple and standardized process. Passive PLPs stop here.
Once they have deposited, there are many options for the other actors in the protocol. Buyers and sellers can call :
mintOptions
- create an option position with up to four distinct legs with a specially encoded - positionID/tokenID, each of which is its own short (sold/added) or long (bought/removed) liquidity chunkburnOptions
- burn or exercise a position created through mintOptions
settleLongPremium
- Force a solvent option buyer to pay any premium owed to sellers. Options sellers will want to call this if a large portion of the total premium owed in their chunk is pending/has not been settled.pokeMedian
- Takes a new internal median observation and inserts it into the internal median ring buffer if enough time has passed since the last observation. Otherwise, the buffer is poked during mintOptions
/burnOptions
Meanwhile, force exercisers and liquidators can perform their respective roles with the forceExercise
and liquidateAccount
functions.
contracts/ ├── CollateralTracker — "ERC4626 vault where token liquidity from Panoptic Liquidity Providers (PLPs) and collateral for option positions are deposited and collateral requirements are computed" ├── PanopticFactory — "Handles deployment of new Panoptic instances on top of Uniswap pools, initial liquidity deployments, and NFT rewards for deployers" ├── PanopticPool — "Coordinates all options trading activity - minting, burning, force exercises, liquidations" ├── SemiFungiblePositionManager — "The 'engine' of Panoptic - manages all Uniswap V3 positions in the protocol as well as being a more advanced, gas-efficient alternative to NFPM for Uniswap LPs" ├── tokens │ ├── ERC1155Minimal — "A minimalist implementation of the ERC1155 token standard without metadata" │ ├── ERC20Minimal — "A minimalist implementation of the ERC20 token standard without metadata" │ └── interfaces ├── IDonorNFT — "An interface the PanopticFactory can use to issue reward NFTs" │ └── IERC20Partial — "An incomplete ERC20 interface containing functions used in Panoptic with some return values omitted to support noncompliant tokens such as USDT" ├── types │ ├── LeftRight — "Implementation for a set of custom data types that can hold two 128-bit numbers" │ ├── LiquidityChunk — "Implementation for a custom data type that can represent a liquidity chunk of a given size in Uniswap - containing a tickLower, tickUpper, and liquidity" │ └── TokenId — "Implementation for the custom data type used in the SFPM and Panoptic to encode position data in 256-bit ERC1155 tokenIds - holds a pool identifier and up to four full position legs" ├── libraries │ ├── CallbackLib — "Library for verifying and decoding Uniswap callbacks" │ ├── Constants — "Library of Constants used in Panoptic" │ ├── Errors — "Contains all custom errors used in Panoptic's core contracts" │ ├── FeesCalc — "Utility to calculate up-to-date swap fees for liquidity chunks" │ ├── InteractionHelper — "Helpers to perform bytecode-size-heavy interactions with external contracts like batch approvals and metadata queries" │ ├── Math — "Library of generic math functions like abs(), mulDiv, etc" │ ├── PanopticMath — "Library containing advanced Panoptic/Uniswap-specific functionality such as our TWAP, price conversions, and position sizing math" │ └── SafeTransferLib — "Safe ERC20 transfer library that gracefully handles missing return values" └── multicall └── Multicall — "Adds a function to inheriting contracts that allows for multiple calls to be executed in a single transaction"
Panoptic has been presented at conferences and was conceived with the first Panoptic's Genesis blog post in mid-summer 2021:
File | Logic Contracts | Interfaces | SLOC |
---|---|---|---|
contracts/CollateralTracker.sol | 1 | **** | 792 |
contracts/PanopticFactory.sol | 1 | **** | 249 |
contracts/PanopticPool.sol | 1 | **** | 1162 |
contracts/SemiFungiblePositionManager.sol | 1 | **** | 724 |
contracts/libraries/CallbackLib.sol | 1 | **** | 22 |
contracts/libraries/Constants.sol | 1 | **** | 9 |
contracts/libraries/Errors.sol | 1 | **** | 35 |
contracts/libraries/FeesCalc.sol | 1 | **** | 86 |
contracts/libraries/InteractionHelper.sol | 1 | **** | 72 |
contracts/libraries/Math.sol | 1 | **** | 417 |
contracts/libraries/PanopticMath.sol | 1 | **** | 573 |
contracts/libraries/SafeTransferLib.sol | 1 | **** | 33 |
contracts/multicall/Multicall.sol | 1 | **** | 18 |
contracts/tokens/ERC1155Minimal.sol | 1 | **** | 115 |
contracts/tokens/ERC20Minimal.sol | 1 | **** | 52 |
contracts/tokens/interfaces/IDonorNFT.sol | **** | 1 | 4 |
contracts/tokens/interfaces/IERC20Partial.sol | **** | 1 | 6 |
contracts/types/LeftRight.sol | 1 | **** | 156 |
contracts/types/LiquidityChunk.sol | 1 | **** | 91 |
contracts/types/TokenId.sol | 1 | **** | 305 |
Totals | 18 | 1 | 4921 |
Contract |
---|
deploy/DeployProtocol.s.sol |
periphery/PanopticHelper.sol |
scripts/DeployTestPool.s.sol |
scripts/tokens/ERC20S.sol |
test/foundry/core/CollateralTracker.t.sol |
test/foundry/core/Misc.t.sol |
test/foundry/core/PanopticFactory.t.sol |
test/foundry/core/PanopticPool.t.sol |
test/foundry/core/SemiFungiblePositionManager.t.sol |
test/foundry/libraries/CallbackLib.t.sol |
test/foundry/libraries/FeesCalc.t.sol |
test/foundry/libraries/Math.t.sol |
test/foundry/libraries/PanopticMath.t.sol |
test/foundry/libraries/PositionAmountsTest.sol |
test/foundry/libraries/SafeTransferLib.t.sol |
test/foundry/libraries/harnesses/CallbackLibHarness.sol |
test/foundry/libraries/harnesses/FeesCalcHarness.sol |
test/foundry/libraries/harnesses/MathHarness.sol |
test/foundry/libraries/harnesses/PanopticMathHarness.sol |
test/foundry/periphery/PanopticHelper.t.sol |
test/foundry/testUtils/PositionUtils.sol |
test/foundry/testUtils/PriceMocks.sol |
test/foundry/testUtils/ReentrancyMocks.sol |
test/foundry/tokens/ERC1155Minimal.t.sol |
test/foundry/types/LeftRight.t.sol |
test/foundry/types/LiquidityChunk.t.sol |
test/foundry/types/TokenId.t.sol |
test/foundry/types/harnesses/LeftRightHarness.sol |
test/foundry/types/harnesses/LiquidityChunkHarness.sol |
test/foundry/types/harnesses/TokenIdHarness.sol |
Question | Answer |
---|---|
Test coverage | - |
ERC20 used by the protocol | any |
ERC721 used by the protocol | any |
ERC777 used by the protocol | no |
ERC1155 used by the protocol | SFPM and factory ERC1155 tokens |
Chains the protocol will be deployed on | Ethereum, Arbitrum, Avax, Base, BSC, Optimism ,Polygon |
Question | Answer |
---|---|
Enabling/disabling fees (e.g. Blur disables/enables fees) | No |
Pausability (e.g. Uniswap pool gets paused) | No |
Upgradeability (e.g. Uniswap gets upgraded) | No |
N/A
SFPM:
The factory contract and usage of libraries by external integrators is relatively unimportant -- wardens should focus their efforts on the security of the SFPM (previously audited by C4, code has changed since that audit however), PanopticPool, and CollateralTracker
N/A There is a factory owner but they do not have any permissions over the contracts in scope.
⚠️Note: You will need to provide your own Ethereum Mainnet eth_rpc_url (Works best with a local archives node) in the Foundry.toml.
git clone --recurse-submodules https://github.com/code-423n4/2024-04-panoptic.git cd 2024-04-panoptic export FOUNDRY_PROFILE=ci_test # (tests WILL fail without this because of a Foundry bug) forge build forge test
To run gas benchmarks:
forge test --gas-report
Employees of Panoptic and employees' family members are ineligible to participate in this audit.