ELIP-006 提议: 在 EigenLayer 中引入可重新分配的罚没机制

ELIP-006 提议在 EigenLayer 中引入可重新分配的罚没机制,允许服务构建者在惩罚运营商时,不仅可以销毁罚没资金,还可以将其重新分配给指定的接受者。这种机制的引入扩展了 EigenLayer 的使用场景,尤其是在借贷、保险和风险对冲等领域,同时需要对 EigenLayer 的安全模型和权益保障进行调整以支持这种新的罚没模式。

作者 创建时间 状态 参考 讨论
Matt Nelson, 0xClandestine 2025-04-30 merged PR 1355, PR 1485, 合约文档 讨论论坛帖子

ELIP-006: 可重新分配的 Slashing


执行摘要

Slashing (ELIP-002) 是 EigenLayer 愿景的关键部分;它使得服务构建者能够执行对消费者和用户做出的加密经济承诺。目前,在 EigenLayer 上利用 slashing 时,安全资金总是在惩罚 Operator 时被销毁或锁定。这给涉及借贷、保险、风险对冲或广泛需要补偿受害方或分摊风险的承诺的用例构建者带来了挑战。

可重新分配的 Slashing 是一种功能,它使服务构建者不仅可以销毁,还可以重新利用被 slashing 的资金。重新分配代表了构建者可以在 EigenLayer 上启动的用例类型的扩展,通过扩展平台上 slashing 的表达性。一种具有严格配置控制的新型 Operator Set 允许 AVS 指定接收被 slashing 资金的重新分配接受者。这项新功能需要对 EigenLayer 安全模型和 AVS 的 stake 保证进行调整,并且随这些调整一起发布,以支持这种新的 slashing 范式。

动机

EigenLayer 中的 Slashings 会导致资金立即且不可逆转地销毁。现有的 slashing 机制在资本表达方面具有限制性;资金要么被永久销毁,要么需要链下方法来重新利用。这种限制大大缩小了潜在应用的范围——尤其是在保险和借贷等关键领域。与此同时,链下或竞争解决方案采用了可重新分配的 slashing。缺乏重新分配会影响服务构建者探索 DeFi 或保险等用例。

引入可重新分配的 slashing 显着扩展了 EigenLayer 上 slashing 的表达性和实用性。更复杂的 slashing 解锁了有价值的协议应用程序,例如 EigenLayer 上的保险、借贷、桥接和 DeFi 服务。使服务构建者能够围绕可重新分配的 slashing 设计协议,可以提高 AVS、Operator 和 Staker 的资本效率。这些 slashing 更改代表了影响大、工程工作量适中的机会。

总的来说,可重新分配的 slashing 承诺扩展用例的多样性,增加 AVS 的参与度,增加安全资产和 AVS 代币的价值积累,并最终实现 EigenLayer 生态系统中更强大的收入增长。

特性与规范

概述

截至今天,当被 slashing 时,ERC-20 资金在 0x0...00e16e4 地址被销毁;EigenPod Native ETH 资金在被 slashing 时会被永久锁定。这是在 slashOperator 函数之后异步完成的。有关 slashing 机制的更多详细信息,请参见 ELIP-002。相同的 slashOperator 机制在很大程度上适用于可重新分配的 slashing。可重新分配的 slashing 需要对核心协议进行最小的更改……

  • 创建一种新型的可重新分配 Operator Set,
  • 处理 redistributionRecipient,当调用 clearBurnOrRedistributableShares 以将资金从协议中转移出来时,它会替换销毁地址,
  • 更好地使用标识符 (slashId) 装饰每次 slashing,这有助于下游的以编程方式进行的重新分配和会计处理。

这些更改在 AllocationManager 接口中是面向外部的。 这也伴随着对 AllocationManager 的存储的更改。 在内部,我们修改了 ShareManagerStrategyManager 接口,以及一些存储和内部逻辑。

规范

重新分配的操作员集合

为了利用可重新分配的 slashing,AVS 必须实例化一个新的 RedistributingOperatorSet。这些集合指定了一个 redistributionRecipient 地址,以后无法更改。这是在触发 slashing 后将接收资产的地址。可以将其设置为 Ethereum 上的任何地址(EOA 或合约)。AVS 可以在上游设置他们喜欢的任何地址,但应保证任何合约的运行方式,以吸引和留住 Staker 和 Operator。

