EigenLayer 改进提案-001:奖励 v2

该提案介绍了EigenLayer的奖励机制的第二次迭代(v2),旨在增强EigenLayer生态系统中奖励的灵活性。Rewards v2的主要功能包括:AVS根据operator表现定向奖励;AVS奖励的可变operator费用;专门用于Programmatic Incentives的operator拆分;以及方便staker和operator批量申领奖励。

EigenLayer 改进提案-001:奖励 v2

作者 Matt Nelson, Rajath Alex, Scott Conner, Sean McGary
创建日期 2024 年 10 月 18 日
状态 已合并
参考资料 EigenLayer 协议 PR EigenLayer 中间件 PR EigenLayer Sidecar PR
讨论 论坛帖子

概要

本提案介绍了 EigenLayer 奖励(v2) 的迭代,这是一项旨在增强 EigenLayer 生态系统中奖励灵活性的升级。在发布奖励的第一次迭代之后,通过来自 AVS 和 Operator 的反馈,我们建议扩展平台奖励功能。奖励 v2 是对奖励结构和合约的轻量级补充,解决了关键的奖励用例:

  • 基于绩效的和来自 AVS 的定向奖励给 Operator,
  • AVS 奖励上的可变 Operator 费用,
  • 专门针对程序化激励的 Operator 分成,
  • 针对 Staker 和 Operator 的批量奖励领取。

总而言之,这些变更将有助于在生态系统中实现广泛的灵活性:更多的 AVS 可以奖励 Operator,更多的 Operator 可以运行具有可变费率的不同 AVS,并且 Staker 将拥有数据来发现哪些服务和安全形式是 AVS 所重视的。

动机

奖励 v2 解决了 EigenLayer 奖励 MVP(v1)中发现的关键挑战,特别是需要通过外部逻辑进行 Operator 定向奖励,以及 Operator 在设置不同费率方面的灵活性,以便更好地覆盖运营成本或在运行不同 AVS 类型时吸引更多 stake。AVS 对更多基于绩效的奖励的需求不断增长,促使了这项新提案,确保 EigenLayer 的奖励协议能够服务于更广泛的场景。

在与 AVS 讨论之后,本提案旨在快速迭代 EigenLayer 奖励,以服务于以下用例:

  • 来自 AVS 的 Operator 定向奖励,允许 AVS 对特定 Operator 进行细分和奖励。这使 AVS 可以灵活地为个别 Operator 设置自定义奖励逻辑,基于完成的工作或他们可能设计或渴望的任何其他内容(例如,为了去中心化或安全原因,Operator 支持的更平均分配)。
    • 每个 AVS 的可变 Operator 费用,由 Operator 设置,允许 Operator 从奖励中提取少于或多于 10% 的默认费用。这保持了 EigenLayer 作为协议的费用无关性,并通过 Operator 在选择运行哪个 AVS 和吸引新的 stake 时的可变抽取率来释放灵活性。
    • 通过允许他们简化奖励领取流程,这也更好地服务于像 LRT 这样的集成 Staker-Operator,并释放了程序化分配奖励的更多灵活性,这可能会启用新的用例。
  • 用于 Staker 和 Operator 的批量奖励领取,允许以一种节省 gas 的方式代表单个交易中的多个赚取者进行领取。

以上迭代将使奖励从 AVS 流向 Operator 的方式更加灵活。

AVS 一直在寻找向 EigenLayer 协议管理的 token 生命周期添加额外激励功能的方法,例如 Staker 定向奖励。此功能不在本提案的范围之内。

设计目标

