EigenLayer Rewards
Restaking rewards distribution from EigenLayer to Byzantine stakers, operators and curators
Last updated
Restaking rewards distribution from EigenLayer to Byzantine stakers, operators and curators
Last updated
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.
: 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.
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.
A simplified and high level flow is as follows:
AVSs distributes rewards to their stakers and operators via RewardsCoordinator
.
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
.
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
.
Anyone including the staker can pull the rewards that belongs to a specific Eigen Vault from RewardsCoordinator
to EigenRewards
.
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 TreeAs 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.
An Earner leaf on RewardsCoordinator
becomes a Vault leaf on EigenRewards
.
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 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
.
To claim rewards, follow these three steps: submit the root, pull vault rewards from EigenLayer to Byzantine, and claim staker rewards.
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.
This step is a crucial condition that must be fulfilled to claim staker rewards from a vault.
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.
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.
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)
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.
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.
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.
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.