⚠️ 警告

重新分配的操作员集合无法配置 EIGEN 或 Native ETH Strategy。这些资产不支持可重新分配的 slashing。有关基本原理的更多详细信息,请参见下文。

AllocationManger 接口中提供了新的 getter 和 setter 函数:

interface IAllocationManager {
    /// @dev `IAllocationManager` 中的现有结构体。
    struct CreateSetParams {
        uint32 operatorSetId;
        IStrategy[] strategies;
    }

    /// 事件

    /// @notice 当 AVS 创建重新分配的操作员集合时发出。
    event RedistributionAddressSet(OperatorSet operatorSet, address redistributionRecipient);

    /// 写入

    /**
     * @notice 由 AVS 调用,用于 slashing 给定操作员集合中的操作员。该操作员必须已注册,并且已将可 slashing 的 stake 分配给该操作员集合。
     *
     * @param avs 发起 slashing 的 AVS 地址。
     * @param params slashing 参数,包含:
     *  - operator:要 slashing 的操作员。
     *  - operatorSetId:操作员要从中 slashing 的操作员集合的 ID。
     *  - strategies:要从中 slashing 分配的 Strategy 数组(必须按升序排列)。
     *  - wadsToSlash:要从每个 Strategy 中 slashing 的比例数组(必须介于 0 和 1e18 之间)。
     *  - description:操作员被 slashing 的原因的描述。
     *
     * @dev 对于每个 Strategy:
     *      1. 将操作员的当前分配量按 wadToSlash 比例减少。
     *      2. 按比例减少 Strategy 的最大量和已占用量。
     *      3. 如果有待处理的取消分配,则按比例减少它。
     *      4. 更新 DelegationManager 中操作员的份额。
     *
     * @dev 由于舍入,少量 slashing 可能导致实际代币被销毁
     *      ,这将导致少量代币被锁定在合约中
     *      ,而不是通过销毁机制完全销毁。
     * @return slashId 操作员集合的 slashing 唯一标识符。
     * @return shares 要为每个被 slashing 的 Strategy 销毁或重新分配的份额数量。
     */
    function slashOperator(
        address avs,
        SlashingParams calldata params
    ) external returns (uint256 slashId, uint256[] memory shares);

    /**
     * @notice 允许 AVS 创建新的重新分配操作员集合。
     * @param avs 创建新操作员集合的 AVS。
     * @param params 操作员集合创建参数的数组。
     * @param redistributionRecipients 当操作员被 slashing 时将接收重新分配的资金的地址数组。
     * @dev 与 `createOperatorSets` 的逻辑相同,只是存储了对应于每个操作员集合的 `redistributionRecipients`。
     *      此外,为每个创建的操作员集合发出 `RedistributionOperatorSetCreated` 事件,而不是 `OperatorSetCreated` 事件。
     */
    function createRedistributingOperatorSets(
        address avs,
        CreateSetParams[] calldata params,
        address[] calldata redistributionRecipients
    ) external;

    /// 读取

    /**
     * @notice 返回给定操作员集合的 slashing 资金将被发送到的地址。
     * @param operatorSet 要查询的操作员集合。
     * @return 对于重新分配的操作员集合,返回在操作员集合创建期间配置的重新分配地址集。
     *         对于非重新分配的操作员集合,返回 `DEFAULT_BURN_ADDRESS`。
     */
    function getRedistributionRecipient(
        OperatorSet memory operatorSet
    ) external view returns (address);

    /**
     * @notice 返回给定的操作员集合是否支持重新分配
     * 或当资金被 slashing 并从 EigenLayer 销毁时不支持。
     * @param operatorSet 要查询的操作员集合。
     * @return 对于重新分配的操作员集合,返回 true。
     *         对于非重新分配的操作员集合,返回 false。
     */
    function isRedistributingOperatorSet(
        OperatorSet memory operatorSet
    ) external view returns (bool);

