rdin777/Permanent-loss-of-user-funds-Panoptic

GitHub: rdin777/Permanent-loss-of-user-funds-Panoptic

针对 Panoptic 永续期权协议的安全研究和概念验证,展示了可导致用户资金永久损失的舍入误差和逻辑缺陷等关键漏洞。

Stars: 0 | Forks: 0

# Panoptic 安全分析:用户资金永久损失 本仓库包含对 **Panoptic** 协议中发现的关键漏洞的专业安全研究和概念验证(PoC)。 ## 🛡️ 执行摘要 研究重点在于可能导致用户资金永久损失或在 DeFi 生态系统中产生"幽灵债务"的复杂逻辑缺陷和舍入误差。 ### 主要发现: - **严重:** 由于[简要描述攻击向量,例如金库会计错误]导致用户资金永久损失。 - **高:** 债务计算中的舍入误差导致资不抵债头寸。 - **中/高:** 流动性供应周期中的逻辑缺陷。 ## 🚀 仓库结构 - `/contracts`:用于测试的简化版 Panoptic 合约。 - `/audits`:详细报告(报告 #270、#271、#272)。 - `/script`:部署和实用脚本。 - `/test` 或 `/script/PoC`:基于 Foundry 的概念验证,展示漏洞利用。 ## 🛠️ 如何运行 PoC 本项目使用 **Foundry**。要运行安全测试: 1. 克隆仓库: git clone [https://github.com/rdin777/Permanent-loss-of-user-funds-Panoptic.git](https://github.com/rdin777/Permanent-loss-of-user-funds-Panoptic.git) 安装依赖: Bash forge install 运行概念验证测试: Bash forge test --match-path script/YourPoCFile.s.sol -vvvv 📝 技术文章 要深入了解这些漏洞背后的逻辑,请阅读我在 Medium 上的研究: [链接到您的 Medium 文章 1] [链接到您的 Medium 文章 2] 🤝 联系与服务 我是一名专注于 DeFi 的安全研究员和智能合约审计员。可提供远程审计和漏洞赏金合作。 用户名:RimDinov 平台活动:Cantina、Code4rena、Bugcrowd。 # Panoptic 审计详情 - 总奖池:$56,000 USDC - 高危奖励:最高 $50,400 USDC - 如果未发现有效的高危或中危漏洞,高危奖池为 $0 - QA 奖励:$2,100 USDC - 裁判奖励:$3,000 USDC - 侦察奖励:$500 USDC - [阅读我们的指南了解更多详情](https://docs.code4rena.com/competitions) - 开始时间:2025 年 12 月 19 日 20:00 UTC - 结束时间:2026 年 1 月 7 日 20:00 UTC ### ❗ 审计员重要说明 1. 所有高危/中危提交都需要可运行的代码化 PoC。 - 审计员应使用项目的测试套件来展示他们发现的漏洞。(参见 [提交 PoC]( 余额)掩盖了真实的赤字程度。由于 `_getMargin(...)` 用于 `isAccountSolvent(...)`,将利息(要求)设置为余额值会隐藏实际资金短缺。 **示例:** Alice 欠 100 利息,余额为 20。将利息设置为 20,余额设置为 0,显示赤字为 20 而不是实际赤字 80。 3. **破坏的奖金计算** `_getMargin(...)` 中的 if 语句逻辑通过掩盖真实赤字来破坏奖金计算。奖金交叉和阈值交叉的值是基于掩盖的赤字而不是实际短缺计算的。 4. **委托/撤销中的孤儿份额** `delegate(...)` 到 `revoke(...)` 的交互创建了无人拥有的份额,破坏了供应不变量。在强制行使场景中: 1. 用户从余额 X 开始。 2. **委托:** 用户余额膨胀至 inflation + X,然后由于利息支付不足减少 X。余额 = inflation。 3. **结算燃烧 / 应计利息:** Y 份额被燃烧以支付利息(足够的虚拟余额)。总供应量减少 Y。用户余额 = inflation - Y。 4. **撤销:** 由于 inflation > 余额,用户余额被清零,总供应量通过添加 Y 恢复(inflation - (inflation - Y))。 5. **结果:** 总供应量净变化为 0(-Y 燃烧 +Y 恢复)。原始 X 份额保留在总供应量中,但无人拥有。 # 概述 Panoptic 是一个无需许可的期权交易协议。它支持在任何 [Uniswap V3](https://uniswap.org/) 和 [Uniswap V4](https://uniswap.org/) 池上交易永续期权。 Panoptic 协议是非托管的,没有交易对手风险,提供即时结算,并设计为始终保持完全抵押。 ## 核心合约 ### SemiFungiblePositionManager 一种 gas 高效的 Uniswap NonFungiblePositionManager 替代方案,管理编码在 ERC1155 tokenId 中的复杂多腿 Uniswap 头寸,执行允许用户仅用一种代币铸造头寸的兑换,并且最重要的是,支持铸造典型的 LP 头寸(流动性添加到 Uniswap)和"多头"头寸( Uniswap 流动性被销毁)。虽然 SFPM 被确立为协议的核心组件,我们认为它是 Panoptic 的"引擎",但它也是一个公共产品,我们希望精明的 Uniswap V3 和 V4 LP 会发现它是管理流动性的必备工具和升级。 ### RiskEngine Panoptic 协议的中心风险评估和偿付能力计算器。该合约是所有风险相关计算的数学框架,不持有资金或用户余额状态。RiskEngine 负责: - **抵押品要求**:根据头寸构成和池利用率,计算复杂期权策略(包括价差、跨式、铁鹰式和合成头寸)所需的抵押品 - **偿付能力验证**:通过 `isAccountSolvent` 函数确定账户是否满足维持保证金要求,考虑 token0 和 token1 之间的交叉抵押 - **清算参数**:计算支付给清算人的清算奖金和协议损失(通过 `getLiquidationBonus`),考虑账户的代币余额和头寸要求 - **强制行使成本**:通过 `exerciseCost` 计算强制行使价外多头头寸的成本,使用基于与执行价距离的指数衰减函数 - **自适应利率模型**:使用 PID 控制器方法根据池利用率计算动态借款利率,利率在最小和最大阈值之间调整以瞄准最佳利用率 - **预言机管理**:管理具有波动性保护、指数移动平均线(EMA)和中值过滤器的内部定价预言机,以防止价格操纵 - **风险参数**:存储和提供协议范围的风险参数,包括卖方/买方抵押品比率、佣金费用、强制行使成本和目标池利用率 - **守护者控制**:授权守护者地址覆盖安全模式设置并在紧急情况下锁定/解锁池 RiskEngine 使用复杂的算法,包括基于利用率的乘数(由 VEGOID 参数调节)、交叉缓冲比率用于交叉抵押,以及随池利用率动态调整的抵押品要求,以确保协议始终保持偿付能力。 ### CollateralTracker 一个 ERC4626 金库,被动 Panoptic 流动性提供者(PLP)的代币流动性和期权头寸的抵押品存入其中。CollateralTracker 负责: - **资产管理**:跟踪存入的资产、AMM 中部署的资产,以及超过再质押阈值的多头头寸的信用份额 - **利息应计**:实施复利模型,借款人(期权卖方)支付借款流动性的利息,利率由 RiskEngine 根据池利用率确定 - **佣金处理**:收集和分配期权铸造和燃烧的佣金费用,在协议、建设者(如果存在建设者代码)和 PLP 之间分配费用 - **溢价结算**:促进买方和卖方之间的期权溢价支付和接收,包括已结算和未结算溢价的计算 - **余额操作**:通过存款、提取、铸造、赎回以及为活跃头寸委托/撤销虚拟份额来管理用户份额余额 - **清算结算**:通过向清算人铸造份额来处理清算奖金的结算,并在头寸被清算时管理协议损失 - **抵押品退款**:在头寸关闭、强制行使或调整时处理用户之间的退款 每个 CollateralTracker 都维护自己的市场状态,包括用于复利计算的全局借款索引,跟踪每个用户的利息状态(净借款和最后交互快照),并与 RiskEngine 协调根据实时池利用率确定适当的利率。 ### PanopticPool Panoptic Pool 暴露了协议的核心功能。如果 SFPM 是 Panoptic 的"引擎",那么 Panoptic Pool 就是"指挥家"。与协议的所有交互,无论是铸造或燃烧头寸、清算或强制行使困境账户,还是仅检查头寸余额和累积溢价,都源自此合约。它负责: - **头寸协调**:协调调用 SFPM 以在 Uniswap 中创建、修改和关闭期权头寸 - **溢价跟踪**:跟踪用户余额并随时间累积期权头寸的溢价 - **偿付能力检查**:咨询 RiskEngine 以在允许头寸变更或提取之前验证账户偿付能力 - **结算协调**:使用必要的数据调用 CollateralTracker 以结算头寸变更,包括佣金支付、利息应计和余额更新 - **风险验证**:确保所有操作符合 RiskEngine 计算的风险参数和抵押品要求 ## 架构与角色 Panoptic 协议在每个 Uniswap 池上的实例包含: - 一个 PanopticPool 协调协议中的所有交互 - 一个 RiskEngine 计算抵押品要求、验证偿付能力并管理风险参数 - 两个 CollateralTracker,每个用于 Uniswap 池中的组成代币 token0/token1 - 一个规范的 SFPM - SFPM 管理每个 Panoptic Pool 的流动性 Panoptic 生态系统中假设有五个主要角色: ### Panoptic 流动性提供者(PLP) 将代币存入一个或两个 CollateralTracker 金库的用户。这些用户存入的流动性被期权卖方借用以创建他们的头寸——他们的流动性使得抵押不足的头寸成为可能。作为回报,他们在期权头寸铸造时获得佣金费用(基于名义价值和内在价值),以及 来自借款人的利息支付。请注意,期权买方和卖方也是 PLP——他们必须存入抵押品才能开仓。我们认为存入抵押品但不_在 Panoptic 上交易的用户是"被动"PLP。 ### 期权卖方 这些用户通过 Panoptic 将流动性存入 Uniswap 池,供期权买方移除。此角色类似于直接向wap V3 提供流动性,但提供诸多好处,包括管理风险复杂头寸的先进工具,以及当流动性被期权买方移除时其流动性产生费用/溢价的乘数。期权 卖方向 PLP 支付借款流动性的利息,利率由 RiskEngine 根据池利用率动态调整。Panoptic 上卖出的期权头寸具有与传统期权类似的收益。 ### 期权买方 这些用户从 Uniswap 池中移除期权卖方添加的流动性,并将代币转回 Panoptic。他们向卖方支付的溢价特权等同于被移除流动性本应产生的费用,加上基于其 Uniswap 流动性区块中被移除或利用的部分的价差乘数。 ### 清算人 这些用户负责清算不再满足 RiskEngine 计算的抵押品要求的困境账户。他们提供必要的代币来关闭困境账户中的所有头寸,并从剩余抵押品中获得奖金,由 RiskEngine 的清算奖金公式计算。有时,他们可能还需要买卖期权以允许较低流动性的头寸被行使。 ### 强制行使者 这些通常是期权卖方。他们提供必要的代币并强制行使(来自期权买方)的不再产生溢价的价外执行价的多头头寸,以便这些头寸的流动性被添加回 Uniswap,卖方可以行使他们的头寸(涉及燃烧该流动性)。他们向被行使的用户支付费用作为补偿, 费用金额由 RiskEngine 的 `exerciseCost` 函数确定。 ## 流程 所有协议用户首先通过将代币存入一个或两个 CollateralTracker 金库并获得份额(从而成为 PLP)来加入。Panoptic 的 CollateralTracker 支持完整的 ERC4626 接口,使存款和提款成为简单而标准化的流程。被动 PLP 到此为止。 一旦存入,所有与协议的交互都通过 PanopticPool 的统一入口点发起: - `dispatch()` - 用户代表自己执行操作的主要入口点 - `dispatchFrom()` - 允许批准的操作员代表另一用户执行操作 这些入口点接受编码的操作数据,指定要执行的操作,包括: - 铸造最多四个不同腿的期权头寸,每个编码为 positionID/tokenID,作为空头(卖出/添加)或多头(买入/移除)流动性区块。RiskEngine 验证账户在铸造后将保持偿付能力。 - 燃烧或行使头寸。RiskEngine 确保在燃烧过程中满足抵押品要求。 - 结算多头溢价以迫使偿付能力的期权买方支付欠卖方的任何溢价 - 戳动中值预言机以向 RiskEngine 的内部中值环形缓冲区插入新观察 - 强制行使其他用户持有的价外多头头寸,成本由 RiskEngine 计算 - 清算不再满足抵押品要求的困境账户,奖金由 RiskEngine 确定 这种统一的调度架构为所有协议交互提供了一致的接口,同时允许 PanopticPool 根据请求的操作协调调用 SFPM、CollateralTracker 和 RiskEngine。 # 范围 _参见 [scope.txt](https://github.com/code-423n4/2025-12-panoptic/blob/main/scope.txt)_ ### 范围内的文件 **注意:** 下表中的 nSLoC 计数是自动生成的,可能因"重要"代码行的定义不同而有所不同。因此,它们应被视为每个合约涉及行的指示性而非绝对表示。 | 文件 | nSLOC | | ---- | ----- | | [/contracts/PanopticPool.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/PanopticPool.sol) | 1183 | | [/contracts/RiskEngine.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/RiskEngine.sol) | 1294 | | [/contracts/types/OraclePack.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/types/OraclePack.sol) | 291 | | [/contracts/types/MarketState.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/types/MarketState.sol) | 65 | | [/contracts/types/PoolData.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/types/PoolData.sol) | 42 | | [/contracts/types/RiskParameters.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/types/RiskParameters.sol) | 72 | | [/contracts/SemiFungiblePositionManager.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol) | 673 | | [/contracts/SemiFungiblePositionManagerV4.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/SemiFungiblePositionManagerV4.sol) | 631 | | [/contracts/CollateralTracker.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/CollateralTracker.sol) | 863 | | [/contracts/libraries/PanopticMath.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/libraries/PanopticMath.sol) | 369 | | [/contracts/libraries/Math.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/libraries/Math.sol) | 641 | | [/contracts/types/TokenId.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/types/TokenId.sol) | 232 | | **总计** | **6356** | 以下合约的差异应进行审查: - [SemiFungiblePositionManager.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/SemiFungiblePositionManager.sol): [SemiFungiblePositionManager.sol.diff](https://github.com/code-423n4/2025-12-panoptic/blob/main/diff/SemiFungiblePositionManager.sol.diff) - [SemiFungiblePositionManagerV4.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/SemiFungiblePositionManagerV4.sol): [SemiFungiblePositionManagerV4.sol.diff](https://github.com/code-423n4/2025-12-panoptic/blob/main/diff/SemiFungiblePositionManagerV4.sol.diff) - [CollateralTracker.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/CollateralTracker.sol): [CollateralTracker.sol.diff](https://github.com/code-423n4/2025-12-panoptic/blob/main/diff/CollateralTracker.sol.diff) - [libraries/PanopticMath.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/libraries/PanopticMath.sol): [PanopticMath.sol.diff](https://github.com/code-423n4/2025-12-panoptic/blob/main/diff/PanopticMath.sol.diff) - [libraries/Math.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/libraries/Math.sol): [Math.sol.diff](https://github.com/code-423n4/2025-12-panoptic/blob/main/diff/Math.sol.diff) - [types/TokenId.sol](https://github.com/code-423n4/2025-12-panoptic/blob/main/contracts/types/TokenId.sol): [TokenId.sol.diff](https://github.com/code-423n4/2025-12-panoptic/blob/main/diff/TokenId.sol.diff) ### 范围外的文件 _参见 [out_of_scope.txt](https://github.com/code-423n4/2025-12-panoptic/blob/main/out_of_scope.txt)_ | 文件 | | ------------ | | ./contracts/PanopticFactory.sol | | ./contracts/PanopticFactoryV4.sol | | ./contracts/base/FactoryNFT.sol | | ./contracts/base/MetadataStore.sol | | ./contracts/base/Multicall.sol | | ./contracts/interfaces/IRiskEngine.sol | | ./contracts/interfaces/ISemiFungiblePositionManager.sol | | ./contracts/libraries/CallbackLib.sol | | ./contracts/libraries/Constants.sol | | ./contracts/libraries/EfficientHash.sol | | ./contracts/libraries/Errors.sol | | ./contracts/libraries/FeesCalc.sol | | ./contracts/libraries/InteractionHelper.sol | | ./contracts/libraries/SafeTransferLib.sol | | ./contracts/libraries/V4StateReader.sol | | ./contracts/tokens/ERC1155Minimal.sol | | ./contracts/tokens/ERC20Minimal.sol | | ./contracts/tokens/interfaces/IERC20Partial.sol | | ./contracts/types/LeftRight.sol | | ./contracts/types/LiquidityChunk.sol | | ./contracts/types/Pointer.sol | | ./contracts/types/PositionBalance.sol | | ./script/DeployProtocol.s.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/RiskEngine/AssertExt.sol | | ./test/foundry/core/RiskEngine/RiskEngine.Gaps.t.sol | | ./test/foundry/core/RiskEngine/RiskEngine.Properties.t.sol | | ./test/foundry/core/RiskEngine/RiskEngine.Scenarios.t.sol | | ./test/foundry/core/RiskEngine/RiskEngineHarness.sol | | ./test/foundry/core/RiskEngine/RiskEngineIRM.t.sol | | ./test/foundry/core/RiskEngine/RiskEngineInvariants.t.sol | | ./test/foundry/core/RiskEngine/RiskEnginePropertiesPlus.t.sol | | ./test/foundry/core/RiskEngine/RiskEngineSafeModeAndOracle.t.sol | | ./test/foundry/core/RiskEngine/helpers/PositionFactory.sol | | ./test/foundry/core/RiskEngine/mocks/MockCollateralTracker.sol | | ./test/foundry/core/SemiFungiblePositionManager.t.sol | | ./test/foundry/coreV3/CollateralTracker.t.sol | | ./test/foundry/coreV3/Misc.t.sol | | ./test/foundry/coreV3/PanopticFactory.t.sol | | ./test/foundry/coreV3/PanopticPool.t.sol | | ./test/foundry/coreV3/RiskEngine/AssertExt.sol | | ./test/foundry/coreV3/RiskEngine/RiskEngine.Gaps.t.sol | | ./test/foundry/coreV3/RiskEngine/RiskEngine.Properties.t.sol | | ./test/foundry/coreV3/RiskEngine/RiskEngine.Scenarios.t.sol | | ./test/foundry/coreV3/RiskEngine/RiskEngineHarness.sol | | ./test/foundry/coreV3/RiskEngine/RiskEngineIRM.t.sol | | ./test/foundry/coreV3/RiskEngine/RiskEngineInvariants.t.sol | | .//foundry/coreV3/RiskEngine/RiskEnginePropertiesPlus.t.sol | | ./test/foundry/coreV3/RiskEngine/RiskEngineSafeModeAndOracle.t.sol | | ./test/foundry/coreV3/RiskEngine/helpers/PositionFactory.sol | | ./test/foundry/coreV3/RiskEngine/mocks/MockCollateralTracker.sol | | ./test/foundry/coreV3/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/testUtils/ERC20S.sol | | ./test/foundry/testUtils/PositionUtils.sol | | ./test/foundry/testUtils/PriceMocks.sol | | ./test/foundry/testUtils/ReentrancyMocks.sol | | ./test/foundry/testUtils/V4RouterSimple.sol | | ./test/foundry/test_periphery/PanopticHelper.sol | | ./test/foundry/tokens/ERC1155Minimal.t.sol | | ./test/foundry/types/LeftRight.t.sol | | ./test/foundry/types/LiquidityChunk.t.sol | | ./test/foundry/types/PositionBalance.t.sol | | ./test/foundry/types/TokenId.t.sol | | ./test/foundry/types/harnesses/LeftRightHarness.sol | | ./test/foundry/types/harnesses/LiquidityChunkHarness.sol | | ./test/foundry/types/harnesses/PositionBalanceHarness.sol | | ./test/foundry/types/harnesses/TokenIdHarness.sol | | 总计:80 | # 额外背景 ## 关注领域(应重点关注的安全方向) 工厂合约和外部集成商对库的使用相对不重要——审计员应将精力集中在 SFPM、PanopticPool、RiskEngine 和 CollateralTracker 的安全性上 # 主要不变量 ## SFPM(SemiFungiblePositionManager) - 在任何给定操作中从 Uniswap 收取的费用不应超过执行该操作的用户拥有的流动性所赚取的费用。 - 支付给给定用户的费用不应超过该用户拥有的流动性所赚取的费用。 ## CollateralTracker ### 资产会计 - `totalAssets()` 必须始终等于 `s_depositedAssets + s_assetsInAMM + unrealizedGlobalInterest` - `totalSupply()` 必须始终等于 `_internalSupply + s_creditedShares` - `s_depositedAssets` 永远不应下溢低于 1(初始虚拟资产) - 份额价格(`totalAssets() / totalSupply()`)必须随时间非递减(协议偏好舍入和发生协议损失的清算除外) ### 利息应计 - 全局 `borrowIndex` 必须随时间单调递增,从 1e18(WAD)开始 - 对于任何 `netBorrows > 0` 的用户,他们的 `userBorrowIndex` 必须 ≤ 当前全局 `borrowIndex` - 用户欠款的利息必须等于:`netBorrows * (currentBorrowIndex - userBorrowIndex) / userBorrowIndex` - `unrealizedGlobalInterest` 永远不能超过所有用户欠款利息的总和 - 在 `_accrueInterest()` 之后,用户的 `userBorrowIndex` 必须等于当前全局 `borrowIndex`(除非资不抵债且无力支付) ### 信用份额 - `s_creditedShares` 代表多头头寸的份额,只能在头寸创建时增加,在关闭时减少 - 当多头头寸关闭时,如果 `creditDelta > s_creditedShares`,差额必须由期权所有者作为舍入 haircut 支付 - Uniswap 头寸管理中的舍入 haircut 每个头寸不应超过几 wei ### 存款和取款 - 拥有未平仓头寸(`numberOfLegs > 0`)的用户不能通过 `transfer()` 或 `transferFrom()` 转移份额 - 拥有未平仓头寸的用户只能提供 `positionIdList` 并在取款后保持偿付能力才能取款 - 存款不得超过 `type(uint104).max`(2^104 - 1) - 取款必须在 `s_depositedAssets` 中留下至少 1 个资产(不能完全耗尽池) ## RiskEngine ### 偿付能力检查 - 账户是偿付的当且仅当:`balance0 + convert(scaledSurplus1) >= maintReq0` 且 `balance1 + convert(scaledSurplus0) >= maintReq1`(转换方向取决于价格) - 维持要求包括:头寸抵押品要求 + 应计利息欠款 + 欠多头溢价 - 欠空头溢价 - 信用额度 - 交叉抵押使用基于池利用率的 `crossBufferRatio`(更高的利用率 = 更保守的缓冲) - 必须在预言机 tick 而非当前 tick 检查偿付能力,以防止操纵 ### 抵押品要求 - 抵押品要求必须随池利用率增加(更高的利用率 = 更高的要求) - 用于保证金计算的"全局利用率"是用户铸造头寸时所有头寸的最大利用率 ### 清算奖金 - 清算奖金 = `min(collateralBalance / 2, required - collateralBalance)` - 奖金使用两种代币转换为相同 denomination 交叉计算 - 如果被清算人在一种代币中余额不足,可以使用另一种代币的多余余额通过代币转换来减轻协议损失 - 如果在清算期间向卖方支付了溢价,如果它会导致协议损失超过剩余抵押品,则必须被追回(haircut) ### 溢价 haircut - 如果 `collateralRemaining < 0`(存在协议损失),清算期间向卖方支付的溢价必须按比例追回 - haircut 基于协议损失与支付溢价的比例按每个腿应用 - haircut 后,调整后的奖金不得导致协议损失超过初始抵押品余额 ### 强制行使成本 - 基础强制行使成本 = 价内头寸名义价值的 1.024%(`FORCE_EXERCISE_COST = 102_400 / 10_000_000`) - 价外头寸成本 = 1 bps(`ONE_BPS = 1000 / 10_000_000`) - 成本必须考虑当前价格和预言机价格之间所有多头腿的代币 delta - 只有多头腿(而非空头腿)贡献强制行使成本 ### 利率模型 - 利率必须有界限:`MIN_RATE_AT_TARGET ≤ rate ≤ MAX_RATE_AT_TARGET` - 利率根据利用率误差持续调整:`targetUtilization - currentUtilization` - 自适应利率(`rateAtTarget`)以 `ADJUSTMENT_SPEED * error` 每秒的速度复利 - 初始 `rateAtTarget` = 4% 年利率(`INITIAL_RATE_AT_TARGET`) - 目标利用率 = 66.67%(`TARGET_UTILIZATION = 2/3 in WAD`) ### 预言机安全 - 快慢预言机 tick 之间允许的最大 delta = 953 ticks(约 10% 价格变动) - 清算期间,当前 tick 必须在 TWAP 的 513 ticks 内(约 5% 偏差) - 如果预言机 delta 超过阈值,协议进入安全模式,使用更保守的价格估计 - 中值 tick 缓冲区只能在上次观察经过足够时间后才能更新 ## PanopticPool ### 入口点 - 所有用户操作必须源自 `dispatch()` 或 `dispatchFrom()` 入口点 - `dispatchFrom()` 需要调用者获得账户所有者的操作员批准 - 每次 dispatch 调用可以执行多个操作(铸造、燃烧、铸造、铸造、燃烧等)并允许临时资不抵债状态 ### 头寸管理 - 用户最多可以铸造总共 `MAX_OPEN_LEGS = 33` 个头寸腿 - 佣金在协议和建设者(如果存在建设者代码)之间按 `PROTOCOL_SPLIT` 和 `BUILDER_SPLIT` 分配 - 期权卖在头寸燃烧时必须归还精确数量的 `shortAmounts` 代币 - 期权买方在头寸燃烧时必须归还被移除的精确流动性数量 ### 偿付能力要求 - 用户在任何铸造、燃烧或取款操作后必须保持偿付能力(按 RiskEngine) - 偿付能力在快预言机 tick 检查,如果它们分歧超过阈值则在多个预言机 tick 检查 ### 溢价结算 - 期权卖方不应获得未结算溢价(尚未从 Uniswap 收取或由多头持有者支付的溢价) - 卖方已结算溢价的份额必须与其在该区块流动性中的份额成比例 - 溢价分配比例:`min(settled / owed, 1)` 适用于区块中的所有卖方 - 可以对偿付能力的买方结算多头溢价以强制付款 ### 清算 - 只有当 `RiskEngine.isAccountSolvent()` 在预言机 tick 返回 false 时才能进行清算 - 清算人必须关闭被清算人持有的所有头寸 - 支付给清算人的清算奖金不得超过被清算人清算前的抵押品余额 - 如果清算导致协议损失,则向清算人铸造份额以弥补差额 - 即使被清算人有剩余代币余额,如果该余额在转换时不足,协议损失也可能发生,这是可接受的 ### 溢价 haircut 不变量 - 如果在清算期间向卖方支付了溢价_并且_清算后存在协议损失,则必须对溢价进行 haircut(追回)以减少协议损失 - haircut 后,协议损失必须最小化,但如果溢价追回不足,仍可能为正 ### 头寸大小限制 - 单独头寸大小受 Uniswap 池中可用流动性限制 - 最大价差比率(移除/净流动性)上限为 `MAX_SPREAD = 90_000 / 100_000 = 90%` - 头寸大小不得在任何代币数量或流动性计算中导致整数溢出 ## 跨合约不变量 ### 预言机一致性 - 用于偿付能力检查的预言机 tick 必须来自 PanopticPool 的预言机管理 - 单笔交易中的所有操作必须使用一致的预言机 tick - 预言机必须通过 EMA 和中值过滤器考虑波动性以防止操纵 ## 协议中所有受信任的角色 | 角色 | 描述 | | --------------------------------------- | ---------------------------- | | 守护者 | 只能通过 **RiskEngine.sol** 智能合约与协议交互:
- 锁定/解锁池(将 safeMode 设置为 3)
- 收取 RiskEngine 中未结协议费用
- BuilderFactory 的所有者,可以部署新的 builderWallets | ## 运行测试 ### 构建 传统的 `forge` 构建命令将安装相关依赖并构建项目: ``` #### forge build ### 测试 The following command can be issued to execute all tests within the repository: ```sh #### forge test Wardens are expected to populate the [foundry.toml](https://github.com/code-423n4/2025-12-panoptic/blob/main/foundry.toml) file with their own `eth_rpc_url` and `sepolia` infura endpoints. ### Submission PoCs Wardens are instructed to utilize the test suite of the project to illustrate the vulnerabilities they identify. If a custom configuration is desired, wardens are advised to create their own PoC file that should be executable within the `test` subfolder of this contest. All PoCs must adhere to the following guidelines: - The PoC should execute successfully - The PoC must not mock any contract-initiated calls - The PoC must not utilize any mock contracts in place of actual in-scope implementations ## 其他 Employees of Panoptic and employees' family members are ineligible to participate in this audit. Code4rena's rules cannot be overridden by the contents of this README. In case of doubt, please check with C4 staff. ```
标签:DeFi安全, Foundry, Panoptic, PoC, Solidity, 区块链安全, 合约漏洞, 四舍五入错误, 安全测试, 攻击性安全, 智能合约审计, 暴力破解, 漏洞分析, 资金损失, 路径探测, 逻辑缺陷