奖励 v2 旨在成为奖励 MVP(v1)的 可选 和附加升级,具有以下属性:

  1. AVS 的外部奖励计算逻辑

    1. AVS 可以利用他们自己的链上或链下奖励计算逻辑,基于除与 stake 线性缩放以外的其他因素(,利用绩效或生成的工作),并通过基于绩效的奖励界面严格提交追溯性奖励。
  2. AVS 和 Operator 基础设施的灵活性:

    1. Operator 可以设置他们每个 AVS 的费用,并向 AVS 和 Staker 发出信号,表明他们的服务价值多少以及他们将收取多少费用以换取所涉及的工作。任何费用变更都会延迟七天生效,以便 Staker 有时间根据新的抽取率调整其 Operator 服务提供商。
    2. AVS 可以根据 Operator 在特定时期内执行的工作来奖励 Operator,奖励由 AVS 根据 Operator 提供的工作进行定价。这将创建一个迭代的调整过程以达到平衡。
    3. AVS 可以向 Staker 发出信号,表明他们重视的服务和安全形式以及权重。
  3. 更便宜的批量领取:

    1. 在单个交易中对多个申领人进行批量申领将有助于降低 gas 成本。
  4. 利用现有基础设施:

    1. RewardsCoordinator 合约将被升级以支持基于绩效的奖励分配、设置每个 AVS 的 Operator 费用和批量申领的功能。
    2. 现有的 EigenLayer sidecar 将用于支持新的奖励类型,并将使用新的 Operator 费用将其纳入奖励计算中。奖励根计算和奖励根发布基础设施将保持不变。
    3. 对于 Staker 和 Operator 来说,申领 UX 体验将保持不变,并包括批量申领的额外好处。
  5. 奖励归属

    1. 基于绩效的或定向的 Operator 奖励的链上性质,以及策略和乘数的包含以及与 sidecar 的集成,实现了归属和奖励率计算。这有助于填充面向用户的信息并将 stake 吸引到 Operator 和 AVS。
      1. 归属定义为奖励根据 stake 权重在 Staker 之间分配的链上保证。这保证了“Staker-A 在 AVS-C 上赚取了 X 数量的 Token-B,因为他们 stake 了 Y 数量的 Token-D”形式的归属
  6. 无需许可的可验证性

    1. 奖励 v2 的所有方面都可以独立验证。
    2. 在“安全注意事项”部分中进一步说明。
  7. 防止奖励分配树膨胀:

    1. sidecar 中将进行验证,以确保在指定期间内获得奖励的 Operator 至少在该期间的一段时间内已注册到 AVS。这将使奖励树免于来自未注册 Operator 及其各自 Staker 的膨胀。
    2. 在“安全注意事项”部分中进一步解释。
  8. 启用程序化激励

    1. 奖励和 Operator 费用的更大灵活性更好地使协议能够根据 AVS、Staker 和 Operator 的输入在生态系统中分配激励。
    2. 更丰富的信息提供了对 AVS、Staker 和 Operator 偏好的更多见解,使贡献者能够更好地了解市场状况,并有可能设计新的有针对性的激励措施以鼓励更具体的行为。
    3. 允许一组许可的地址向任何 Operator 发送奖励将能够在生态系统中激励各种行为。

特性与规范

本文档中的关键词“必须”、“不得”、“必需”、“应”、“不应”、“应该”、“不应该”、“推荐”、“可以”和“可选”应按照 RFC 2119 中的描述进行解释。

高级设计

奖励 v2 流程图

高级流程如下:

  1. Operator 可以通过调用 RewardsCoordinator 上的 setOperatorAVSSplit() 来设置其每个 AVS 的奖励费用(称为“split”)。这介于 AVS 奖励的 0% 或 100% 之间。在 7 天的激活延迟后才有效。如果他们不设置,它将保持在默认的 10%。一个 Operator 一次只能有一个待处理的 split 配置。
  2. AVS 在链下计算要分配给其已注册 Operator 的适当奖励:
    1. 他们首先向其 AVSServiceManager 授予 ERC20 批准,以获得所有 Operator 奖励的总和。
    2. 然后,他们在 AVSServiceManager 上调用 createOperatorDirectedAVSRewardsSubmission(),该调用将调用代理到 RewardsCoordinator。这将启动基于绩效的奖励分配,并将所有 Operator 奖励的总和存入 RewardsCoordinator 的分配中。
    3. 发出 OperatorDirectedAVSRewardsSubmissionCreated 事件。
  3. 现有的奖励 v1 的链下基础设施也用于基于绩效的奖励:
    1. Sidecar 监听 OperatorDirectedAVSRewardsSubmissionCreated 事件并存储它。
    2. Sidecar 每天生成奖励根,同时考虑 Operator 定向奖励和适当的 Operator split(除了它已经处理的其他奖励事件之外)。
    3. Root Updater 从 sidecar 检索最新的根,并通过调用 RewardsCoordinator 上的 submitRoot() 每周发布该根。
  4. 在现有的 7 天激活延迟后,Operator 和 Staker 然后通过调用 RewardsCoordinator 合约上的 processClaims() 来批量领取他们所有的奖励。

有关 Sidecar 的更多详细信息,请参见下文。

低级规范

EigenLayer 协议

RewardsCoordinator 透明代理将升级为指向包含以下逻辑的新实现。

Operator 定向奖励的分配

该设计主要建立在现有的奖励 v1 接口之上,并带有额外的字段,这些字段:

  1. 启用从 AVS 到 Operator 的可归属奖励。
  2. 使 AVS 委托的接口具有前瞻性。

AVS 可以自由地在奖励归属逻辑中使用链上或链下数据来确定每个 Operator 的奖励金额。这可以根据 Operator 在特定时间段内执行的工作进行自定义,可以是统一的奖励率,也可以是基于 AVS 经济模型的其他结构。这将使 AVS 能够灵活地奖励不同 Operator 的绩效和其他变量,同时为委托给同一 Operator 和 strategy 的 Staker 保持相同的易于计算的奖励率。AVS 可以提交以不同 token 计价的多个基于绩效的奖励,以获得更大的灵活性。