    /**
     * @notice 返回给定操作员集合的 slashing 数量。
     * @param operatorSet 要查询的操作员集合。
     * @return 操作员集合的 slashing 数量。
     * @dev Slash 计数器仅在重新分配生效后才会递增(不包括之前的 slashing)。
     */
    function getSlashCount(
        OperatorSet memory operatorSet
    ) external view returns (uint256);

    /**
     * @notice 返回操作员是否可以被重新分配操作员集合 slashing。
     * @param operator 要查询的操作员。
     */
    function isOperatorRedistributable(
        address operator
    ) external view returns (bool);
}

RedistributingOperatorSets 在核心中的行为方式与普通 Operator Sets 相同. 与协议和 AVSRegistrar 合约相关的Operator Set 创建和注册的逻辑和控制流程保持不变。我们在存储中存储一个额外的字段,该字段将 Operator Set ID 映射到给定的 redistributionRecipientStake 分配机制的行为方式与其他 Operator Sets 相同。

Slash 标识符

Slash 的处理方式与现有协议中基本相同。 slashOperator 函数已更新为返回 slashId(充当 nonce)、被 slashing 的 strategiesshares 中被 slashing 的数量。在返回数据中添加 slashId 是为了辅助上游(和链外)合约对资金进行编程处理,以实现重新分配逻辑。Stake 的核算没有改变。新的存储模型如下:

abstract contract AllocationManagerStorage {
    /// @notice 返回给定操作员集合的 slashing 数量。
    /// @dev 这也用作唯一的 slash 标识符。
    /// @dev 这会跟踪重新分配发布后的 slashing 数量。
    mapping(bytes32 operatorSetKey => uint256 slashId) internal _slashCount;

    /// @notice 返回给定操作员集合的 slashing 资金将被发送到的地址。
    /// @dev 对于重新分配的操作员集合,返回在操作员集合创建期间配置的重新分配地址集。
    ///      对于非重新分配或不存在的操作员集合,返回 `address(0)`。
    mapping(bytes32 operatorSetKey => address redistributionAddr) internal _redistributionRecipients;
}

所有处理 slashing 的核心合约,即 DelegationManagerShareManagerStrategyManagerEigenPodManager,都已更新某些输入以接受 slashId。这是为了在资金销毁或重新分配期间进行适当的下游核算。以下 ShareManager 已针对 slashId 进行了修改

interface IShareManager {
    /// @notice 由 DelegationManager 使用,用于在进入提款队列时从特定的 Strategy 中删除 Staker 的份额。
    /// @dev strategy 在与 EigenPodManager 通信时必须是 beaconChainETH。
    /// @return updatedShares 减量后的 staker 的存款份额。
    function removeDepositShares(
        address staker,
        IStrategy strategy,
        uint256 depositSharesToRemove
    ) external returns (uint256);

    /// @notice 由 DelegationManager 使用,用于奖励 Staker 一些已通过提款队列的份额。
    /// @dev strategy 在与 EigenPodManager 通信时必须是 beaconChainETH。
    /// @return existingDepositShares 在添加任何份额之前的 staker 的份额。
    /// @return addedShares 添加到 staker 余额中的新份额。
    function addShares(
        address staker, 
        IStrategy strategy, 
        uint256 shares
    ) external returns (uint256, uint256);

    /// @notice 由 DelegationManager 使用,用于将存款份额转换为代币并将它们发送给 staker。
    /// @dev strategy 在与 EigenPodManager 通信时必须是 beaconChainETH。
    /// @dev 在与 EigenPodManager 通信时,不会验证代币。
    function withdrawSharesAsTokens(
        address staker, 
        IStrategy strategy, 
        IERC20 token, uint256 shares) external;

    /// @notice 返回 `user` 在 `strategy` 中的当前份额。
    /// @dev strategy 在与 EigenPodManager 通信时必须是 beaconChainETH。
    /// @dev 如果用户有负份额,则返回 0。
    function stakerDepositShares(address user, 
        IStrategy strategy
    ) external view returns (uint256 depositShares);

