You Could've Invented EigenLayer

In this blog post, we will take you through the evolution of the protocol, by covering how EigenLayer's architecture emerged from the initial concept.

This blog is inspired by David Philipson’s series on account abstraction. Special thanks to Noam Horowitz, Shiva, NashQ, Mike Neuder, and Sina from the community for comments and feedback on the article.

While many people are familiar with the terms restaking and EigenLayer, only a few are aware that our core contracts consist of thousands of lines of code with the following architecture.

Simplified architecture of EigenLayer

Where did the complexity of a seemingly simple idea come from?

In this blog post, we will take you through the evolution of the protocol, by covering how EigenLayer's current complex architecture emerged from the initial concept.

The target audience for this post is individuals who have a basic understanding of smart contracts and have heard of EigenLayer or restaking.

Since the purpose of this blog post is to provide a high-level explanation of the EigenLayer's design evolution, there will be instances where the interface, variables, and logic may differ from the current EigenLayer core contracts.

Now, let's dive in.

End Goal: Making building infrastructure easy

First, let's preface with the problem EigenLayer is trying to solve. If you are already familiar with this part, move to later sections.

Developers who build decentralized infrastructures on Ethereum face the challenge of establishing their own economic security. While Ethereum provides economic security for smart contract protocols, infrastructures like bridges or sequencers require their own economic security to enable a distributed network of nodes to reach consensus.

Consensus mechanisms are essential for facilitating interactions among these nodes, whether it's an L1, an oracle network, or a bridge.

Proof of work is energy-intensive, proof of authority is overly centralized, and as a result, proof of stake (PoS) has emerged as the prevailing consensus mechanism for most infrastructure projects.

However, bootstrapping a new PoS network is hard.

Firstly, it is difficult to identify where the stakers (people who provide stake) are located. There is no single place where developers can find stakers.

Secondly, stakers must invest a significant amount of money to obtain a stake in the new network, usually by buying the network's native token, which is generally volatile and hard to get.

Thirdly, stakers must forgo other rewards opportunities, such as the 5% rewards offered by Ethereum.

Lastly, the current security model is undesirable as the cost to corrupt any dApp is simply the cost needed to compromise its weakest infrastructural dependency.

For now, we will assume that a staker participating in an infrastructure project is also responsible for operating the off-chain software to guarantee its security. However, we will change this assumption later in the article.

EigenLayer was created to address these issues.

  • It serves as a platform connecting stakers and infrastructure developers.
  • Stakers can offer economic security using any token.
  • Stakers have the option to restake their stake and contribute to the security of other infrastructures while earning native ETH rewards.
  • Through restaking, EigenLayer pools security instead of fragmenting it.
EigenLayer's whitepaper provides an in-depth exploration of these questions.

EigenLayer generalizes the concept of providing economic security.

Goal: Creating a platform connecting stakers and infrastructure developers

EigenLayer is the platform where stakers can provide stake for any infrastructure project, and infrastructure projects can pitch to potential stakers on EigenLayer. The backbone of this platform is enabling stakers to make credible commitments for different infrastructures.

What is this credible commitment?

These commitments are applicable to all PoS systems, not just EigenLayer. L1 stakers generally commit to following the protocol rules and risk losing their stake if they sign conflicting blocks at the same block height.

Infrastructure developers build the infrastructure logic and software, while stakers provide stake to secure the infrastructure. The stake serves as a commitment to the users of the infrastructures. This commitment is for the smooth running of the protocol and against specific misbehaviors.

Conceptually, when a project has $100m stake behind it, it means that if it deviates from its commitment and behaves maliciously, some portion of that $100m will be slashed. For simplicity, "slashed" can be thought of as burning that money.

The higher this number is, the more security and guarantees it provides to its users.

If we permit stakers to allocate stakes to various commitments, we can then create a user-friendly interface on top to make a platform.

We require a trustless and programmable platform to enforce different staker commitments, and Ethereum is the most suitable for this. Additionally, Ethereum holds the largest stake, which aids in bootstrapping the staker-side market.

The goal here is that a staker should be able to secure, for example, a bridge protocol through EigenLayer, on Ethereum. If a staker were to maliciously forge a message on Ethereum and transmit it to Gnosis, anyone can submit proof of this and slash the staker.

