Byzantine Finance
Website - Home🖥️ For Developers
  • 👋Introduction
    • What is Byzantine Finance?
      • Permissionless strategy vaults
      • Strategy layer & infrastructure layer - Explain Like I'm 5
      • Architecture Overview
    • Explanation of terms
    • Restaking explained
  • Media kit
  • 🔑Byzantine Vaults
    • What are Byzantine vaults?
    • Features of Native Vaults
      • Byzantine Oracle
      • Best practices for Validator Managers
    • Types of Native Vaults
      • Solo Staker Vaults
      • Partner Validated Vaults
      • Distributed Validator Vaults
  • ↔️Vault Interaction
    • Deposit
      • Deposit to ERC20 Vaults
      • Deposit to Native Vaults
    • Withdraw
      • Withdraw from ERC20 Vaults
      • Withdraw from Native Vaults
    • Claim Rewards
      • Restaking Rewards
        • EigenLayer Rewards
        • Symbiotic Rewards
  • 🎛️Vault Creation
    • Overview
      • Vault Configuration Guide
      • Vault Parameters
        • Byzantine Vault Parameters
        • Native Vault Parameters
        • EigenLayer Parameters
        • Symbiotic Parameters
      • Roles
    • Single Protocol Vaults
      • EigenLayer Vault
        • Eigen ERC20 Vault
        • Eigen Native Vault
      • Symbiotic Vault
        • Sym ERC20 Vault
        • Sym Native Vault
    • Cross Protocol Vaults
      • Eigen Layer / Symbiotic ERC20 Vault
  • 🤖Curation
    • Overview
    • Curator Related Roles
    • Vault Management
    • Strategy Management
      • EigenLayer Strategy
      • Symbiotic Strategy
      • Cross Protocol Vault
    • Curation Fee Management
  • 🌐Node operators
    • Operators in the Byzantine ecosystem
    • Register as a Staking Operator
    • Staking
    • Restaking Operator
      • Symbiotic
      • EigenLayer
      • Allocation to existing Restaking Operators
      • Creation of on-demand Restaking Operators
  • Claiming DV operator fees
Powered by GitBook
On this page
  • Keywords
  • Overview
  • High Level Design
  • EigenRewards Merkle Tree
  • Byzantine Rewards Calculation Process
  • Step-by-Step Process For Staker Rewards
  • Fees For Curator
  • Merkle Proof Generation For Claims
  1. Vault Interaction
  2. Claim Rewards
  3. Restaking Rewards

EigenLayer Rewards

Restaking rewards distribution from EigenLayer to Byzantine stakers, operators and curators

PreviousRestaking RewardsNextSymbiotic Rewards

Last updated 1 day ago

This section explores the detailed technical structure of the contract, focusing on how restaking rewards from EigenLayer are distributed to the Byzantine stakers, operators and curators.


Keywords

  • : A smart contract within the EigenLayer ecosystem that handles restaking rewards distributed by AVSs to their stakers and operators.

  • : A Byzantine contract that interacts with the RewardsCoordinator contract. It recalculates the rewards for each Byzantine staker based on the rewards distributed by the RewardsCoordinator and allows these stakers to claim their EigenLayer restaking rewards.

  • EigenLayer : An open source, permissionless, verified indexer enabling anyone (AVS, operator, etc) to access EigenLayer’s protocol rewards in real-time.

  • Byzantine Sidecar: Operates similarly to the EigenLayer Sidecar. It serves as an indexer enabling users to access Byzantine's Eigen-related rewards in real-time. The Byzantine Sidecar runs in parallel with the EigenLayer Sidecar to extract the relevant rewards data. These rewards are recalculated to ensure equitable distribution among stakers in the same Eigen Byz vault, based on their staking amount and duration.

  • Merkle trees: Cryptographic data structures that allow efficient and secure verification of large data sets.

  • Distribution root: A Merkle root of the earnings distribution for a given period. It is used later to verify that a staker has a specific amount of rewards in specific tokens within a particular vault.

  • Merkle proof: When using merkle trees to store data, a proof is used to verify that a specific transaction is part of a leaf against a Merkle root hash. By comparing hashes along a path from the data to the root, the authenticity of specific data can be verified.


Overview

  • The EigenLayer rewards calculation is performed off-chain based on the rewards given by AVSs to operators and stakers.

  • The Byzantine rewards are also calculated off-chain based on the EigenLayer rewards calculation by monitoring the EigenLayer Sidecar.

  • Both EigenLayer and Byzantine protocols use the Merkle tree solution to enable stakers to claim rewards.

  • The EigenRewards contract requires that every time EigenLayer submits a distribution root to RewardsCoordinator, the root submitter from Byzantine must submit a distribution root to EigenRewards.

In the context of the Byzantine protocol, an earner on EigenLayer is either an Eigen Native Vault or an Eigen ERC20 Vault.


High Level Design