    /**
     * @notice 增加给定 Strategy 的可销毁/可重新分配的份额数量。 当在 EigenLayer 中 slashing 操作员时,DelegationManager 将调用此函数。
     * @param operatorSet 要在其中销毁份额的操作员集合。
     * @param slashId 要在其中销毁份额的 slash ID。
     * @param strategy 要在其中销毁份额的 Strategy。
     * @param addedSharesToBurn 要销毁的增加的份额数量。
     * @dev 仅当 slashing 操作员时,DelegationManager 才会调用此函数。
     */
    function increaseBurnOrRedistributableShares(
        OperatorSet calldata operatorSet,
        uint256 slashId,
        IStrategy strategy,
        uint256 addedSharesToBurn
    ) external;
}

销毁和分配机制

从协议中退出被 slashing 资金的流程和代码路径已更改。 之前,ERC-20 资金以固定的节奏通过提款或销毁(转移到 0x00...00e16e4)流出协议。 在此升级之后,当发生 slashing 时,资金将分两步退出。 为了保持协议保证 slashOperator 永远不会失败,流出转移是非原子的。

当发生单个 slashing 时……

  • 与原始销毁实现类似,首先在 StrategyManager 存储中将已 slashing 的份额增加为“可销毁或可重新分配”的份额。
  • 在另一次调用中,将 slashed 的份额转换为资金,并将其直接转移到 redistributionRecipient(如果使用非重新分配操作员集,则销毁)。 这是通过对 StrategyManager 上的 clearBurnOrRedistributeShares 函数进行无需许可的调用来完成的。

这种两部分流程是非原子完成的,以保持 slashing 永远不会失败的保证,即使在代币转账或从协议中删除资金的某些其他上游问题可能失败的情况下也是如此。 在将资金转移到重新分配接收者时,使用非原子方法维护此流程,并添加可重新分配的份额而不会造成延迟。 AVS 可以调用 clearBurnOrRedistributeShares,或者 cron 作业会在一段时间后调用它,以确保资金在 slashing 后不会保留在协议中。

下图说明了新流程:

sequenceDiagram
    title 重新分配和销毁流程

    participant AVS as AVS
    participant ALM as 分配管理器
    participant DM as 委托管理器
    participant SM as Strategy 管理器
    participant STR as Strategy 合约
    participant RR as 重新分配接收者

    Note over AVS,SM: Tx 1. Slashing Operator
    AVS->>ALM: slashOperator<br>(avs, slashParams)
    ALM-->>DM: *Internal* <br>slashOperatorShares<br>(operator, strategies,<br> prevMaxMags, newMaxMags)
    Note over DM,SM: 份额管理
    DM-->>SM: *Internal*<br>increaseBurnOrRedistributableShares<br>(operatorSet, slashId, strategy, addedSharesToBurn)

    Note over SM,RR: Tx 2. 销毁或重新分配资金
    SM->>SM: clearBurnOrRedistributableShares(operatorSet, slashId)
    SM-->>STR: *Internal*<br>withdraw<br>(recipient, token, underlyingAmount)
    STR-->>RR: *Internal*<br>transfer<br>(token, underlyingAmount)
    Note right of RR: 最终协议资金流出

StrategyManager 接口已更新为处理资金的直接重新分配,从而取代了以前可用的 burnShares 功能。

interface IStrategyManager {
    /// @dev 尝试添加已在操作员集合的销毁或可重新分配份额中的 Strategy 时抛出。
    error StrategyAlreadyInSlash();

    /// @notice 当 slashing 操作员并且要销毁或重新分配的份额增加时发出
    event BurnOrRedistributableSharesIncreased(
        OperatorSet operatorSet, uint256 slashId, IStrategy strategy, uint256 shares
    );

    /// @notice 当标记为销毁或重新分配的份额减少并分配时发出
    event BurnOrRedistributableSharesDecreased(
        OperatorSet operatorSet, uint256 slashId, IStrategy strategy, uint256 shares
    );

    /// NOTE: 我们保留了原始的 `burnShares` 函数,以便仍然可以完成传统的销毁。

    /**
     * @notice 从存储中删除已销毁的份额,并将 slashId 的基础代币转账到重新分配接收者。
     * @dev 在 `clearBurnOrRedistributableSharesByStrategy` 函数中检查了重入。
     * @param operatorSet 要在其中销毁份额的操作员集合。
     * @param slashId 要在其中销毁份额的 slash ID。
     * @return 转移到每个 Strategy 的重新分配接收者的代币数量。
     */
    function clearBurnOrRedistributableShares(
        OperatorSet calldata operatorSet,
        uint256 slashId
    ) external returns (uint256[] memory);