接口

可以在下面找到 RewardsCoordinator 中 Operator 定向奖励的接口。

/**
 * @notice Strategies 和乘数的线性组合,供 AVS 加权 EigenLayer strategies。
 * @param strategy 要用于奖励 submission 的 EigenLayer strategy。
 * @param multiplier 奖励 submission 中 strategy 的权重。
 */
 struct StrategyAndMultiplier {
     IStrategy strategy;
     uint96 multiplier;
 }

/**
 * @notice Operator 的奖励结构体
 * @param operator 要奖励的 Operator
 * @param amount Operator 的奖励金额
 */
struct OperatorReward {
    address operator;
    uint256 amount;
}

/**
 * @notice OperatorDirectedRewardsSubmission 结构体,由 AVS 在为其 Operator 和 staker 制定 Operator 定向奖励时提交。
 * @param strategiesAndMultipliers strategies 及其相对权重。
 * @param token 要分配的奖励 token。
 * @param operatorRewards Operator 的奖励。
 * @param startTimestamp 考虑用于分配的 submission 范围的时间戳(秒)。
 * @param duration submission 范围的持续时间,以秒为单位。
 * @param description 描述奖励 submission 的用途。
 */
struct OperatorDirectedRewardsSubmission {
    StrategyAndMultiplier[] strategiesAndMultipliers;
    IERC20 token;
    OperatorReward[] operatorRewards;
    uint32 startTimestamp;
    uint32 duration;
    string description;
}

/**
 * @notice 当 AVS 创建有效的 `OperatorDirectedRewardsSubmission` 时发出
 * @param caller 调用 `createOperatorDirectedAVSRewardsSubmission` 的地址。
 * @param avs 代表其提交 Operator 定向奖励的 avs。
 * @param operatorDirectedRewardsSubmissionHash (`avs`、`submissionNonce` 和 `operatorDirectedRewardsSubmission`) 的 Keccak256 哈希。
 * @param submissionNonce avs 的当前 nonce。用于生成唯一的 submission 哈希。
 * @param operatorDirectedRewardsSubmission Operator 定向奖励 Submission。包含 token、开始时间戳、持续时间、Operator 奖励、描述以及 strategy 和乘数。
 */
event OperatorDirectedAVSRewardsSubmissionCreated(
    address indexed caller,
    address indexed avs,
    bytes32 indexed operatorDirectedRewardsSubmissionHash,
    uint256 submissionNonce,
    OperatorDirectedRewardsSubmission  
);

/**
 * @notice 代表 AVS 创建一个新的 Operator 定向奖励 submission,以在注册到 `avs` 的 Operator 和委托给 Operator 的 staker 集合之间进行 split。
 * @param avs 代表其提交奖励的 AVS。
 * @param operatorDirectedRewardsSubmissions 要创建的 Operator 定向奖励 submissions。
 */
function createOperatorDirectedAVSRewardsSubmission(
    address avs,
    OperatorDirectedRewardsSubmission[] calldata operatorDirectedRewardsSubmissions
) external;
实现
  1. Operator 定向奖励必须包括以上字段;没有一个是可选的。
  2. 目前avs 调用(它具有前瞻性,可以由 avs 委托地址调用)。需要进行 msg.sender == avs 检查。如果检查失败,则抛出错误。
  3. 对于每个 operatorDirectedRewardsSubmissions
    1. 验证以下各项:
      1. 如果 strategiesAndMultipliers 数组的长度为 0,则抛出错误。这些是必需的。
      2. 如果 operatorRewards 数组的长度为 0,则抛出错误。这些是必需的。
      3. 对于每个 operatorReward,验证以下各项:
        1. 如果 operatoraddress(0),则抛出错误。
        2. 如果 Operator 地址不是按升序排列,则抛出错误。这是为了处理重复项。
        3. 如果 amount 为 0,则抛出错误。
      4. 所有金额的总和必须 <= MAX_REWARDS_AMOUNT。否则抛出错误。
      5. duration 必须 <= MAX_REWARDS_DURATION。否则抛出错误。
      6. duration 必须CALCULATION_INTERVAL_SECONDS 的倍数。否则抛出错误。
      7. startTimestamp 必须CALCULATION_INTERVAL_SECONDS 的倍数。否则抛出错误。
      8. startTimestamp 必须 > GENESIS_REWARDS_TIMESTAMP。否则抛出错误。
      9. startTimestamp 必须block.timestamp 之前的 MAX_RETROACTIVE_LENGTH 内。否则抛出错误。
      10. startTimestamp + duration 必须 < block.timestamp。否则抛出错误。基于绩效的奖励必须是严格的追溯性奖励。
      11. 对于每个 strategyAndMultiplier,验证以下各项:
        1. strategy 必须在存款的白名单中。否则抛出错误。
        2. 如果 strategy 地址不是按升序排列,则抛出错误。这是为了处理重复项。
    2. Keccak256 哈希 avssubmissionNonceoperatorDirectedRewardsSubmission 的 ABI 编码。
    3. 存储哈希并更新 nonce。
    4. 将绩效奖励 submission token 的奖励总额转移到 RewardsCoordinator 合约中。
    5. 将发出 OperatorDirectedAVSRewardsSubmissionCreated 事件。