Since the staker's stake and commitment enforcement occur on Ethereum, the slashing logic is also implemented on Ethereum as smart contracts. If the staker breaches their commitment, anyone can present proof to the slashing contract and forfeit the malicious staker's stake.

This forms the foundation of EigenLayer - any staker can make credible commitments to any infrastructure protocol.

Initial Design for EigenLayer

Now, let's try to implement this. We'll start with the simplest design: a staker stakes tokens into a contract, which includes a function that allows for the slashing of the staker's tokens if a proof is submitted and meets the criteria. The user can then withdraw their balance.

Other stakers can also stake into this contract, adding to the security of the infrastructure. We'll refer to this contract as TokenPool.

To provide some clarity, here are some definitions for the terms used in this article:

  • Staker: anyone who provides tokens into EigenLayer.
  • Token: any kind of token; for simplicity, think of an ERC20 token for now.
  • TokenPool: a smart contract that holds the stakers' tokens.
  • Slashing: removing the staker's access to their staked tokens.

The interface of this TokenPool can be represented as the following:

contract TokenPool {
    mapping(address => uint256) public balance;
    function stake(uint256 amount) public;
    function withdraw() public;
    function slash(address staker, ??? proof) public;

Does this fulfill the requirement for any staker to provide stake for any infrastructure? Yes!

  1. Staker can pledge stake to a specific commitment (defined in the slash function)
  2. Slashed if found malicious (breaks from the commitment).
  3. Withdraw from the system.
βœ… It serves as a platform connecting stakers and infrastructure developers.
- Stakers can offer economic security using any token.
- Stakers have the option to restake their stake and contribute to the security of other infrastructures while earning native ETH rewards.
- Through restaking, EigenLayer pools security instead of fragmenting it.

Goal: Reduce opportunity cost for stakers

When new infrastructure protocols launch, they typically introduce a native token. However, convincing stakers to hold this token is still challenging.

First, the native token's value can fluctuate significantly, making it difficult to persuade stakers to acquire it.

Second, there is competition from other protocols offering higher rewards rates, which makes it necessary for the protocol to provide compelling incentives to attract stakers.

EigenLayer addresses these challenges by allowing stakers to stake any token and earn multiple rewards simultaneously. Since EigenLayer operates on the Ethereum network, we can leverage existing Ethereum primitives to achieve this.

One approach is to enable stakers to provide stake in a liquid staking token (LST). By using LST, stakers can retain their native ETH rewards while securing other infrastructures and potentially earning additional rewards.

What if I do not want to go through a LST provider and instead want to restake my solo validator? We describes in detail how EigenLayer enables this on the bonus section at the end.
βœ… It serves as a platform connecting stakers and infrastructure developers.
βœ… Stakers can offer economic security using any token.
βœ… Stakers have the option to restake their stake and contribute to the security of other infrastructures while earning native ETH rewards.
- Through restaking, EigenLayer pools security instead of fragmenting it.

Goal: Pooling security through restaking

EigenLayer's final goal is to address the issue of fragmented security.

Currently, if an application's security relies on multiple infrastructure dependencies, a single economically compromised dependency can threaten the entire application's security.

This problem becomes worse when the economic security of these dependencies is isolated. These isolated points form economic "honey pots" that attract potential attacks.

Therefore, instead of maintaining several separate economic security pools for different infrastructures, it would be beneficial to consolidate these security measures. Doing so could progressively improve the economic security of all dependencies at once.

In the EigenLayer context, these infrastructure services are referred to as Actively Validated Services (AVS). It's important to differentiate them now, as AVS fundamentally differ from traditional infrastructure projects from the benefits provided by EigenLayer.

Implementing pooled security

Given the model we currently have, how can we incorporate pooled security into it?

As it is, each TokenPool has its own unique slashing condition embedded within the contract. This implies that for each AVS, a separate TokenPool contract needs to be coded. If a staker wishes to participate in two AVSs simultaneously, they would need a new TokenPool. This new pool must incorporate the slash functions from both AVSs.

If two slashing conditions can simultanesouly slash a staker, the staker is making two credible commitments at the same time.

A more efficient approach would allow the staker to participate in different AVSs without the need to create new TokenPool contracts or modify the slash function.

This can be accomplished by relocating the slash function into a different contract, termed the "slasher". Here is how they would interact:

Intermediate EigenLayer design after separating the slashing from the token pools.

The new interface for the TokenPool would look like this. (slash is no longer there.)

contract TokenPool {
    mapping(address => uint256) public balance;
    mapping(address => address[]) public slasher;
    function stake(uint256 amount) public;
    function withdraw() public;
    function enroll(address slasher) onlyOwner;

We still maintain the stake, withdraw, and balance functions and variables. In addition to these, we've introduced a new function and a new variable. The variable, slasher, monitors each staker's currently enrolled AVSs. The function, enroll, allows a staker to participate in AVSs

Enrolling into an AVS therefore is giving a slasher the ability to slash your stake.

With this modification, after staking into the TokenPool, a staker can join a specific AVS by calling the enroll function. This function will incorporate the AVS-specific slasher contract into the slasher mapping.

The enroll function is access controlled here because it could potentially enable anyone to enroll into any slasher contract. To ensure that this TokenPool is managed securely, we will assume that it is overseen by a trusted third-party.

During the withdrawal process, the TokenPool contract can ask each slasher to determine if the staker is eligible to withdraw. This verification is done using the isSlashed function in the slasher contract. If isSlashed for this staker is TRUE, the staker cannot withdraw their stakes as they have been slashed.

contract slasher {
    mapping(address => bool) public isSlashed;
    function slash(address staker, ??? proof) public;

The slash function contains the slashing logic for each AVS. While the slashing logic might differ across various AVSs, upon successful execution of the slash function, the function will set the isSlashed variable to true for the questioned staker.

βœ… It serves as a platform connecting stakers and infrastructure developers.
βœ… Stakers can offer economic security using any token.
βœ… Stakers have the option to restake their stake and contribute to the security of other infrastructures while earning native ETH rewards.
βœ… Through restaking, EigenLayer pools security instead of fragmenting it.

With pooled security implemented, we have created the minimum viable EigenLayer! The minimum viable version acts as a platform connecting stakers and AVS developers. Stakers can now stake any token without compromising other rewards, while AVS developers can utilize the shared security pool to safeguard various types of new infrastructure applications.

In the upcoming section, we will improve the minimum viable version to accommodate additional use cases and make EigenLayer future proof.

Goal: Staker doesn't have to operate

In the minimum viable design, stakers can stake tokens for various AVSs. However, some stakers may not have the capability or desire to personally handle the operations that secure the AVS. This is similar to ETH holders who may prefer not to operate their own validators.

Our goal is to distinguish between these two roles. Stakers provide tokens for the economic security of each AVS, while operators are individuals who run software to ensure the operational security of each AVS.

We can make a slight adjustment to the TokenPool contract to include a delegation process. This allows a staker's token balance to be represented by the operator they delegate to. However, if the operator violates the AVS commitment, the staker's tokens will be slashed.

contract TokenPool {
    mapping(address => uint256) public stakerBalance;
    mapping(address => uint256) public operatorBalance;
    mapping(address => address) public delegation;
    mapping(address => address[]) public slasher;
    function stake(uint256 amount) public;
    function withdraw() public;
    function delegateTo(address operator) public;
    function enroll(address slasher) operatorOnly;
    function exit(address slasher) operatorOnly;

We've divided the balance variable into two distinct parts: one for the operator and one for the staker. Additionally, we've introduced a delegation mapping to record the delegation relationships between stakers and operators.

We've also made a minor modification to the slasher mapping. Now, it gives the slasher contract the authority to slash the operators instead of the stakers.

contract slasher {
    mapping(address => bool) public isSlashed;
    function slash(address operator, ??? proof) public;

In terms of functions, we've incorporated delegateTo, enabling stakers to delegate their tokens to operators. The enroll function has been redesigned to be operator-specific, allowing the operator to enroll in different AVSs, rather than the stakers.

During the withdraw process, the contract initially identifies the operator to whom the staker is delegated. It then checks each slasher contract linked to that operator address. If any slasher reports that the operator is slashed, the withdrawal process is immediately halted.

Maintaining staker autonomy

If the operator is the only one who can opt into AVSs, how can stakers decide which AVSs they want their stake to secure? When a staker is also an operator and self-delegates their stake, they maintain full control over the AVS they operate. But what if a staker can't run it on their own and requires another operator to manage these services? Doesn't this give the operator total control over AVS selection?

We can allow the staker to select the AVS through a simple workaround. The operator can maintain different addresses for various AVS combinations. Each address represents a potential combination of AVSs supported by the operator.

For instance, if an operator supports two AVSs, they can have three addresses: one for AVS 1, another for AVS 2, and a third for running both.

If a staker trusts the operator and only wants to secure AVS 1, they can delegate to the appropriate operator's address.

Through this method, we enable stakers to fully control their stake. At the same time, they can delegate off-chain responsibilities to operators.

Modularizing the operator

The TokenPool contract is quite bulky right now. We will take the operator-specific functions from the TokenPool and put it into a separate contract, DelegationManager.

Now, the TokenPool contract would look like the following:

contract TokenPool {
    mapping(address => uint256) public stakerBalance;
    function stake(uint256 amount) public;
    function withdraw() public;

The TokenPool contract will only track the balance of each staker. The tracking of AVS and enrolling will be handled by the DelegationManager.

contract DelegationManager {
    mapping(address => uint256) public operatorBalance;
    mapping(address => address) public delegation;
    mapping(address => address[]) public slasher;
    function delegateTo(address operator) public;
    function enroll(address slasher) operatorOnly;
    function exit(address slasher) operatorOnly;

Lastly, the slasher contract remains unchanged. It tracks which operator is slashed at the current time for each AVS.

contract slasher {
    mapping (address => bool) isSlashed;
    function slash(address operator, ??? proof);


After cleaning the contract structure and modularizing each component, the architecture would now look like this:

Intermediate EigenLayer design after separating the operator role from the staker role.

Goal: Support more tokens

The design we've developed so far only supports staking one token because we only maintain one mapping for stakers.

We can address this by adopting a LP-share based model of accounting and creating token-specific TokenPool.

To do this, we will create a new contract called TokenManager. TokenManager will be the place where stakers stake and withdraw their tokens.

Underneath the TokenManager, each token will have a TokenPool. The TokenManager will act as the accounting hub for all tokens; it will not store any tokens itself. Each TokenPool will hold its own corresponding tokens.

New component of the design which can now track different tokens from the stakers.

When a user stakes a token, it is processed by the TokenManager. The TokenManager then invokes the stake function of the relevant TokenPool associated with that token. The user's tokens are transferred to the TokenPool. By the end of the function, totalShares and stakerPoolShares are updated to reflect the new stake. totalShares keeps track of the total number of shares issued by the TokenPool, while stakerPoolShares records the number of shares held by each individual staker in each TokenPool.

The interface for each contract would look like this.

contract TokenManager {
    mapping(address => address) tokenPoolRegistry;
    mapping(address => mapping(address => uint256)) stakerPoolShares;
    function stakeToPool(address pool, uint256 amount);
    function withdrawFromPool(address pool);
contract TokenPool {
    uint256 public totalShares;
    function stake(uint256 amount) TokenManagerOnly;
    function withdraw(uint256 shares) TokenManagerOnly;

A minor change will be made to the DelegationManager as well to reflect this change. Instead of tracking a simple mapping of each operator's balance, the DelegationManager will track how much shares does the operator have for each TokenPool, similar to TokenManager.

contract DelegationManager {
    // ...
    mapping(address => mapping(address => uint256)) operatorPoolShares;
    // ...

Now, under the same core architecture, stakers can stake any token into EigenLayer to secure other AVSs.

Goal: Expand AVS designs

Consider the following situation: a staker withdraws their stakes right after engaging in slashable behavior, but before others can slash their assets.

For example, let's say there's an operator who is also a staker, and they act maliciously in an AVS. Before anyone else can slash onchain, the operator withdraws their stake from the EigenLayer contracts. This is possible because, at the time of withdrawal, the slasher has not yet been updated to slash their assets. Consequently, the AVS can no longer slash the malicious operator/staker since there are no more tokens to slash with.

A potential timeline of event for a malicious operator/staker.

Therefore, an AVS that is "safe" would need a slashing contract capable of freezing malicious operators in the same block where the incident occurred. This limitation greatly restricts AVS designs, rendering most of them unsafe.

One solution is to incorporate an unbonding period. Instead of enabling stakers to instantly withdraw their stake, we introduce a delay in the withdrawal process known as the unbonding period. After which, the staker can withdraw like before.

When a staker decides to withdraw from the system, their request is placed in a queue. This queued withdrawal is only processed after the operator's longest unbonding period has expired. This is because an operator may manage multiple AVSs, but a staker's withdrawal can only align with one unbonding period. For security reasons, the system sets the unbonding period to the longest one.

For example, if a staker delegates their stake to an operator participating in three AVSs with unbonding periods of six, five, and seven days, they must wait seven days after requesting a withdrawal from EigenLayer to access their stakes. This is because seven days is the longest of the three periods.

After the seven-day period concludes, the staker can withdraw their stakes. However, if the operator to whom they delegated becomes slashed during this time, the pending withdrawal will be stopped as well.

To incorporate this change, the DelegationManager would need to track this unbonding period for each operator and update it whenever the operator enrolls into a new AVS.

contract DelegationManager {
    // ...
    mapping(address => uint256) public unbondingPeriod;
    // ...

After tracking the unbonding period for each operator, we will also incorporate this value into the staker withdraw process. The withdraw process consists of two steps:

  1. Stakers queue a withdrawal.
  2. After the unbonding period has passed, the staker can complete their withdrawal.

The updated interface would look like the following

contract TokenManager {
    mapping(address => address) public tokenPoolRegistry;
    mapping(address => mapping(address => uint256)) public stakerPoolShares;
    mapping(address => uint256) public withdrawalCompleteTime;
    function stakeToPool(address pool, uint256 amount) public;
    function queueWithdrawal(address pool) public;
    function completeWithdrawal(address pool) public;

When a staker queues a withdrawal, the TokenManager will verify with DelegationManager whether the staker's delegated operator is slashed. If the operator is not slashed, the TokenManager will update the staker's withdrawalCompleteTime according to the unbondingPeriod from the DelegationManager and the current time.

After the unbonding period, the staker can finalize its withdrawal through completeWithdrawal. The function will verify if the withdrawalCompleteTime has passed. If it has, the staker's token will be transferred out following the same process as before.

The design of this process is complex and has undergone several iterations in our pipeline. We could even write a separate article on this topic! At present, we use a time-tracking system to achieve this unbonding tracking. This part is still a work in progress!

Modularize the slashers

Since we are making the slashing mechanism safe, let's also try to make it more modular and efficient.

Currently, during the withdrawal process, TokenManager would need to check with each individual slasher to see if the operator is slashed. This adds gas overhead to stakers and could significantly lower the rewards for smaller stakers.

Moreover, as AVS developers typically design slashers, modularizing this particular component could simplify the development process for individual AVSs.

Like the TokenManager, we will utilize a two-part design for the slashing mechanism. SlasherManager maintains the status of each operator. Individual slasher will handle the slashing logic for each AVS.

Modularize the slashing contract even more to reduce staker gas cost.
contract SlasherManager {
    mapping(address => bool) public isSlashed;
    mapping(address => mapping(address => bool)) public canSlash;
    function enrollAVS(address slasher) operatorOnly;
    function exitAVS(address slasher) operatorOnly;

The SlasherManager allows an operator to enroll in an AVS by adding the AVS slasher contract as one of the slashers capable of slashing the operator. This permission of "who can slash who" is tracked by the canSlash variable.

contract slasher {
    function slash(address operator, ??? proof) public;

The slasher will be AVS-specific and most-likely be developed by the AVS developers. It will interact with the SlasherManager to update the status of different operators.

We've Invented EigenLayer!

To recap: EigenLayer aims to simplify infrastructure building. We started with four main goals:

  1. Connect stakers and infrastructure developers through a platform.
  2. Allow stakers to provide economic security using any token.
  3. Enable stakers to restake their stake and earn native ETH rewards while contributing to the security of other infrastructures.
  4. Pool security through restaking instead of fragmenting it.

After several iterations, we developed three core components: TokenManager, DelegationManager, and SlasherManager. Each component has a specific function:

Simplified architecture of EigenLayer
  • TokenManager: Handles staking and withdrawals for stakers.
  • DelegationManager: Allows operators to register and track operator shares.
  • SlasherManager: Provides AVS developers with the interface to determine the slashing logic.

These core components also communicate with each other to ensure the safety of the entire system.

In addition to these core contracts, there are many other functions and contracts that enhance the entire stack. These additional functionalities support various AVS designs, simplify offchain technical complexity, and reduce gas fees for users and operators.

To learn more about these other functions, you can visit our public repository at:

If you have any question on the EigenLayer core contracts, drop some comments at πŸ˜‰

Bonus 1: Who's trusting who?

When a system is modular, it can be challenging to track the trust assumptions within the protocol. Therefore, it is essential to explicitly outline the trust assumptions among the participants involved in the protocol.

In EigenLayer, there are three main agents: stakers, operators, and AVS developers.

The operator is relying on the AVS developer to accurately code the client software and the onchain slashing condition. If there are bugs in the AVS softwares, at best, the operator might miss potential fee payments. At worst, the operator could be slashed for all their stakes.

Given the significant amount of value at stake, it is important to ensure that the entire system has training wheels before it is put to the test.

The veto committee serves as these training wheels. It has the power to reverse slashing resulted from non-malicious behaviors. The veto committee is a mutually trusted party among the stakers, operators, and AVS developers.

This way, the trust assumptions placed on the AVS developers can be removed. Even if there's a software bug inside the AVS, the staker and operator won't be penalized.

The staker is trusting the operator they are delegating to. If the operator misbehaves, the staker could miss out on potential fee payments or even lose their entire stake. This trust assumption is the same for existing validating services such as Binance Staking and other staking services.

The AVS developers rely on the operators to act honestly. If the operators don't, the AVS service will degrade significantly, leading to customer loss and other consequences.

With the veto committee, among the participants, the trust assumptions are the following:

  • Stakers trust operators to behave honestly, and misbehavior could lead to slashing.
  • AVS developers trust operators to operate the AVS software honestly.
  • Stakers, operators and AVS developers trust the veto committee for reversing slashing.

Bonus 2: Native Restaking

So far, we've discussed staking LST for restaking. But what if you don't want to stake into EigenLayer through a liquid staking protocol? You can start participate in EigenLayer through native restaking.

Let's define native restaking: it is the process of using ETH within a validator for additional commitments. If the validator deviates from the commitment, they will lose the ETH held within their validator.

The challenge here is that the ETH inside these validators is not represented as ERC20 tokens. Instead, the ETH exists on the beacon chain. If you're not familiar with the execution layer or the consensus layer (beacon chain), this explainer is a great resource to get you up to speed.

To solve this issue, we can use EigenPod to track Ethereum validator balances and slash them if necessary.

EigenPod functions as a virtual accounting system. With EigenPod, we can monitor the ETH balance for each restaked validator.

At a high level, EigenPods handle the withdrawal process for validators. When a validator withdraws their stakes from EigenLayer, the ETH first passes through EigenPod to check if the validator has been slashed. If the validator has been slashed, the tokens will be frozen within the EigenPod contract, effectively slashing them.

Implementing EigenPod

Implementing EigenPod is tricky because Ethereum validator balances are stored on the beacon chain and we cannot access the beacon chain data on the execution layer.

To overcome this issue, we utilize an oracle to relay the beacon chain state root to the execution layer. By obtaining the beacon state root, we can access validator balances by providing the corresponding merkle proof.

With EIP-4788 live, we can remove this oracle and query the beacon root directly from the execution layer.

To encapsulate the accounting system, we will incorporate a model similar to the TokenPool and TokenManager model, to modularize the native restaking system. Each EigenPod will handle the withdrawal process for one validator. The EigenPodManager will coordinate with other core contracts to track the amount of ETH restaked for each operator and staker.

contract EigenPodManager{
    mapping(address => uint256) public restakerShares;
    function createEigenPod(address owner) public;
    function stakeToPod(address pod, uint256 amount) public;
    function withdrawFromPod(address pod) public;    
contract EigenPod{
    address podOwner;
    uint256 restakedAmount;
    function stake(uint256 amount) public;
    function verifyRestakedBalance(uint256 amount, MerkleProof proof) public;
    function withdraw() public; 

The EigenPodManager tracks how many shares each staker has. It allows stakers to create EigenPod, stake into it, and withdraw from it.

EigenPod tracks individual validator balances on the beacon chain through the restakedBalance variable. Whenever a balance changes for any restaked validator, anyone can update the balance for this specific validator by calling the verifyRestakedBalance() function. The function will check if the updated balance is correct through the beacon state root, which we retrieved from the BEACON_CHAIN_ORACLE.

And that is how EigenLayer allows native restaking.