    /**
     * @notice 从存储中删除单个 Strategy 的份额,并将 slashId 的基础代币转账到重新分配接收者。
     * @param operatorSet 要在其中销毁份额的操作员集合。
     * @param slashId 要在其中销毁份额的 slash ID。
     * @param strategy 要在其中销毁份额的 Strategy。
     * @return 转移到 Strategy 的重新分配接收者的代币数量。
     */
    function clearBurnOrRedistributableSharesByStrategy(
        OperatorSet calldata operatorSet,
        uint256 slashId,
        IStrategy strategy
    ) external returns (uint256);

    /**
     * @notice 返回给定 slashId 的尚未发送到重新分配接收者的 Strategy 和份额。
     * @param operatorSet 要在其中销毁或重新分配份额的操作员集合。
     * @param slashId 要在其中销毁或重新分配份额的 slash ID。
     * @return 给定 slashId 的 Strategy 和份额。
     */
    function getBurnOrRedistributableShares(
        OperatorSet calldata operatorSet,
        uint256 slashId
    ) external view returns (IStrategy[] memory, uint256[] memory);

    /**
     * @notice 返回给定 slashId 的给定 Strategy 的份额。
     * @param operatorSet 要在其中销毁或重新分配份额的操作员集合。
     * @param slashId 要在其中销毁或重新分配份额的 slash ID。
     * @param strategy 获取份额的 Strategy。
     * @return 给定 Strategy 的给定 slashId 的份额。
     * @dev 如果份额已发送到重新分配接收者,则此函数将恢复。
     */
    function getBurnOrRedistributableShares(
        OperatorSet calldata operatorSet,
        uint256 slashId,
        IStrategy strategy
    ) external view returns (uint256);

    /**
     * @notice 返回给定 slashId 的尚未发送到重新分配接收者的 Strategy 数量。
     * @param operatorSet 要在其中销毁或重新分配份额的操作员集合。
     * @param slashId 要在其中销毁或重新分配份额的 slash ID。
     * @return 给定 slashId 的 Strategy 数量。
     */
    function getBurnOrRedistributableCount(
        OperatorSet calldata operatorSet,
        uint256 slashId
    ) external view returns (uint256);
}

更新了 EigenPodManager 接口,以避免内部流程中的重大更改。

回顾一下新的或修改的功能:

  • 新的操作员集合类型启用固定的 redistributionRecipient
  • 已将其他元数据添加到每个 slashing,以帮助 AVS 构建以编程方式进行的重新分配。
  • StrategyManager 具有修改后的流程以适应重新分配与销毁。

理由

重新分配 AVS 保证和可见性

可重新分配的 slashing 在代码上是一个适度的升级,但对 EigenLayer 系统的激励和保证有广泛的影响。本提案中的大部分设计旨在确保 Staker 的尽可能多的安全,因为重新分配直接增加了 AVS slashing Operator 的动机。

由于资金从协议中释放到 AVS 指定的地址,因此 Staker 必须具有正确的可见性才能了解委托给运行启用了重新分配 slashing 的 AVS 的任何 Operator 的风险,这一点很重要。 这是 redistributionRecipient 成为不可变地址的主要原因,该地址必须在 Operator Set 实例化时设置。 这提供了一些保证:

  • AVS 无法更改此地址。 尽管他们可以使用上游代理或传递合约,但这在 EigenLayer 中此地址的不可变性意味着 AVS 可以通过控制(例如治理、时间锁、不可变性等)来保护上游合约的可升级性来叠加额外的保证。
  • 重新分配的功能无法修改。 操作员集合在其创建时必须是可重新分配的。 因此,该协议可以对 Staker 和 Operator 在该操作员集合的生命周期内做出保证。 标准操作员集合不能突然重新分配。 并且重新分配的集合不能删除该属性。
  • 前端和元数据上的可见性。 通过强制执行上述属性的不可变性,EigenLayer 可以更好地在其应用程序以及链元数据中区分哪些启用了可重新分配的 slashing 以供其用户使用(以及交互的任何隐含或相关的风险和回报权衡)。