注意事项
  1. avs 当前是相应的 AVSServiceManager
  2. 在调用 createOperatorDirectedAVSRewardsSubmission 之前,RewardsCoordinator 合约需要 operatorDirectedRewardsSubmissions 中所有 operatorRewards 总和的 token 批准。
  3. createOperatorDirectedAVSRewardsSubmission 函数主要只是进行链上验证,将奖励总额存入 RewardsCoordinator 合约中并发出事件。
  4. 当与 sidecar 更改一起实施时,每次调用 createOperatorDirectedAVSRewardsSubmission() 都会奖励每个 operator 及其 Staker 在 startTimestamp 之后的 durationamounttoken,代表 avs。 Operator 将获得其合约配置的奖励 split,该奖励在 RewardsCoordinator 中设置,其余部分将按比例分配给 strategies 和乘数。
  5. 奖励计算在 sidecar 中离线完成。在 EigenLayer Sidecar 部分中进一步说明。检查那里以了解如何在给定持续时间内计算 Operator 和 Staker 奖励。
可变 Operator 费用

在奖励 v2 上线后,Operator 将能够在 RewardsCoordinator 中更改其每个 AVS 粒度的税后费用。在 7 天的激活延迟后才有效,以便 Staker 有时间根据新的抽取率调整其 Operator 服务提供商。如果他们不设置每个 AVS 奖励 split,它将默认为 10%。

此可变费用在 AVS 支付的奖励的 0% 到 100% 之间没有对其价值的约束。AVS 仍然可以通过在 AVS 目录合约上调用 deregisterOperatorFromAVS() 来选择驱逐他们认为以恶意行事的 Operator。我们希望 AVS 和 Operator 能够进行讨论,以发现不同类型的 AVS 的正确动态。

接口

可以在下面找到 RewardsCoordinator 中可变 Operator Split 接口。

/**
 * @notice Operator 的 split 结构体
 * @param oldSplitBips 以基点表示的旧 split。如果 `block.timestamp &lt; activatedAt`,则此 split 处于活动状态
 * @param newSplitBips 以基点表示的新 split。如果 `block.timestamp >= activatedAt`,则此 split 处于活动状态
 * @param activatedAt split 将被激活的时间戳
 */
struct OperatorSplit {
    uint16 oldSplitBips;
    uint16 newSplitBips;
    uint32 activatedAt;
}

/**
 * @notice 当设置 AVS 的 Operator split 时发出。
 * @param caller 调用 `setOperatorAVSSplit` 的地址。
 * @param operator 代表其设置 split 的 Operator。
 * @param avs Operator 为其设置 split 的 avs。
 * @param activatedAt split 将被激活的时间戳。
 * @param oldOperatorAVSSplitBips Operator 的 AVS 旧 split。
 * @param newOperatorAVSSplitBips Operator 的 AVS 新 split。
 */
event OperatorAVSSplitBipsSet(
    address indexed caller,
    address indexed operator,
    address indexed avs,
    uint32 activatedAt,
    uint16 oldOperatorAVSSplitBips,
    uint16 newOperatorAVSSplitBips
);

/**
 * @notice 设置特定 Operator 的特定 avs 的 split。
 * @param operator 设置 split 的 Operator。
 * @param avs Operator 为其设置 split 的 avs。
 * @param split Operator 的特定 avs 的 split。
 */
function setOperatorAVSSplit(address operator, address avs, uint16 split) external;

/// @notice 特定 `operator` 的特定 `avs` 的 split
function getOperatorAVSSplit(address operator, address avs) external view returns (uint16);
实现
  1. setOperatorAVSSplit() 必须包括所有字段;没有一个是可选的。
  2. 目前operator 调用(它具有前瞻性,可以由 Operator 委托地址调用)。需要进行 msg.sender == operator 检查。如果检查失败,则抛出错误。
  3. 如果 split 严格大于 10000(即 100%),则抛出错误。
  4. 如果给定 operatoravs 的更早 split 尚未激活,则抛出错误。
  5. 每次调用 setOperatorAVSSplit() 都会代表 operator 设置 avssplit(以基点为单位)。
  6. split 将在 7 天的激活延迟后激活。
  7. 将发出 OperatorAVSSplitBipsSet 事件。