A simplified and high level flow is as follows:

  1. AVSs distributes rewards to their stakers and operators via RewardsCoordinator.

  2. The EigenLayer Sidecar runs daily to listen to the events emitted by the RewardsCoordinator contract and calculate offchain the rewards of each EigenLayer staker. A distribution root that merkleize the cumulative sum of each EigenLayer staker and operator is submitted to RewardsCoordinator by the RootUpdater.

  3. At the same time, the Byzantine Sidecar is running constantly to access the rewards data provided by the Sidecar, recalculates the rewards for each Byzantine staker based on the rewards accumulated by the Eigen Vaults that are extracted from the Sidecar. A distribution root that merkleize the cumulative sum of each Byzantine staker is also submitted to EigenRewards.

  4. Anyone including the staker can pull the rewards that belongs to a specific Eigen Vault from RewardsCoordinator to EigenRewards.

  5. Once the vault rewards are transferred to EigenRewards, the Byzantine stakers can claim their rewards.

Byzantine operators should claim their rewards by interacting directly with the RewardsCoordinator.


EigenRewards Merkle Tree

As mentioned earlier, Merkle proofs are used in the Byzantine rewards distribution. In other words, rewards are saved using a Merkle tree and a Merkle proof verification is required in order to claim rewards.

Byzantine has developed a custom Merkle tree structure tailored to its protocol architecture.

The EigenRewards Merkle tree is designed to contain Byzantine stakers' cumulative rewards. Utilizing the EigenLayer RewardsCoordinator Merkle tree, the Byzantine Sidecar extracts rewards data related to any Eigen Vault and constructs the Byzantine EigenReward tree. This tree is organized hierarchically with the Merkle root at the top and nested subtrees below, efficiently organizing rewards data across Eigen Vaults, stakers, and tokens.

The structure of the tree is explained as follows:

  • The Merkle tree's highest root contains the vault tree Merkle leaves. Each vault leaf holds the cumulative rewards of all stakers within a specific Eigen Vault.

  • Each vault leaf has its own subtree with StakerTreeMerkleLeaf as leaves in the subtree. Each staker leaf contains the cumulative rewards of one staker within a specific Eigen Vault.

  • Each staker leaf has its own subtree with TokenTreeMerkleLeaf as leaves in the subtree. Each token leaf contains the cumulative rewards in specific tokens that a staker has earned for the relevant period.

Overview of the EigenLayer and Byzantine Merkle trees

An Earner leaf on RewardsCoordinator becomes a Vault leaf on EigenRewards.

Distribution roots of both merkle trees

In both EigenLayer and Byzantine protocols, a root submitter is responsible to submit, every 7 days, a new distribution root the the respective contract (RewardsCoordinator and EigenRewards) to ensure that the onchain rewards are up to date.

Both contracts store all historical distribution roots so that stakers can claim their rewards against older roots if they wish. However, rewards contained in both merkle trees are cumulative. The Eigen merkle tree contains the the cumulative earnings of all earners and tokens for a given period, whereas the Byzantine merkle tree includes the cumulative earnings of all all Eigen Byz vaults, stakers, and tokens for the same given period. (cf. graphic below) Therefore, stakers only need to claim against the latest root to claim all available earnings.


Byzantine Rewards Calculation Process

Byzantine has developed an offchain Sidecar that monitors the EigenLayer Sidecar in real-time, enabling the protocol to calculate staker rewards within the Byzantine ecosystem.

(For more details related to the EigenLayer rewards calculation, cf. below:)

Just like EigenLayer rewards calculation, the Byzantine rewards calculation proceeds in 3 stages and runs daily:

  • Data extraction: Accesses the EigenLayer rewards data from the Sidecar and extracts the rewards pertinent to all Eigen Vaults.

  • Rewards calculation: Reorganizes and calculates the rewards in specific tokens for each staker in an Eigen Vault.

  • Rewards aggregation: Aggregates all rewards for a specific period and submits a root that merkleizes the cumulative sum of each staker within a given vault to the EigenReward.

Step-by-Step Process For Staker Rewards

To claim rewards, follow these three steps: submit the root, pull vault rewards from EigenLayer to Byzantine, and claim staker rewards.

1

Submitting Distribution Roots (done by Byzantine)

Function to invoke:

function submitRoot(bytes32 _root, uint32 _rewardsCalculationEndTimestamp) external;

Explanation:

Once the Byzantine Sidecar aggregates all rewards for a specific period and updates the Merkle tree, the root submitter designated by Byzantine must invoke the submitRoot() function. This is necessary to submit the new distribution root to the contract, ensuring the onchain rewards state is updated.

A root becomes claimable by Byzantine stakers if the following conditions are met:

  • The root is not disable by the root submitter.

  • The root's activation delay has elapsed.

  • For each vault that is included the root, the rewards of the vault are pulled from RewardsCoordinator to EigenRewards.

EigenLayer RewardsCoordinator and Byzantine EigenRewards will always have the same number of distribution roots that are submitted to the respective contract.

2

Pulling Vault Rewards (done by anyone or the stakers)

This step is a crucial condition that must be fulfilled to claim staker rewards from a vault.

Function to invoke:

function pullVaultRewards(
    IRewardsCoordinator.RewardsMerkleClaim calldata _claim
) external;

Parameters to prepare:

struct RewardsMerkleClaim {
    uint32 rootIndex;
    uint32 earnerIndex;
    bytes earnerTreeProof;
    EarnerTreeMerkleLeaf earnerLeaf;
    uint32[] tokenIndices;
    bytes[] tokenTreeProofs;
    TokenTreeMerkleLeaf[] tokenLeaves;
}

Explanation:

The pullVaultRewards() function can be called by anyone or a staker to transfer a specific Eigen Vault's rewards from RewardsCoordinator to EigenRewards. These vault rewards, received by EigenRewards, consist of the total earnings in all tokens not yet pulled for all stakers of that specific vault.

Every pullVaultRewards() call is stored at the lastPulledAt mapping which maps the vault address to the distribution root index for later use in claimsStakerRewards().

The caller can claim rewards against an older root.

The caller cannot choose specific tokens or stakers for which to claim rewards.

For practical reasons and simplicity, the transfer of vault rewards from RewardsCoordinator to EigenRewards is structured so that every call to pullVaultRewards() automatically claims all rewards for all stakers associated with a specific vault. This design reduces the number of pullVaultRewards()calls: one single call enables all stakers to proceed with step 3.

Before calling pullVaultRewards() , it is recommended to call rewardsCoordinator.getCurrentClaimableDistributionRoot() . This is to check the latest claimable root on RewardsCoordinator to avoid any revert due to non-activated or disabled root.

Batch claims:

Use this function to execute a single transaction to pull rewards of multiple vaults to EigenRewards. It is required to provide a list of IRewardsCoordinator.RewardsMerkleClaim as input to the function.

function batchPullVaultRewards(
    IRewardsCoordinator.RewardsMerkleClaim[] calldata _claims
) external;

3

Claiming Staker Rewards (done by the stakers)

To claim staker rewards for a specific vault against a particular root, the vault rewards included in the same root must be first transferred from RewardsCoordinator to EigenRewards. (cf. step 2)

Function to invoke:

function claimStakerRewards(RewardsMerkleClaim calldata _claim, address _recipient) external;

Parameters to prepare:

struct RewardsMerkleClaim {
    uint32 rootIndex;
    uint32 vaultIndex;
    bytes vaultTreeProof;
    VaultTreeMerkleLeaf vaultLeaf;
    uint32 stakerIndex;
    bytes stakerTreeProof;
    StakerTreeMerkleLeaf stakerLeaf;
    uint32[] tokenIndices;
    bytes[] tokenTreeProofs;
    TokenTreeMerkleLeaf[] tokenLeaves;
}

Explanation:

The staker or their claimer of EigenByzVaults can call claimStakerRewards() to claim rewards of a specific staker in any vault and in any token. To accomplish this, the staker must prepare the RewardMerkleClaim for this purpose by specifying the vault, the staker, and the list of tokens to claim.

The final claimed amount is the amount of rewards that is left after subtracting the curator fee from the actual earnings.

The caller can claim rewards against an older root. (cf. details in step 2)

The claimer can specify the vault and tokens for which to claim the rewards.

In a RewardsMerkleClaim, three types of proofs are required: vaultTreeProof, stakerTreeProof, and a list of tokenTreeProofs. A staker can claim their eligible rewards in any vault by providing the vaultTreeProof for that specific vault. Similarly, they can claim rewards for any token by submitting the tokenTreeProof within the bytes[] tokenTreeProof array. The remaining unclaimed tokens can be claimed at any later time.

Before calling claimStakerRewards() , it is recommended to call getCurrentActivatedDistributionRoot() . This is to check the latest claimable root on EigenRewards to avoid any revert due to non-activated root, disabled root or vault rewards not pulled yet.

Batch claims:

Use this function to execute a single transaction to claim rewards of multiple stakers in the same or different vaults. It is required to provide a list of RewardsMerkleClaim as input to the function.

The caller must be the claimer set for the stakers for whom the claims are made.

function batchClaimStakerRewards(RewardsMerkleClaim[] calldata _claims, address _recipient) external;

Fees For Curator

Function to invoke:

function claimCuratorFee(IERC20 _token, address _vault, address _recipient) external;

The curator of an Eigen Byz Vault can set and adjust the curator fee percentage. They call this function claim all cumulative fees distributed in a specific token for a particular vault at once.

Each time a staker calls the claimStakerRewards, the curator fee amount is increased and stored in the contract.

Merkle Proof Generation For Claims

Coming soon...

For more details about the code mentioned below, refer to the contract.

The claim for this specific function is provided by the .

When claiming vault rewards based on an old root in a Merkle tree, all accumulated rewards up to that root will be claimed (cf. ). The rewards stored in later roots can still be claimed at any time.

It is recommended and also beneficial to claim vault rewards against the latest root to ensure that the EigenRewards contract always holds most up-to-date token rewards, providing a better UX for stakers. Claiming the latest root doen't cost more gas fee than claiming against an older root.

↔️
🍀
EigenRewards
RewardsCoordinator
EigenRewards
Sidecar
interface of the EigenRewards
RewardsCoordinator contract
cumulative earnings
EigenLayer Rewards Calculation | EigenLayer Sidecar
EigenRewards Merkle Tree Overview
Demonstration of cumulative earnings in distribution roots
Logo