这些保证为增加 slashing 风险和改变的激励提供了对冲。

Native ETH 和 EIGEN 重新分配

Native ETH 不会包含在此提案的范围中。 它的排除主要与信标链的机制有关。 通过 ETH Strategy 上的可重新分配的 slashing,需要从信标链中退出验证器以补偿 redistributionRecipient。 我们无法保证有效余额足够高,或者部分提款可以弥补 slashing 的余额,而不会使验证器余额低于 32 ETH 的最低限额。

持续退出 Ethereum 验证器会给用户和网络带来一些问题:

  • 退出需要在验证器退出队列中等待,队列的长度从几小时到几周不等。
  • 资金必须等待被清除后才能到达 EigenPod 中指定的提款地址。 在清除此队列之前,AVS 将无法访问任何资金,这会影响以编程方式进行的设计。
  • 在某些对抗性情况下,会影响 Ethereum 网络安全。

总而言之,这些足以放弃在可重新分配的 slashing 的初始实现中的这个范围。 随着 Ethereum 的 Pectra 升级中启用的验证器的最大有效余额的增加,有一些可能的设计可以减轻上述担忧(例如,高于 32 ETH 的最低要求余额的部分提款)。 作为 EigenPod 改进的一部分,这些正在积极探索中,包括探索关于 EigenLayer 和 ETH 验证器上 slashing 的强制提款机制。

目前 EIGEN 不能在可重新分配的 slashing 中使用,因为它需要延迟代币协议流出。 这是为了支持其在主观故障中的使用。

安全考虑

最初的 slashing 设计与 ELIP-002 一起启动,它识别了多种类型的灾难性 slashing 错误。 灾难性 slashing 错误被认为是 AVS(或恶意方)可以......

  • slashing 超过分配给给定操作员集合中的操作员的 stake 数量(或超过该集合的总和,最高可达整个协议 TVL),
  • slashing 未注册到 AVS 操作员集合的操作员的唯一 stake,
  • 在未注册 AVS 的情况下触发 slashing。

使用可重新分配的 slashing,这些情况代表了可能导致未经授权的资金重新分配的盗窃途径。 这需要更强大的安全措施、审查,并且需要非常谨慎的实施。 我们已经完成了专门针对此升级的额外尽职调查,可以在我们的审计中找到,并在下面部分解释。

与往常一样,AVS 需要极其谨慎地管理密钥,因为当使用可重新分配的 slashing 时,泄露的 AVS 密钥可能导致用户资金被盗。 这不仅会损害 Staker,还可能造成无法弥补的声誉和金钱损失。

舍入和精度分析

我们进行了全面的手动分析并指导了模糊测试,以分析可重新分配的 slashing 环境中的协议舍入行为。 强烈建议你阅读 ELIP-002 以更好地了解分配和量级。 在这种情况下,我们的分析探讨了三个关键领域:

待处理取消分配中的精度漂移

与当前分配相比,待处理取消分配中的精度损失可能要大得多。 但是,这种额外的精度损失仅用于在完成取消分配时删除操作员的更多量级,从而损害操作员而不是使他们受益。 将待处理取消分配用作精度损失攻击的一部分没有任何好处。

存款缩放因子 (DSF) 操纵

我们发现了一种攻击途径,攻击者可以操纵其存款缩放因子以导致下溢,从而可能以天文数字膨胀其可提取金额。 但是,此攻击需要:

  • 从最大量级为 WAD-1 的 Operator 开始
  • 执行数千到数百万次的 1 份额存款
  • 实现容易下溢的超低 DSF 值

虽然理论上可行,但由于成本、复杂性和这种攻击的可观察性,此攻击在现实世界中是不切实际的。 作为一项安全措施,该协议现在在 SlashingLib.update 中包含 require(newDepositScalingFactor != 0) 以防止 DSF 下溢。

退出队列 Slashing 中的舍入

我们的分析证实,退出队列 slashing 中的精度损失会导致重新分配的资产减少而不是增加。 当发生精度损失时,会导致粉尘残留在协议中而不是可利用。 AVS 不能使用退出队列来 slashing 不属于他们的份额。