注意事项
  1. 在进行奖励计算时,sidecar 将考虑 split 的 7 天激活延迟。在 EigenLayer Sidecar 部分中进一步说明。
用于程序化激励的 Operator Split

Eigen Foundation 程序化激励的默认 Operator split 为 10%,可变 split 旨在确保所有规模和 stake 的 Operator 都能因其参与而获得奖励。在 7 天的激活延迟后才有效。它可以独立于其他 AVS 进行设置,并且具有与 v2 奖励相同的 Operator 委托 Staker 的奖励分配动态。

接口

可以在下面找到 RewardsCoordinator 中用于程序化激励的 Operator Split 接口。

/**
 * @notice Operator 的 split 结构体
 * @param oldSplitBips 以基点表示的旧 split。如果 `block.timestamp &lt; activatedAt`,则此 split 处于活动状态
 * @param newSplitBips 以基点表示的新 split。如果 `block.timestamp >= activatedAt`,则此 split 处于活动状态
 * @param activatedAt split 将被激活的时间戳
 */
struct OperatorSplit {
    uint16 oldSplitBips;
    uint16 newSplitBips;
    uint32 activatedAt;
}

/**
 * @notice 当设置程序化激励的 Operator split 时发出。
 * @param caller 调用 `setOperatorPISplit` 的地址。
 * @param operator 代表其设置 split 的 Operator。
 * @param activatedAt split 将被激活的时间戳。
 * @param oldOperatorPISplitBips Operator 的程序化激励的旧 split。
 * @param newOperatorPISplitBips Operator 的程序化激励的新 split。
 */
event OperatorPISplitBipsSet(
    address indexed caller,
    address indexed operator,
    uint32 activatedAt,
    uint16 oldOperatorPISplitBips,
    uint16 newOperatorPISplitBips
);

/**
 * @notice 设置特定 Operator 的程序化激励的 split。
 * @param operator 代表其设置 split 的 Operator。
 * @param split Operator 的程序化激励的 split。
 */
function setOperatorPISplit(address operator, uint16 split) external;

/// @notice 特定 `operator` 的程序化激励的 split
function getOperatorPISplit(address operator) external view returns (uint16);
实现
  1. setOperatorPISplit() 必须包括所有字段;没有一个是可选的。
  2. 目前operator 调用(它具有前瞻性,可以由 Operator 委托地址调用)。需要进行 msg.sender == operator 检查。如果检查失败,则抛出错误。
  3. 如果 split 严格大于 10000(即 100%),则抛出错误。
  4. 如果给定 operator 的更早 split 尚未激活,则抛出错误。
  5. 每次调用 setOperatorPISplit() 都会代表 operator 设置程序化激励的 split(以基点为单位)。
  6. split 将在 7 天的激活延迟后激活。
  7. 将发出 OperatorPISplitBipsSet 事件。
注意事项
  1. 在进行奖励计算时,Sidecar 将考虑 split 的 7 天激活延迟。在 EigenLayer Sidecar 部分中进一步说明。
批量奖励申领

为了实现 gas 高效的申领方式,奖励 v2 还提供了一个用于批量申领的新接口(即 processClaims())。v1 接口(即 processClaim())仍然可用。目前,我们仅支持每个单个赚取者进行申领。此接口提供了一种将多个赚取者的申领批量化为单个交易的方法。

接口

可以在下面找到 RewardsCoordinator 中的批量奖励申领接口。

/**
 * @notice 赚取者帐户叶子的 Merkle 树中的内部叶子。
 * @param earner 赚取者的地址。
 * @param earnerTokenRoot 赚取者 token 子树的 Merkle 根。
 */
struct EarnerTreeMerkleLeaf {
    address earner;
    bytes32 earnerTokenRoot;
}

/**
 * @notice 分配 Merkle 树中的实际叶子,指定各个赚取者的子树的 token 收益。
 * @param token 要申领收益的 ERC20 token。
 * @param cumulativeEarnings 赚取者的 token 的累积收益。
 */
struct TokenTreeMerkleLeaf {
    IERC20 token;
    uint256 cumulativeEarnings;
}

/**
 * @notice 针对分配根的申领。
 * @param rootIndex DistributionRoots 列表中根的索引。
 * @param earnerIndex Merkle 树中赚取者帐户根的索引。
 * @param earnerTreeProof 针对 Merkle 根的赚取者的 EarnerTreeMerkleLeaf 的证明。
 * @param earnerLeaf 赚取者的 EarnerTreeMerkleLeaf 结构体,提供赚取者地址和 earnerTokenRoot
 * @param tokenIndices 赚取者子树中 token 叶子的索引
 * @param tokenTreeProofs 针对赚取者的 earnerTokenRoot 的 token 叶子的证明
 * @param tokenLeaves 要申领的 token 叶子。
 */
struct RewardsMerkleClaim {
    uint32 rootIndex;
    uint32 earnerIndex;
    bytes earnerTreeProof;
    EarnerTreeMerkleLeaf earnerLeaf;
    uint32[] tokenIndices;
    bytes[] tokenTreeProofs;
    TokenTreeMerkleLeaf[] tokenLeaves;
}

/**
 * @notice 当针对 distribution 根申领赚取者奖励时发出。
 * @param root 被申领的 distribution 根。
 * @param earner 代表其申领奖励的赚取者。
 * @param claimer 奖励的申领者。
 * @param recipient 接收 ERC20 奖励的地址。
 * @param token 要申领收益的 ERC20 token。
 * @param claimedAmount 被申领的金额。
 */
event RewardsClaimed(
    bytes32 root,
    address indexed earner,
    address indexed claimer,
    address indexed recipient,
    IERC20 token,
    uint256 claimedAmount
);

/**
 * @notice 针对给定的 distribution 根批量申领奖励。
 * @param claims 要处理的 RewardsMerkleClaims。包含根索引、赚取者、token 叶子和所需的证明
 * @param recipient 接收 ERC20 奖励的地址。
 */
function processClaims(RewardsMerkleClaim[] calldata claims, address recipient) external;
实现
  1. processClaims() 必须包括所有字段;没有一个是可选的。
  2. 现有 processClaim() 外部函数中的所有逻辑都将重构为新的 _processClaim() 内部函数。processClaim() 将调用 _processClaim()。这保持了 processClaim() 的现有接口不变。
  3. processClaims() 只能由有效的申领者调用,也就是说,如果 claimerFor[claim.earner]address(0),则只有赚取者可以申领,否则只有 claimerFor[claim.earner] 可以申领奖励。
  4. processClaims() 将迭代多个 claims,并为每个申领调用 _processClaim()
  5. 奖励 Merkle 树的结构为 Merkle 根位于顶部,而 EarnerTreeMerkleLeaf 作为树中的内部叶子。每个赚取者叶子都有自己的子树,其中 TokenTreeMerkleLeaf 作为子树中的叶子。为了证明针对指定的 rootIndex(指定正在使用的 distributionRoot)的申领,该申领将首先验证赚取者叶子在树中是否包含在 _distributionRoots[rootIndex].root 中。然后,对于每个 token,它将验证 token 叶子在赚取者的子树中是否包含在赚取者的 earnerTokenRoot 中。
  6. 将为每个申领发出 RewardsClaimed 事件。
注意事项
  1. 收益是累积的,因此赚取者不必针对他们获得收益的所有 distribution 根进行申领。他们只需针对最新的根进行申领,并且合约将计算其 cumulativeEarningscumulativeClaimed 之间的差额。然后,此差额将转移到 recipient 地址。
  2. 每个申领都可以指定他们要申领的赚取者的哪些已赚取 token(即不必在单个申领中申领所有 token)
更新后的计算间隔秒数

CALCULATION_INTERVAL_SECONDS 将从 1 周更新为 1 天,以反映 sidecar 中发生的每日奖励计算。这将使 AVS 能够提交 startTimestampduration 是 1 天而不是 1 周的倍数的奖励。

globalOperatorCommissionBips 重命名为 defaultOperatorSplitBips

这是接口中的一个重大更改globalOperatorCommissionBips 公共存储变量将在 RewardsCoordinator 合约中的所有实例中重命名为 defaultOperatorSplitBips

EigenLayer 中间件

EigenLayer 中间件具有强制性版本,作为此 ELIP 的一部分,以支持基于绩效的奖励。AVS 必须升级其各自的 AVSServiceManager 合约,以继承新的 ServiceManagerBase 实现,以便能够提交基于绩效的奖励。

接口

可以在下面找到 ServiceManagerBase 中 Operator 定向奖励的接口:

/**
 * @notice 创建一个新的 Operator 定向奖励提交,以在 Operator 和委托给注册到此 `avs` 的 Operator 的 Staker 集之间进行划分。
 * @param operatorDirectedRewardsSubmissions 要创建的 Operator 定向奖励提交
 */
function createOperatorDirectedAVSRewardsSubmission(IRewardsCoordinator.OperatorDirectedRewardsSubmission[] calldata operatorDirectedRewardsSubmissions) external;

/**
 * @notice 将调用转发到 Eigenlayer 的 RewardsCoordinator 合约,以设置可以代表此合约调用 `processClaim` 的实体的地址。
 * @param claimer 可以代表赚取者调用 `processClaim` 的实体的地址
 */