精度损失与以下因素成反比:

  • Operator 的分配量级
  • 被 Slashing 量级的比例
  • Operator 持有的份额数量

影响摘要

AVS 和服务构建者

AVS 将获得一种强大的新原语,即可重新分配的 slashing,在此基础上开发用例。 这也更加强调适当的密钥管理和操作安全要求。 redistributionRecipient 应被视为 AVS 控制的角色和签名密钥,并据此进行管理。 如果攻击者获得对 slasherredistributionRecipient 的 AVS 密钥的访问权限,则可以耗尽给定操作员集合的所有操作员和 Staker 分配的 stake。 这将对 AVS 的声誉和持续信任产生严重影响。

由于重新分配可能允许 AVS 从与 slashing 相关的盗窃中受益,因此必须格外注意设计,以考虑所有可以与之交互的各方的激励。 如果处理得当,AVS 将有新的用例机会,但必须考虑那些运行其代码的人的更高风险和 slashing 激励。

操作员选择和 Slashing 参数

根据我们的舍入和精度分析,AVS 在设计其 slashing 协议时应考虑以下准则(或实施不变量),以避免精度损失问题。 通常,以非常小的增量进行 slashing、slashing 量级非常低的操作员或 slashing 份额余额非常低的操作员可能导致精度损失,从而导致销毁/重新分配的金额远低于预期。 应遵循以下准则以最大程度地降低此风险。

操作员选择标准:

量级阈值:

  • 拒绝分配量级低于 1e9 的操作员:分配量级非常低的操作员在 slashing 期间更容易受到精度损失的影响
  • 理由:在 slashing 小量级时,由于舍入,mulWadRoundUp 操作可能会导致重新分配的金额为零
  • 检查:在允许注册之前,查询每个操作员-Strategy 对的 getAllocatedMagnitude()
  • 示例
    • Slashing 和分配参数:
    • 最大量级:1e18
    • 分配量级:1e4
    • wadsToSlash:1e14
    • operatorShares:1e17
    • 结果:
    • Slashing 量级:1 个粉尘
    • Slashing 份额:0

份额阈值:

  • 拒绝委托份额少于 1e9 的操作员:低份额计数会增加舍入错误的概率,从而减少重新分配的金额
  • 理由calcSlashedAmount 函数取决于 mulDiv 操作中的足够精度,以避免零结果
  • 检查:在注册之前,查询操作员在所有 Strategy 中的总委托份额
  • 交叉验证:确保同时满足量级和份额阈值,因为它们是相互依赖的

Slashing 金额注意事项:

百分比阈值:

  • 当 slashing 小于 0.01% (1e14 WAD) 时,请格外小心:非常小的 slashing 百分比更容易出现精度损失
  • 数学基础:对于具有不确定量级/份额的操作员,slashing 金额低于 1e14 WAD 可能会导致重新分配的金额为零
  • 建议:考虑实施最低 slashing 百分比(例如,0.1% 或 1e15 WAD)以实现可靠的重新分配
  • 测试:验证你预期的 slashing 百分比是否会相对于你的最低操作员阈值产生非零结果

代币小数位数注意事项:

  • 标准代币(18 个小数位数):通常遵循量级/份额阈值时是安全的
  • 低小数位数代币需要格外小心
    • USDC(6 个小数位数):需要至少 1000 USDC 存款才能达到 1e9 精度
    • USDT(6 个小数位数):与 USDC 相同的注意事项
    • WBTC(8 个小数位数):需要至少 10 WBTC 存款才能达到 1e9 精度
  • 计算:对于小数位数为 d 的代币,最低存款 = 1e9 / 10^d 个代币
  • 风险评估:评估你预期的操作员生态系统是否可以满足这些存款要求

实施建议:

我们提供了一些建议以避免上述一些陷阱。 此处提供了一个演示,可以帮助说明一些验证。 以下是其他基本示例:

预注册验证:

// 示例验证检查
require(getAllocatedMagnitude(operator, strategy) >= 1e9, "量级不足");
require(getOperatorShares(operator) >= 1e9, "份额不足");
require(tokenDecimals >= 6, "代币小数位数太低"); // 根据风险承受能力进行调整
```*前置 Slash 验证:*

```solidity
// 前置 slash 检查示例
uint256 expectedSlash = calculateExpectedSlash(operator, strategy, slashPercentage);
require(expectedSlash > 0, "Slash 金额四舍五入为零");
require(slashPercentage >= MINIMUM_SLASH_PERCENTAGE, "Slash 百分比太小");

监控和警报:

  • 跟踪精度损失事件:监控导致重新分配金额为零或异常小的 Slash
  • 边缘案例警报:为接近幅度/份额阈值的 Operator 设置警报
  • 审计 Slash 结果:定期验证 Slash 金额是否与预期计算相符

测试建议:

  • 模糊测试:针对具有不同幅度/份额组合的 Operator,使用随机小金额测试 Slash
  • 边缘案例测试:使用你预期的 Slash 百分比专门测试最小阈值
  • 多策略测试:验证当 Operator 在具有不同 Token 小数位的多个策略中进行分配时的行为

恢复程序:

  • Dust 累积:了解精度损失会导致少量 "Dust" 残留在协议中
  • Operator 补救:为低于阈值的 Operator 制定程序(例如,要求额外存款)
  • Slash 调整:如果精度损失变得成问题,则制定调整 Slash 参数的程序

风险评估框架: AVS 应该根据以下参数评估其特定用例:

  1. 预期的 Operator 规模分布:大多数 Operator 是否可以轻松满足 1e9 阈值?
  2. Slash 频率和金额:你预计 Slash 的频率和数量是多少?
  3. Token 生态系统:Operator 将 Stake 哪些 Token,它们是否满足小数位要求?
  4. 精度容忍度:你的协议可以容忍少量的精度损失吗?

遵循这些指南有助于确保 Slash 可靠运行并且重新分配的金额与预期相符,同时最大限度地降低与精度相关的问题的风险。

Operators

在运行任何可重新分配的 AVS 时,Operator 同样必须确保关注密钥管理和运维安全。Operator 密钥的泄露可能导致恶意行为者注册恶意的 AVS,并将分配给某些地址的 Staker 资金进行 Slash 和重新分配。Operator 可能会遭受潜在的不可挽回的声誉损害和 Staker 的不信任。

Operator 应该意识到,在注册任何重新分配的 Operator Sets 时,元数据会将他们标识为 Redistributable。这是为了帮助 Staker 识别风险。Operator 可能希望避免在寻求吸引 Stake 时更改其展示的资料(或者可以选择参与具有较高奖励的各种风险协议)。从所有重新分配的 Operator Sets 取消注册将删除此标记。对于 Operator 而言,运行具有可重新分配的 Slash 的 Operator Set 始终是可选择加入的。

Stakers

该提案对 Staker 的风险、奖励和激励模型产生了最大的影响。一般来说,当启用重新分配时,Slash 用户资金的动机更大。Staker 应该仔细考虑其委托的 Operator 正在运行的协议,并考虑风险和奖励的权衡。可重新分配的 Operator Sets 可能会提供更高的奖励,但应根据增加的 Slash 风险来考虑这些奖励。 此外,Staker 可能面临来自恶意 AVS 和恶意 Operator 的风险。如果 AVS 的治理或其 Slash 功能损坏,攻击者可能能够耗尽 Operator 委托的资金。如果 Operator 本身受到损害,它可能会启动自己的 AVS 来窃取用户资金。Staker 在进行委托时应仔细考虑 Operator 的声誉和合法性。我们在我们的论坛上更详细地概述了这些攻击场景

行动计划

该提案将使用上述接口和方法进入测试网上的测试阶段。EigenLayer 正在积极征求社区对该功能的反馈,然后再将其移至主网。因为这主要是 Operator 的一个可选择加入的功能(并且通过代理 Staker)。

  1. 实施和公开评论期(现在)
  2. 公开测试期和代码库的迭代,包括公开审计和相关补丁(下一步)
  3. 协议委员会的评估,并在接受后发布到主网(稍后)

该提案计划在两到三个月内完成。

参考文献和相关讨论

  • 原文链接: github.com/eigenfoundati...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
eigenfoundation
eigenfoundation
江湖只有他的大名,没有他的介绍。