function setClaimerFor(address claimer) external;
实现
  1. createOperatorDirectedAVSRewardsSubmission() 必须包含以上字段;没有一个是可选的。
  2. 只有 rewardsInitiator 才能调用它。否则抛出错误。
  3. 对于每个 operatorDirectedRewardsSubmissions
    1. 将奖励总额转移到该 token 中的 AVSServiceManager
    2. 批准 RewardsCoordinator 用于该 token 中的奖励总额。
  4. RewardsCoordinator 合约中调用 createOperatorDirectedAVSRewardsSubmission
注意事项
  1. operatorDirectedRewardsSubmission 对象必须遵守 RewardsCoordinator.createOperatorDirectedAVSRewardsSubmission 中的验证
  2. 在调用 createOperatorDirectedAVSRewardsSubmission 之前,AVSServiceManager 合约需要 operatorDirectedRewardsSubmissions 中所有 operatorRewards 总和的 token 批准。

EigenLayer Sidecar

EigenLayer Sidecar 是一个开源的、无需许可的、经过验证的索引器,它使任何人(AVS、Operator 等)都可以实时访问 EigenLayer 的协议奖励和 EigenLayer 状态。作为此 ELIP 的一部分,EigenLayer Sidecar 必须强制发布,以增强基于性能的奖励。这是 Rewards v2 流程的关键部分。

将引入以下高级功能:

  1. 摄取新的 Rewards v2 事件并将它们存储在 sidecar 的内部数据库中:OperatorDirectedAVSRewardsSubmissionCreatedOperatorAVSSplitBipsSetOperatorPISplitBipsSet
  2. 新的 Operator 指导的奖励计算,包括每个 avs 的 Operator 拆分(如果已设置)。
  3. 更新 Rewards MVP (v1) 计算,以包括每个 avs 的 Operator 拆分(如果已设置)。
  4. 更新 Programmatic Incentives 奖励计算,以包括 Programmatic Incentives 的 Operator 拆分(如果已设置)。
EigenStateModel

Rewards v2 版本将包括对 3 个新支持的事件的状态模型:OperatorDirectedAVSRewardsSubmissionCreatedOperatorAVSSplitBipsSetOperatorPISplitBipsSet

Schema
// `OperatorDirectedAVSRewardsSubmissionCreated` 事件的 Eigen State Schema
type OperatorDirectedRewardSubmission struct {
    Avs             string
    RewardHash      string
    Token           string
    Operator        string
    OperatorIndex   uint64
    Amount          string
    Strategy        string
    StrategyIndex   uint64
    Multiplier      string
    StartTimestamp  *time.Time
    EndTimestamp    *time.Time
    Duration        uint64
    Description     string
    BlockNumber     uint64
    TransactionHash string
    LogIndex        uint64
}

// `OperatorAVSSplitBipsSet` 事件的 Eigen State Schema
type OperatorAVSSplit struct {
    Operator                string
    Avs                     string
    ActivatedAt             *time.Time
    OldOperatorAVSSplitBips uint64
    NewOperatorAVSSplitBips uint64
    BlockNumber             uint64
    TransactionHash         string
    LogIndex                uint64
}

// `OperatorPISplitBipsSet` 事件的 Eigen State Schema
type OperatorPISplit struct {
    Operator                string
    ActivatedAt             *time.Time
    OldOperatorAVSSplitBips uint64
    NewOperatorAVSSplitBips uint64
    BlockNumber             uint64
    TransactionHash         string
    LogIndex                uint64
}
Implementation

每个新事件都将被 sidecar 摄取、处理并根据上述 schema 存储在 sidecar 的内部数据库中的各自的表中。

Operator 指导的奖励计算

Rewards v2 版本将包括一个新的 Operator 指导的奖励计算,该计算考虑了每个 avs 的 Operator 拆分。

Implementation

Operator 指导的奖励计算将遵循此处指定的现有奖励计算实施。

此外还有以下内容:

  1. Operator 佣金按照以下逻辑计算:
    1. 如果在当前快照时间,operator_avs_split 表中存在特定 operator 的已激活的 OperatorAVSSplit 行,则使用该 split 进行奖励计算。
    2. 否则,使用默认拆分(目前设置为 10%)。
  2. Operator 指导的奖励提交中指定的 Operator 金额在 Operator 注册到该特定 AVS 的天数内平均分配。对于未注册到该特定 AVS 的天数,Operator 不会获得任何奖励。
  3. 在 Operator 指导的奖励提交包括在整个指定期间未注册到该特定 AVS 的 Operator 的极端情况下,该期间快照的 Operator 金额将作为特定快照的分配叶子退还给 AVS。AVS 可以使用常规的申领流程来获得退款。这样做的原因在安全注意事项部分(在防止奖励分配树膨胀下)中进行了解释。
Rewards MVP (v1) 计算

Rewards MVP 计算将被更新,以包括作为 Rewards v2 一部分发布的每个 avs 的 Operator 拆分。

Implementation
  1. 如果在当前快照时间,operator_avs_split 表中存在特定 operator 的已激活的 OperatorAVSSplit 行,则使用该 split 进行奖励计算。
  2. 否则,使用默认拆分(目前设置为 10%)。
Programmatic Incentives 计算

Programmatic Incentives 计算将被更新,以包括作为 Rewards v2 一部分发布的每个 avs 的 Operator 拆分。

Implementation
  1. 如果在当前快照时间,operator_pi_split 表中存在特定 operator 的已激活的 OperatorPISplit 行,则使用该 split 进行奖励计算。
  2. 否则,使用默认拆分(目前设置为 10%)。

Security Considerations

关键安全考虑因素包括:

  1. 无需许可的可验证性

    1. Rewards v2 利用与 Rewards MVP (v1) 相同的链下基础设施进行奖励计算(即 sidecar)和 root 发布(即 root updater)。
    2. sidecar 被设计为可以从 EigenLayer genesis 进行重放,以便任何人都可以以无需许可的方式启动一个新的 sidecar 并验证计算。
    3. sidecar 将使用其现有计算来观察并验证 RewardsCoordinator 中更新的 root 是否正确。
  2. 防止奖励分配树膨胀:

    1. sidecar 中将进行验证,以确保在指定期间获得奖励的 Operator 在该期间的至少一部分时间内已注册到 AVS。这将使奖励树免受未注册的 Operator 及其各自的 Staker 的膨胀。
    2. 如果在特定的快照时间存在对未注册的 Operator 的链上奖励,则该快照的未注册的 Operator 的金额将作为该快照的分配叶子退还给 AVS。然后,AVS 可以将这些资金作为常规申领过程的一部分进行申领。

已对 Rewards v2 进行了 2 次审计:

  1. SigmaPrime 对 Core Protocol、Middleware 和 Sidecar 组件的整体审核:审计报告
  2. OpenBlock 对奖励计算的 SQL 审计:审计报告

Impact Summary

Rewards v2 的预期影响包括:

优点:

  1. 增强的灵活性:AVS 可以更灵活地控制奖励逻辑,从而实现可以在链上归属的定制化和多样化的奖励机制。
  2. AVS 增加采用率: 通过支持 Operator 指导的奖励系统,Rewards v2 将使 Eigenlayer 对 AVS 更有用。
  3. 鼓励 Operator 运行更多的 AVS:通过提供每个 AVS 可变的 Operator 费用结构,Operator 在选择要运行的 AVS 时具有更大的经济灵活性。
  4. 提高奖励发布速度:Operator 指导的奖励将奖励逻辑与核心协议合约分离,使 AVS 可以更快地迭代奖励逻辑,并减少协议更新中的瓶颈。
  5. 无需许可的可验证性:Rewards v2 的所有方面都可以独立验证。
  6. 批量处理节省 gas: 通过启用奖励申领的批量处理,具有多个地址的 Operator 和 Staker 可以节省赎回费用。

缺点:

  1. Gas 成本:由于 Operator 指导的奖励仍保留在链上以保持奖励归属的属性,因此随着 AVS 奖励更多的 Operator,奖励提交的 gas 成本将线性增加。
  2. 没有直接给 Staker 的奖励或激励结构:链上归属的权衡取消了完全灵活的分配结构。这消除了 EigenLayer 作为 AVS 的激励分配机制和 token 生命周期工具的用例。

Action Plan

此 ELIP 的实施将遵循以下关键步骤:

  1. 升级 EigenLayer 协议:升级 RewardsCoordinator 透明代理以指向一个新的实现合约,该合约引入了此处指定的逻辑。
  2. 更新 EigenLayer Middleware:为 ServiceManagerBase 发布一个新版本,其中引入了此处指定的逻辑。 AVS 必须升级其各自的 AVSServiceManager 合约以继承新的 ServiceManagerBase 实现,以便能够提交基于性能的奖励。
  3. 更新 EigenLayer Sidecar:为 EigenLayer Sidecar 发布一个新版本,其中引入了此处指定的逻辑。 所有运行奖励计算和验证的各方必须在此 ELIP 升级 EigenLayer 协议的区块高度之前将其 EigenLayer sidecar 升级到此版本。 否则将导致不正确的计算并可能导致 sidecar 停止。

此过程将首先在 Eigen 测试网上开始,然后在 AVS 进行测试和集成后在主网上进行,以确保成功。 在主网之后,将通过索引链上奖励的事件来跟踪 Rewards v2 的采用情况。 这可以帮助确定此 ELIP 的成功并跟踪对协议的改进。

References & Relevant Discussions

Operator Working Group October 2024 AVS Working Group October 2024

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

0 条评论

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