[ARFC] Onboard ezETH to Aave V3 Lido Instance

[ARFC] Onboard ezETH to Aave V3 Lido Instance

Author: Renzo Protocol & ACI (Aave Chan Initiative)

Date: 2024-08-02


ARFC has been updated to bundle [ARFC] Chaos Labs Risk Parameter Updates - Increase Borrow caps for wstETH on the Lido Market - 10/20/24 and update mode parameters for more efficiency 2024-10-22

ARFC has been updated with Risk Parameters provided by Risk Service Providers 2024-08-12.

ARFC has been updated again with Risk Parameters provided by Risk Service Providers 2024-10-15

Summary

This is an ARFC to continue to gauge community sentiment for adding borrow/lend support for Renzo Protocol and its Liquid Restaking Token (LRT) ezETH on AAVE V3 Ethereum, after the successful TEMP CHECK.

To align best with goals of all relevant stakeholders, this proposal suggests onboarding ezETH to Lido’s Aave v3 instance.

Motivation

As productive assets, staking tokens are high quality collateral to borrow against. ezETH is one of the largest liquid restaking tokens. With withdraw feature now enabled and the peg holding steady over the near term, we believe it is time to consider adding ezETH as a collateral asset.

The onboarding of ezETH will consequently create increased ezETH demand and increased revenues for both Aave and Renzo Protocol, whilst also bolstering the liquidity and peg stability of ezETH.

Adding ezETH to the Lido Aave v3 instance brings additional synergies for all stakeholders.

ezETH will add additional demand for wstETH borrowing, making the wstETH looping more favorable for the main users. Incentives from Renzo can bring additional ETH liquidity to the Lido instance, bolstering the existing liquidity mining campaigns.

To allow these synergies to operate, wstETH borrow cap is proposed to be raised at 14000 and wstETH is removed as a borrowable asset in wstETH/wETH emode category to avoid wstETH/wstETH undesired looping.

Chain to be deployed/listed

Aave v3 Lido instance on Ethereum

Proof of Liquidity and Deposit Commitments

Renzo will be providing 3X points multiplier for ezETH deposits, which will be the highest points multiplier available for comparable protocols.

Specification

ezETH: 0xbf5495Efe5DB9ce00f80364C8B423567e58d2110

Risk Parameters:

Initial Risk Parameters haven been provided by Risk service providers during the ARFC phase and ARFC has been updated 2024-10-15

This Emode is updated to remove borrowable status of wstETH

E-mode Category 0: wstETH / wETH

Parameter Value Value
Asset wstETH wETH
Collateral Yes No
Borrowable No Yes
Max LTV 93% 93%
Liquidation Threshold 95% 95%
Liquidation Penalty 1.00% 1.00%

E-mode Category 1: ezETH / USDS

Parameter Value Value
Asset ezETH USDS
Collateral Yes No
Borrowable No Yes
Max LTV 75% 75%
Liquidation Threshold 78% 78%
Liquidation Penalty 7.50% 7.50%

E-mode Category 2: ezETH / wstETH

Parameter Value Value
Asset ezETH wstETH
Collateral Yes No
Borrowable No Yes
Max LTV 93% 93%
Liquidation Threshold 95% 95%
Liquidation Penalty 1.00% 1.00%

ezETH Risk Parameters (Non E-mode)

Parameter Value
Asset ezETH
Isolation Mode No
Borrowable No
Collateral Enabled Yes
Supply Cap 15,000
Borrow Cap -
Debt Ceiling -
LTV 0.05%
LT 0.10%
Liquidation Penalty 7.5%
Liquidation Protocol Fee 10.00%
Variable Base -
Variable Slope1 -
Variable Slope2 -
Uoptimal -
Reserve Factor -
Stable Borrowing Disabled
Flashloanable Yes
Siloed Borrowing No
Borrowable in Isolation No
E-Mode Category 1 ezETH / USDS
E-Mode Category 2 ezETH / wstETH
Chain Asset Current Supply Cap Recommended Supply Cap Current Borrow Cap Recommended Borrow Cap
Ethereum Lido instance wstETH 650,000 - 100 14,000

E-mode Category 0: wstETH / wETH

Parameter Value Value
Asset wstETH wETH
Collateral Yes No
Borrowable No Yes
Max LTV 93% 93%
Liquidation Threshold 95% 95%
Liquidation Penalty 1.00% 1.00%

CAPO

We recommend a maxYearlyRatioGrowthPercent of 7.39% for ezETH, with a MINIMUM_SNAPSHOT_DELAY of 7 days. This recommendation is based on the frequent occurrence of rate distributions and relatively minimal rate variance observed over time.

maxYearlyRatioGrowthPercent ratioReferenceTime MINIMUM_SNAPSHOT_DELAY
7.39% monthly 7 days

Useful Links

Renzo Protocol

Documentation

Github

Audits

Chainlink Data Feed

Composable Stable Pool

TEMP CHECK

TEMP CHECK Snapshot

Disclaimer

This proposal is powered by Skywards. The Aave Chan Initiative is not directly affiliated with Renzo Protocol and did not receive compensation for creation this proposal.

Next Steps

  1. Publication of a standard ARFC, collect community & service providers feedback before escalating proposal to ARFC snapshot stage.
  2. If the ARFC snapshot outcome is YAE, publish an AIP vote for final confirmation and enforcement of the proposal.

Copyright

Copyright and related rights waived under CC0.

3 Likes

Summary

LlamaRisk expressed reservations regarding integrating ezETH as collateral in the Aave V3 Lido Instance. This position aligns with the Lido market’s objectives, initially understood as risk isolation, enabling more aggressive looping parameters.

The Liquid Restaking Token (LRT) ecosystem, including ezETH, presents a significantly higher risk profile than wstETH. This proposal may deviate from the goal of risk isolation, and depositors should be aware of the additional risks associated with LRTs like ezETH. The absence of EigenLayer slashing mechanisms has led to LRT protocols onboarding numerous Actively Validated Services (AVSs) without immediate repercussions. However, the potential implementation of slashing protocols necessitates a comprehensive re-evaluation of LRT use cases as collateral.

Notwithstanding these concerns, a viable path exists for the safe integration of ezETH, either within the main or Lido instance. It’s worth highlighting that Renzo ezETH has made significant progress since our last report, namely enabling withdrawals and on-chain governance processes — although governance remains centralized.

Collateral Risk Assessment

1. Asset Fundamental Characteristics

1.1 Asset

ezETH is an ERC20 repricing token that maintains a soft peg to ETH, with its exchange rate against ETH incrementally appreciating as rewards accumulate. It is collateralized by a portfolio of staked Ethereum and select Liquid Staking Derivatives (LSDs), specifically WBETH and stETH. The yield is derived from two primary sources: the native Ethereum staking rewards and the re-staking incentives provided by secured Active Validator Sets (AVSs) through the EigenLayer protocol. Renzo imposes a 10% fee on all accrued rewards.

Despite mentioning plans to expand LSD coverage in our first report, Renzo currently accepts only WBETH and stETH as supported Liquid Staking Derivatives, which remain the only accepted options. The minting mechanism is based on ezETH’s book value and underlying re-staked collaterals. The ezETH exchange rate is calculated using the ETH-equivalent value of assets involved, the total ETH value in the protocol, and ezETH’s circulating supply. For LSDs, using their protocols’ internal exchange rates rather than market rates provides more stability to the ezETH/ETH exchange rate, reducing risks of depegs and liquidations.

On-chain analysis shows that value locked is predominantly in WETH, with only marginal amounts of wBETH and stETH. Only stETH deposits are limited to 50k and currently standing at 6.3k as of August 8th, 2024.

1.2 Architecture

Overview

The deposit and exchange process mechanics vary slightly depending on whether a native ETH or an LSD is deposited. Native ETH deposits must first be staked by spinning up validators through select node operators before re-staking into EigenLayer, whereas LSD deposits can be directly re-staked. The deposit of stETH is limited to 50k and is currently filled up to 5.9k, whereas WBETH and ETH deposits are uncapped. The Renzo Protocol also provides a cross-chain feature, enabling the restaking of native ETH from partnered chains through Chainlink’s Cross-Chain Interoperability Protocol (CCIP), which broadens the utility and accessibility of ezETH.

image
Source: docs.renzoprotocol.com/docs

Enabled withdrawals

Users can now redeem their ezETH for ETH, WBETH, and stETH thanks to withdrawal buffers that are replenished hourly through staking rewards, unstaked assets, and new deposits. As of Monday, February 5, 2024, there are 190 WBETH and close to 0 stETH in the contract’s buffer.

It is important to note that no LSD withdrawals are possible if the buffers are empty and that queued withdrawals are only available for native ETH. Queued withdrawals work on a first-come, first-served basis (FIFO), meaning that the unstaked assets will be allocated to the earliest withdrawal requests and then the subsequent ones. Furthermore, queued (ETH) withdrawals have priority over the buffer replenishing process, meaning that unstaked assets will first be allocated to ongoing withdrawal requests and then replenish the buffers.

In addition to the time needed for LSD buffer replenishment or ETH unstaking from Ethereum consensus and EigenLayer or Symbiotic, all withdrawals are subject to a 3-day cooldown period, regardless of the underlying asset. This waiting period, set to increase to 7 days once EigenLayer enables slashing, allows the Renzo protocol to detect potential issues and prevent front-runners from taking advantage of unfair ezETH exchange rates during slashing events. The ezETH exchange rate is calculated twice: at withdrawal initiation and finalization, with the lower rate applied. While these added delays may impact ezETH peg stability by slowing arbitrage opportunities, we consider them a necessary precaution.

1.3 Tokenomics

REZ token statistics as of August 7, 2024:

  • 10,000,000,000 total supply
  • 1,150,000,000 circulating supply
  • $39.7m market cap

Renzo introduced the REZ governance token on April 30, 2024, through the first TGE event called Season1, where 7% of the total supply was distributed linearly to ezPoint holders. REZ can be staked for additional rewards, but it is not necessary to vote on governance proposals. However, it can be delegated to others. The allocation of REZ to large holders such as investors and core contributors is subject to various vesting schedules, ensuring the long-term participation of key stakeholders.

According to the documentation, this governance token will vote on various aspects of the protocol, including risk management, collateral assets, whitelisted operators and AVSs, and treasury allocation. For now, no proposals discussed in the forum have been escalated to a vote on Snapshot, as the only topics on the forum are REZ delegate pitches and a single proposal for strengthening community engagement and rewards.

2. Market Risk

2.1 Liquidity

As of August 6, 2024, Renzo ezETH is supported on many DEXs, including but not limited to:

Paraswap, a DeFi aggregator, indicates that 2,124 ezETH ($5.5m as of August 9, 2024) can be liquidated within a 7.5% price impact. It’s important to note that this measure follows the Yen carry trade unwind on August 5, 2024, significantly reducing available liquidity on secondary markets. These abnormal conditions may not be representative of typical market circumstances.

image
Source: Paraswap (August 9th, 2024)

2.2 Volatility

Since our first report on May 24, 2024, Renzo protocol has implemented a withdrawal feature for native ETH and the supported LSDs WBETH and stETH. Consequently, the ezETH peg to its theoretical book value has significantly improved, reaching a value slightly below the expected one.

A significant event that affected the ezETH peg in the past was the disclosure of the REZ tokenomics, which at the time caused a lot of disappointment from token holders and led to them exiting their position on secondary markets. Because withdrawals were not enabled at the time, this caused a significant depeg of ezETH which reached up to -78% on some trading venues.

Source: Dune query forked from @Henrystats

Like other LSD/LRT, ezETH depegged to the downside following the unwinding of the Yen carry trade on Monday, August 5, 2024. This was due to market-wide liquidations that took place on-chain, which consumed all available liquidity on DEXs. This depeg is expected to correct itself as on-chain liquidity replenishes.

2.3 Growth

After reaching a plateau at around 1.1m ETH-equivalent on April 24th, 2024, the TVL then started to decrease following the activation of withdrawals in mid-June 2024, and seems to have now stabilized at around 550k ETH-equivalent. We can also see that the TVL of pzETH, an LRT that is based on Symbiotic, has been picking up since the end of June 2024. Renzo ezETH remains the second-largest LRT by TVL, behind EtherFi weETH.

Source: Dune, August 8th, 2024

3. Technological Risk

3.1 Smart Contract Risk

At the time of our first report, Renzo only provided a single audit from Halborn (November 29, 2023). Three additional audits have been performed since then:

  • Halborn (May 22, 2024) specifically for the withdrawal feature: 3 critical issues, two high issues, one medium issue.
  • Halborn (April 24, 2024) specifically for the REZ staking feature: 1 informational finding.
  • SigmaPrime (June 2024): 1 critical issue, five high issues, and three medium issues. All were either fixed or dismissed.

All findings were addressed through justification or remediation. The SigmaPrime audit revealed critical issues potentially risking significant user funds. Given the protocol’s >$1b TVL, earlier detection of these issues through more frequent audits during initial deployment would have been prudent. Notably, these recent audits now cover the cross-chain interoperability feature, addressing a gap identified in our previous report.

The Renzo Protocol has also been running a bug bounty with Immunefi since December 14, 2023, with a maximum bounty of $250,000. This maximum amount is much lower than the recommended 10% of the TVL. Notably, the bounty does not cover the cross-chain interoperability contract xRenzoDeposit. More details can be found at Immunefi.com.

3.2 Price Feed Risk

ezETH utilizes a Chainlink oracle, available on multiple L2 networks. The oracle is configured with a 0.5% deviation threshold and a 24-hour heartbeat. The system employs 16 oracles, with each price aggregation requiring responses from at least 11 of them.

3.3 Dependency Risk

ezETH, like other Liquid Restaking Tokens (LRTs), integrates with EigenLayer to secure Active Validator Sets (AVSs) and generate additional yield for token holders. While EigenLayer’s smart contract risk is inherent, Renzo claims to select node operators and AVSs carefully. Renzo aims to secure numerous AVSs, as EigenLayer’s slashing and reward mechanisms are not yet operational. However, once activated, a thorough reassessment of secured AVSs will be crucial to ensure well-defined slashing conditions that align with the protocol’s risk profile and maintain a positive risk-adjusted yield for token holders.

Renzo Protocol uses Connext Network and Chainlink’s CCIP for native cross-chain restaking on supported L2s and alternative L1s. Users can obtain xezETH without migrating funds to L1. While this introduces limited risks to the core L1 system, xezETH minters face potential slippage due to ezETH price reporting via CCIP and bridge-related inflation attacks. Notably, the xRenzoDeposit contract allows both CCIP and the contract owner to update the ezETH price, the latter through the updatePriceByOwner function.

Renzo previously relied on a Chainlink oracle for stETH and a centralized oracle operated by Binance for WBETH. The Binance-operated oracle presented a significant centralization risk, potentially exposing the protocol to exploitation. It’s important to note that the WBETH oracle has not been updated since our initial report. Consequently, ezETH remains vulnerable to the price manipulation attack that we previously demonstrated.

4. Counterparty Risk

4.1 Governance and Regulatory Risk

Although the REZ governance token’s distribution has started, its governance utility remains limited. Renzo’s governance forum currently only contains delegate pitches and a single governance proposal that has not been escalated to a snapshot.org vote yet. According to the current snapshot.org parameters for the Renzo space, the execution of proposals is off-chain for now, meaning that the team remains the ultimate arbiter regarding the protocol’s governance. Therefore, Renzo ezETH remains centralized.

4.2 Access Control Risk

We identified several important wallets:

Contract upgrades are controlled by Timelock A with a 3-day delay with the following role assignment:

Renzo protocol also uses a role-based access control system comprised of the following roles and assignations:

Although numerous roles were created, most of them are assigned to Multisig A. Ideally, roles should be split according to privilege levels and assigned to different multisig wallets with gradually increasing security requirements (threshold and eventually timelock).

We also note that the DEFAULT_ADMIN_ROLE role is still assigned to Multisig A without a Timelock, meaning that the multisig could change the assignment of roles instantly. Notably, the RX_ETH_MINTER_BURNER role could be assigned to another wallet which would be able to mint ezETH and extract the collaterals from the protocol at the expense of Renzo’s users.

Note: This assessment follows the LLR-Aave Framework, a comprehensive methodology for asset onboarding and parameterization in Aave V3. This framework is continuously updated and available here.

3 Likes

Overview

Chaos Labs supports listing ezETH on Aave V3 Ethereum — Lido as part of the community’s strategy to increase the LST/LRT offerings supported by Aave. Below is our analysis and initial risk parameter recommendations.

Note: The following analysis is conducted solely from a market risk viewpoint, excluding centralization and third-party risk considerations. If the community aims to reduce exposure to ezETH, adopting more conservative parameters should be considered.

Liquidity and Market Cap

Currently, ezETH has a TVL of 500K ETH, down from a high of 1M ETH when withdrawals were opened in mid-June. Since launch, it has a daily trading volume of $83.4M.

Untitled (73)

ezETH / ETH Volatility

Relative to ETH, ezETH has a daily annualized volatility of 7.03% over the last 180 days and 2.16% over the last 30 days. Its maximum price drop relative to ETH was 2.79% over the former time frame.

LTV, Liquidation Threshold, and Liquidation Bonus

Considering ezETH’s volatility and correlation to ETH, we recommend setting the LTV to 72% and the LT to 75%.

Untitled (74)

Given ezETH’s liquidity, volatility, and historical depegs, we recommend a liquidation penalty of 7.5%, ensuring that liquidating non-WETH ezETH-collateralized positions are profitable to liquidate even in times of stress.

E-mode

We recommend including ezETH in the ETH-correlated E-mode category.

Supply Cap, Borrow Cap, and Liquidation Bonus

Following Chaos Labs’ approach to initial supply caps, we propose setting the Supply Cap at 2x the liquidity available under the Liquidation Penalty price impact.

Thus, we recommend a supply cap of 7,000 ezETH. While circulating supply has fallen, it would have to fall to 9.5K to break the community-voted rule of not setting supply caps over 75% of an asset’s on-chain supply. Additionally, we find it likely that there will be an element of induced demand, wherein users are more likely to hold the asset following its availability on Aave.

Given limited historical demand for similar ETH-derivative assets — weETH excluded given incentives that encourage borrowing — we recommend setting the borrow cap at 10% of the supply cap.

Pricing ezETH

Native withdrawals of ezETH have been open for a sufficient time, and it has shown to mean revert rapidly enough to recommend pricing ezETH using a calculated oracle based on its exchange rate. For example, during the August 4 price decline, ezETH fell to 0.86 WETH on its most liquid pair on Ethereum. However, by the next block, its price had risen to 0.99 WETH; 30 minutes later, it had reverted to a 44bps discount. Ultimately, this proved to be an outlier, as its market oracle reached a low of only 0.992 ETH.

Untitled (76)

Pool Selection

We find limited additional risk posed by allowing ezETH to be listed on the core Aave V3 Ethereum instance. Additionally, this may be preferable, given that 7 of the 10 largest WETH suppliers on the core instance are borrowing against their WETH. As mentioned in our previous response to the Lido instance, attracting WETH supply while limiting its borrowable assets and borrowing power will likely require WETH supply incentives in perpetuity unless the composition of available assets and WETH’s borrowing power changes. However, should the community be comfortable with this paradigm, we note that the Lido instance does carry slightly more lenient parameters in E-Mode, allowing for higher leverage looping. We note that our parameter recommendations below apply for listing the asset in either the Lido instance or the core instance, with the exception of its E-Mode parameters, which will be aligned according to the instance: 93.5% LTV and 95.5% LT on Lido; 93% LTV and 95% LT on core.

Recommendations

Following the above analysis, we recommend the following parameter settings:

Parameter Value
Isolation Mode No
Borrowable Yes
Collateral Enabled Yes
Supply Cap 7,000
Borrow Cap 700
Debt Ceiling -
LTV 72%
LT 75%
Liquidation Penalty 7.5%
Liquidation Protocol Fee 10.00%
Variable Base 0.0%
Variable Slope1 7.00%
Variable Slope2 300.00%
Uoptimal 45.00%
Reserve Factor 15.00%
Stable Borrowing Disabled
Flashloanable Yes
Siloed Borrowing No
Borrowable in Isolation No
E-Mode Category ETH-correlated

CAPO

We recommend a maxYearlyRatioGrowthPercent of 7.39% for ezETH, with a MINIMUM_SNAPSHOT_DELAY of 7 days. This recommendation is based on the frequent occurrence of rate distributions and relatively minimal rate variance observed over time, as seen in the plot below.

Untitled (77)

maxYearlyRatioGrowthPercent ratioReferenceTime MINIMUM_SNAPSHOT_DELAY
7.39% monthly 7 days
1 Like

After Risk Service Providers feedback, that has been updated in ARFC, the current proposal has been escalated to ARFC Snapshot.

Vote will start tomorrow

1 Like

In parallel to ARFC Snapshot being opened for vote, an extra analysis from BGD Labs will be provided, in order to be aligned with Onboarding ezETH to Aave V3 Lido Instance.

After Snapshot monitoring, the current ARFC Snapshot ended recently, reaching both Quorum and YAE as winning option with 910K votes.

Therefore, the ARFC to Onboard ezETH to Aave V3 Lido Instance has passed.

Nevertheless, as stated in previous comment, an extra analysis from BGD Labs will be provided, before moving the proposal forward.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.

ezETH (Renzo) technical analysis


Summary

This is a technical analysis of all the smart contracts of the ezETH token and its main dependencies.

Disclosure: This is not an exhaustive security review of the asset like the ones done by the Renzo team, but an analysis from an Aave technical service provider on different aspects we consider critical to review before a new type of listing. Consequently, like with any security review, this is not an absolute statement that the asset is flawless, only that, in our opinion, we don’t see significant problems with its integration with Aave, apart from different trust points.



Analysis

ezETH is an LRT reward-bearing token, exchange-rate based, where users can deposit native ETH and LSTs (currently stETH) in exchange for ezETH.

ezETH-architecture


ezETH’s surrounding system handles operations that enable users to deposit their ETH and LSTs. These assets are then staked into the EigenLayer ecosystem, and used to earn rewards from staking and restaking.
In return, users receive ezETH tokens representing their share of staked assets and rewards, that can later on be redeemed by requesting a withdrawal, waiting for the unstake period, and doing a claim.

For the context of this analysis, our focus has been on the following aspects, critical for the correct and secure integration with Aave:

  • Mechanism to update the exchange rate of the asset for the underlying ETH.
  • Access control (ownerships, admin roles) and nature of the entities involved.
  • Any miscellaneous aspect of the code we can consider of importance.

General points

  • The upgradeability admin of all systems is an OZ Timelock, which has a 3-day time lock and is controlled by a 3-of-5 Gnosis Safe.
  • The system’s default admin role is held by the Timelock.
  • For proxies, it uses an OZ transparent proxy pattern.
  • The system has a proper hierarchical organization of permissions, with the most critical being controlled by the default admin role (given to the Timelock and the 3-of-5 Safe) and others with less power and different protections surrounding them.
  • The current validators are Renzo’s partners Figment and P2P.org, which runs institutional-grade nodes on Ethereum and EigenLayer.

Contracts

The following is a non-exhaustive overview of the main smart contracts involved with ezETH.

ezETH-architecture2


Role Manager

The system’s main access controller, keeping track of all the roles and permissions: each role gives specific permissions to perform crucial actions within the system.

This contract has functions to check if a given address has a specific role, and the system’s contracts use them to ensure an address is allowed to perform certain operations. The Role Manager it’s an OZ Transparent Proxy with the OZ Access Control pattern, and upgradeability by the general Timelock.

  • The DEFAULT_ADMIN_ROLE role, which has permissions to grant and remove all the roles, is held by the Timelock.
  • Currently, the contract contains 13 different roles, most of which are held by the 3-of-5 Gnosis Safe. Each role will have a description in the corresponding contract of the system where it is utilized.
  • In the worst scenario, if the DEFAULT_ADMIN_ROLE is compromised, the system could have serious problems, allowing the controller to change the behavior of the flow of underlying funds.

ezETH

The ezETH token represents participation within the system and allows authorized addresses to mint and burn tokens. It is an ERC20 OZ Transparent Proxy contract with upgradeability by the general Timelock.

  • The mint() and burn() are permissioned functions that can only be called by the owners of the RX_ETH_MINTER_BURNER role. At the present of this analysis, the Restake Manager contract and the Withdraw Queue contract hold this role. The Restake Manager acts as the minter, while the Withdraw Queue acts as the burner.
  • In a scenario where the RX_ETH_MINTER_BURNER role gets compromised, an unlimited number of ezETH tokens can be minted and sent to any address.

Restake Manager

The Restake Manager contract is the main entry point for depositing native ETH and LSTs in exchange for ezETH. This contract serves as the core interaction between users and the staking within the EigenLayer by managing how funds should be allocated across different Operator Delegators. It also manages the basket of LSTs and their limits that can be deposited into the system. The Restake Manager is a Transparent Proxy contract with upgradeability by the general Timelock.

Access control

Deposits and exchange rate:

  • Users can deposit native ETH through the depositETH() function, while LSTs are deposited via the deposit(token, amount) function. The ETH amount is sent to the Deposit Queue Contract to be staked later. For the LST, if there is any withdrawal deficit (the amount to cover withdrawal requests), the deficit is subtracted from the amount and is transferred to the Deposit Queue contract via the fillERC20withdrawBuffer(token, amount) function.
  • For LSTs, it first checks if it is needed to fill any withdrawal deficit buffer and sends it to the Deposit Queue contract via the fillERC20withdrawBuffer(token, amount) function, which is sent to the Withdraw Queue contract afterward. Any remaining amount in the Restake Manager is sent to an Operator Delegator Contract chosen by calling the chooseOperatorDelegatorForDeposit() function and deposit via the operator.deposit(token, amount) function.
  • The exchange rate can be obtained by calling the calculateMintAmount(TVL, amount, totalSupply) function in the Renzo Oracle contract and passing the protocol’s total value deposited, the amount value to be minted, and the total supply of ezETH. The formula utilized is mintAmount = (totalSupply * amount) / TVL.
  • The total value deposited for the protocol (across all Operator Delegators contracts, Deposit Queue, and Withdrawal Queue contracts) is calculated by calling the calculateTVLs() function, which internally calls the Renzo Oracle to obtain the prices of each asset. The Operator Delegators use internal accounting for LSTs to safeguard against potential donations. However, the total supply of ezETH is fetched directly via ezETH.totalSupply(), and the Withdraw Queue fetches its balance by calling lst.balanceOf(withdrawQueue), which may lead to donation of LSTs into the system, manipulating the exchange rate.

Tokens list and Capacity

  • Currently, one LSTs (stETH) can be deposited in the system.
  • The Restake Manager Admin can add new tokens by calling the addCollateralToken(token) function. This function internally checks whether the token is already listed and whether it has 18 decimals before adding it.
  • The Restake Manager Admin can also remove a token from the list by calling the removeCollateralToken() function. Before removing it, ensure that no TVL is left across the contracts in the system.
  • For Native ETH, no cap limits are defined. For LSTs, caps are checked internally in the deposit(token, amount) function.
  • The caps for LSTs are set via the setTokenTvlLimit(token, limit) function, which is called only by the Restake Manager Admin.

Validators and flow of funds

  • When the minimum 32 ETH is reached, the ETH is staked in the Beacon Chain via the stakeEthInOperatorDelegator(delegator) function called by the Deposit Queue contract. The ETH is sent to the chosen Operator Delegator contract, which will stake via the Eigen Pod Manager (Eigen Layer Contract), allowing for both stake and Eigen Layer AVS rewards to be earned.
  • LSTs are deposited via the depositTokenRewardsFromProtocol() function only called by the Deposit Queue contract. Internally, the Restake Manager contract will pick one Operator Delegator contract via the chooseOperatorDelegatorForDeposit() and then deposit it by calling the deposit(token, amount) function.
  • The Restake Manager Admin can add new Operator Delegator contracts via the addOperatorDelegator(operator) function. Before pushing it to the Operators list, it first checks if the operator’s address is not in the system if it has a valid percentage, and if the delegation address is set.
  • The Restake Manager Admin can remove Operator Delegator contracts via the removeOperatorDelegator(operator) function. Before removing it from the Operators list, it checks if the Operator still has the value locked within.
  • The Restake Manager Admin can set the allocation amount for each Operator Delegator by calling the setOperatorDelegatorAllocation() function. Before updating the allocation, it’s checked whether the new allocation percentage is valid and doesn’t exceed the maximum percentage value.

Emergency Pause

  • The Deposit Withdraw Pauser Admin can pause/unpause all deposits into the system by calling the setPaused() function.

Renzo Oracle

The Renzo Oracle contract is responsible for fetching listed asset prices via ChainLink feeds using ETH as the reference. It works by retrieving reliable prices of LSTs used by the Restake Manager to calculate the TVL across all Operator Delegators and the Withdraw Queue contract. It also aids the Restake Manager in calculating the mint amount, and helps the Withdraw Queue in determining the amount to be redeemed.
The Renzo Oracle is a Transparent Proxy with upgradeability by the general Timelock.

  • The Oracle Admin (Safe 3-of-5 0xD1e6…B68A) can add new feeds by calling the setOracleAddress(token, oracle) function. This function only ensures that the token is not an invalid address and that the Oracle address has 18 decimals.
  • Before returning prices, the system checks if the price is greater than zero and the price’s time update window is within 24 hours + 60 seconds (via the MAX_TIME_WINDOW storage variable).
  • The Restake Manager uses the lookupTokenValue(token, balance) function to calculate the total value of each token in the system. This function returns the value in 18 decimals, as Restake Manager only allows tokens with 18 decimals to be included in the assets list.
  • The Restake Manager fetches the mint amount from the calculateMintAmount(TVL, amount, totalSupply) helper function. This function uses the formula mintAmount = (totalSupply * amount) / TVL and reverts if mintAmount = 0.
  • The Withdraw Queue fetches the ETH redeemed amount value from the calculateRedeemAmount(amount, totalSupply, TVL) helper function. This function uses the formula redeemAmountValue = (TVL * amount) / totalSupply and reverts if redeemAmountValue = 0. If the redeemed token is an LST, the Withdraw Queue will call the lookupTokenAmountFromValue(token, redeemAmountValue) function, passing the redeem amount value to obtain the asset amount.

Deposit Queue

The Deposit Queue is the contract designed to manage the flow of assets in the basket, in and out of the system. It acts as the middleman that handles funds deposited via the Restake Manager, manages the withdrawal buffer, and coordinates with the Restake Manager and Operator Delegators for the staking into the Beacon Chain and the Eigen Layer.
The Deposit Queue contract is a Transparent Proxy that can be upgraded by the general Timelock.

  • The Restake Manager Admin can change the Restake Manager and Withdraw Queue contracts by respectfully calling setRestakeManager(address) and setWithdrawQueue(address).
  • The Restake Manager Admin can change the fees earned by the system by calling the setFeeConfig(receiver, fee). It’s defined in basis points and currently is set to 10% in the feeBasisPoints storage variable.
  • The Restake Manager contract sent ETH deposits by calling the depositETHFromProtocol() function. This function checks whether the Withdraw Queue has a deficit, which is subtracted from the amount sent to the Withdraw Queue contract. The remaining amount is kept in the Deposit Queue contract and will be staked later. In the case of an LST, it sends by calling the fillERC20withdrawBuffer(token, amount) function, which redirects the amount to the Withdraw Queue contract.
  • The Operator Delegators contracts sent ETH unstaked by calling the forwardFullWithdrawalETH() function. This function behaves like the depositETHFromProtocol() function explained above. In the case of an LST, the Operator Delegator sends via the fillERC20withdrawBuffer(token, amount) function.
  • The Native ETH Restake Admin (EOA 0x3f77…d4e8, EOA 0x64E9…baE6) initiates the ETH stake in the Beacon Chain by calling the stakeEthFromQueue(operator) function. This function calls the stakeEthInOperatorDelegator(operator) function in the Restake Manager Contract, sending 32 ETH through the call. It can also stake in multiple validators by calling the stakeEthFromQueueMulti(operators) function.
  • This contract also receives rewards from the Execution Layer and MEV from native staking via the receive() function. It internally takes the protocol fee from the amount sent and sends any deficit existing in the Withdraw Queue Contract. Any remaining amount is kept in the Contract and will be staked later. A reentrant guard modifier protects the receive() function.
  • The ERC20 Rewards Admin (currently not set) can deposit any accumulated amount of LSTs in the Deposit Queue Contract to the Restake Manager by calling the sweepERC20(token) function, which will internally call deposit(token, amount) in an Operator Delegator contract to be sent to EigenLayer.

Withdraw Queue

The Withdraw Queue contract serves as the exit point for users to redeem their underlying tokens, operating on a first-come, first-served basis. This contract manages the withdrawal process by queueing users’ requests, ensuring that enough liquidity is available until each user’s turn to claim it after the cooldown period elapses. During the claim process, after all conditions are met, the ezETH is burned and the underlying asset is sent to the user.
The Withdraw Queue contract is a Transparent Proxy contract with the upgradeability by the general Timelock.

General admin permissions

  • The Withdraw Queue Admin (Timelock, Safe 3-of-5 0xD1e6…B68A) can set the withdraw buffer amount of assets by calling the updateWithdrawBufferTarget() function. Before updating the amounts, it checks internally whether the asset address is valid and if the buffer amount is not zero.
  • The Withdraw Queue Admin can update the cooldown period of the withdraw requests using the updateCoolDownPeriod() function. The current value in the cooldownPeriod storage variable is three days.
  • The Deposit Withdraw Pauser Admin (Safe 3-of-5 0xD1e6…B68A) can pause/unpause all withdrawals from the system by calling the pause() and unpause() functions, respectively.

Withdrawals and exchange rate

  • Users can withdraw ETH or LST by requesting via the withdraw(amount, asset) function. This function internally calls the calculateRedeemAmount(amount, totalSupply, TVL) in the Renzo Oracle contract, which returns the amount in ETH value. If the asset requested is an LST, it calls the lookupTokenAmountFromValue(token, redeemAmountValue) function to get the amount of the corresponding asset. The ezETH is locked in the contract and will be burned later.
  • The exchange rate is calculated in the calculateRedeemAmount(amount, totalSupply, TVL) function with the formula redeemAmountValue = (TVL * amount) / totalSupply. This returns the value of the redeemed amount in ETH. The lookupTokenAmountFromValue(token, redeemAmountValue) uses the formula tokenAmount = redeemAmountValue / tokenPrice to obtain the amount in the unit of the token.
  • The window for completing the withdrawal can vary from 3 to 10 days. This timeframe depends on whether the requested amount is already available in the WithdrawQueue or needs to be unstake from the Beacon Chain and Eigen Layer. If the amount is available, the request can completed in 3 days. Otherwise, the amount is queued to be unstake, which may take up to 10 days. Unstake from the Ethereum Beacon Chain can vary from a day to 9 days (Exit Queue + Sweep Delay), and the Eigen Layer requires seven days before withdrawal.
  • Users complete the withdrawal by calling the claim() function. Internally, it recalculates the redeemed amount by calling calculateRedeemAmount(amount, totalSupply, TVL) and updates the withdrawal to the lower value of the two amounts: the initially requested amount in the withdraw() function or the recalculated amount in the claim() step. Finally, the ezETH amount is burned, and the underlying tokens are sent to the user’s address.

Flow of funds

  • The unstaked tokens are sent to an Operator Delegator contract, which sends them to the Deposit Queue Contract to fill the Withdraw Queue contract by calling fillEthWithdrawBuffer() or fillERC20WithdrawBuffer(token) for LSTs.

Operator Delegator

The Operator Delegator contract manages the stake of ETH in the Beacon Chain and the deposit of LSTs in Eigen Layer strategies. This contract is responsible for staking and delegating the system’s assets to operators within EigenLayer, managing shares, and requesting and claiming withdrawals when needed.
The Operator Delegator is a Transparent Proxy with upgradeability by the general Timelock.

General admin permissions

  • The Operator Delegator Admin (Safe 3-5 0xD1e6…B68A, TimeLock) can set the strategy manager from EigenLayer for a given token by calling the setTokenStrategy(token, strategy).
  • The Operator Delegator Admin can set the Eigen Layer Operator of the tokens by calling the setDelegateAddress() function. Internally, it calls the Delegation Manager and delegates to an Operator, and it can be set only once.
  • The Operator Delegator Admin can set the Rewards Coordinator (EigenLayer contract to claim rewards) and the Rewards Destination address (from where to send the rewards) by calling the setRewardsCoordinator(address) and the setRewardsDestination(address), respectively.

Flow of funds

  • Once the Deposit Queue reaches 32 ETH, the Native ETH Restake Admin can call the stakeEthFromQueue(delegator) function in the Deposit Queue contract. This will send the funds to the Restake Manager contract using the stakeEthInOperatorDelegator(delegator) function, which in turn calls the stakeEth() function in the chosen Operator Delegator contract. This internally triggers the stake() function in the Eigen Pod Manager, and the ETH is staked.
  • LSTs are deposited into EigenLayer when users deposit them in the Restake Manager. Internally, it first fills any withdraw buffer in the Withdraw Queue contract and then calls the deposit(token, amount). The deposits can also be triggered via the Rewards Admin by calling the sweepERC20(token) in the Deposit Queue contract. This will send the Deposit Queue token balance minus protocol fees to the Restake Manager via the depositTokenRewardsFromProtocol(token) function, which calls the deposit(token, amount) in the chosen Operator Delegator contract. The Operator Delegator contract will deposit his token balance via the EigenLayer strategy Manager.
  • When the users’ ETH is staked in the Beacon Chain, the withdrawal credentials are delegated to the EigenPod in EigenLayer. With that, users earn staking rewards and rewards from their contribution to securing AVSs in EigenLayer.
  • To unstake ETH and withdraw LSTs from EigenLayer, the Native ETH Restake Admin should call the queueWithdrawals(tokens) function. This will trigger a withdrawal request from the Beacon Chain/Strategy Manager by calling the queueWithdrawals(tokens) in the Delegation Manager contract. Internally, the Operator Delegator is set as the receiver of the unstaked tokens, and shares of the withdrawn amount are incremented to a queuedShares[token] in the storage.
  • The Native ETH Restake Admin finalizes the withdrawal request by calling the completeQueuedWithdrawal(tokens) function, which calls the same function name in the Delegation Manager contract. The shares are discounted from the queuedShares[token], and the Operator Delegator fills the withdraw buffer if necessary. Any remaining token balance is restaked via the internal _deposit(token, amount) function.
  • The receive() function handles ETH unstaked from the Beacon Chain and protocol rewards. If the sender is the Eigen Pod contract, this function understands the value as ETH unstaked and sends it to the Deposit Queue contract by calling the forwardFullWithdrawalETH() function. For any other address that sends ETH, the function will consider the value as a protocol reward and transfer it to the Deposit Queue contract via a call() function, not limiting the reward amount for ETH.
  • The receive() function handles ETH unstaked from the Beacon Chain and protocol rewards. If the sender is the Eigen Pod contract, the function sends the ETH to the Deposit Queue contract via the forwardFullWithdrawalETH() function. For any other address that sends ETH, the function considers it a protocol reward and transfers it to the Deposit Queue contract via a call() function.
  • The Native Restake Admin can withdraw and send to any address any ETH in the Eigen Pod that is not staked in the Beacon Chain by calling the withdrawNonBeaconChainETHBalanceWei(address, amount) function. It can also rescue and send any ERC20 token accidentally sent to the Eigen Pod to any address by calling the recoverTokens(tokens).

Asset Pricing

After reviewing the system from a technical perspective (e.g. how the exchange rate is calculated), and the planned configurations, our suggestion for pricing is using a CAPO ezETH/ETH (exchange rate, not secondary market) + ETH/USD feed.

During the analysis, we identified that the exchange rate of ezETH can be inflated due to the accounting of stETH being queried directly via the balanceOf function. However, the potential for profitable manipulation through donations is effectively minimized and useless, given the following points:

  • As the listing of ezETH will happen after Aave v3.2, the main use case of the asset will be as collateral on an ezETH/wstETH eMode, or as collateral to borrow other assets is other eModes or non-eMode. Not being borrowable stops any potential attack.
  • Donating stETH to artificially increase the price of ezETH and borrow more wstETH is not economically viable on the base layer (Renzo). This is because donating stETH represents a real cost and a permanent loss. The attacker wouldn’t receive any ezETH, and the potential benefit gained from being able to borrow more wstETH due to an increase in the collateral’s value is unlikely to offset the cost of donated stETH. And still, the non-borrowable configuration on Aave supersedes this consideration.
  • Even if the price of ezETH reaches the maximum growth ratio (maxYearlyRatioGrowthPercent) in the CAPO oracle, creating arbitrage opportunities on the borrowing side, this behavior is short-lived and self-correcting, as withdrawals will quickly deplete the ezETH supply to sell it on the market at the inflated price.

Miscellaneous aspects

  • The system has four technical audit reviews by Halborn (1, 2), SigmaPrime, and Code4rena.
  • The minimum proposal delay of 3 days for upgradability is acceptable, but we recommend evaluating an extension, allowing more time to verify the safety of the new implementations.
  • Even if we don’t see any immediate threat on it, the system’s architecture pattern may lead to complexities within the system, and if not correctly managed during upgrades, unexpected behaviors can occur in the storage layout.
  • Regarding the Oracle contract, we notice a need for sanity verifications when adding a new oracle address, like compatibility with the ChainLink interface and whether the price is valid by calling Oracle.latestRoundData(), which is used by the system afterward. Still, from our perspective it is a pre-requirement of listing to Aave having a compromise to not list more assets without important time in advance, and we recommend to move to the Timelock the admin role of the Restake Manager.


Conclusion

We think ezETH doesn’t have any problem in terms of integration with Aave, and there is no major blocker for listing.

That being said, given the anticipated use cases of the asset, we highly encourage to wait until the Aave v3.2 release for listing.
Additionally, we recommend the Renzo team to consider the aforementioned minor considerations




Special thanks for the Renzo team to always support on all our inquiries about their system.

5 Likes

Thanks to @BGD for their thorough analysis.

With the imminent release of 3.2, we provide updated guidance on E-Mode for ezETH here:

  • The AIP proposal to onboard ezETH to the Lido instance will be submitted after 3.2 is live.
  • ezETH E-Mode will be configured based on 3.2 to allow only for borrowing wstETH

The intended result is that ezETH users borrow wstETH, increasing the deposit rate on wstETH therefore allowing for a higher acceptable ETH borrow rate for leverage stakers. In turn, the ETH supply rate will increase leading to additional deposits.

1 Like

Summary

Chaos Labs introduces two new E-mode categories - ezETH/USDS and ezETH/wstETH - and recommends updated parameters for ezETH on the Lido instance.

Motivation

With the introduction of Aave v3.2 and Liquid E-Modes, it is now possible to assign multiple E-Modes to a single asset. In this recommendation, we analyze the E-Mode parameters for each category and recommend parameters following Chaos Labs’ methodologies.

In our methodology, we consider on-chain liquidity, historical volatility, and daily price fluctuations to recommend supply caps and categorize the asset’s risk class, ensuring alignment between the LT and LTV ratios.

ezETH Supply caps

Based on Renzo Protocol’s documentation, the buffer capacity, which is the amount of collateral available for withdrawal at any given time, is set to 10,000 ETH and renews every beacon chain withdrawal cycle (approximately 10 days).
Chaos Labs’ approach to initial supply caps recommendations is usually at 2x the liquidity available under the Liquidation Penalty price impact in DEXes, which is around 2.5K. Combined with the liquidity available in the liquidity buffer, we recommend 15,000 ezETH. Notably, we can immediately double these caps post-listing to 30,000 through the risk steward and then adjust them every five days if user behavior and liquidity allow. This approach aims to quickly scale to the desired supply cap.
To promote the desired use case in the ezETH/wstETH E-Mode category, we will propose increasing the wstETH borrow caps on the Lido instance in a separate proposal.
Chaos Labs will continue monitoring the ezETH market to provide additional recommendations when needed.

LT and LTV

ezETH/wstETH E-mode category introduces a new pair of ETH-correlated assets and, therefore, remains consistent with the E-mode configurations on the Ethereum instance.

E-mode Category: ezETH/USDS

Relative to USD, ezETH has a daily annualized volatility of 64.5% over the last 180 days and 46.76% over the last 30 days. Its maximum price drop relative to USD was 10.3% over the former time frame.

image (107)

Given the isolated environment of the ezETH/USDS liquid E-Mode, we recommend setting slightly less restrictive parameters than ezETH would typically receive in the Lido instance on the Ethereum deployment. We find that an LTV of 75% and a Liquidation Threshold (LT) of 78% are permissive enough without exposing the protocol to unnecessary risk to account for the asset’s inherent volatility.

Revised Parameters for ezETH in the Non E-mode Setting

In V3.2, with assets allowed in multiple E-Modes, using ezETH as collateral outside of E-Mode in the Lido instance no longer fits the intended use case, as it introduces additional asset pairs and unnecessary risk. Therefore, in the non E-mode configuration, we suggest setting the Liquidation Threshold (LT) to 0.10% and the Loan-to-Value (LTV) ratio to 0.05%. Additionally, we recommend listing this asset as non-borrowable to prevent point farming looping.

Specification

E-mode Category 1: ezETH / USDS

Parameter Value Value
Asset ezETH USDS
Collateral Yes No
Borrowable No Yes
Max LTV 75% 75%
Liquidation Threshold 78% 78%
Liquidation Penalty 7.50% 7.50%

E-mode Category 2: ezETH / wstETH

Parameter Value Value
Asset ezETH wstETH
Collateral Yes No
Borrowable No Yes
Max LTV 93% 93%
Liquidation Threshold 95% 95%
Liquidation Penalty 1.00% 1.00%

ezETH Risk Parameters (Non E-mode)

Parameter Value
Asset ezETH
Isolation Mode No
Borrowable No
Collateral Enabled Yes
Supply Cap 15,000
Borrow Cap -
Debt Ceiling -
LTV 0.05%
LT 0.10%
Liquidation Penalty 7.5%
Liquidation Protocol Fee 10.00%
Variable Base -
Variable Slope1 -
Variable Slope2 -
Uoptimal -
Reserve Factor -
Stable Borrowing Disabled
Flashloanable Yes
Siloed Borrowing No
Borrowable in Isolation No
E-Mode Category 1 ezETH / USDS
E-Mode Category 2 ezETH / wstETH
3 Likes

Following a thorough review of the ezETH price cap adapter smart contract, we can confirm the oracle is secure for use.

The contract operates similarly to other LST price cap oracles, and after tracing its design to the Renzo implementation, we verified that the contract correctly returns price data in the expected economic units of [base_currency]/[LST], maintaining the precision of the ETH-USD Chainlink oracle decimals.

In particular, we focused on BGD’s concern regarding the possibility of inflating ezETH’s valuation through donation attacks.

BGD rightly notes that this type of manipulation could harm Aave users if ezETH were borrowable. By artificially inflating the price of the LST through ETH donations, an attacker could trigger liquidations, profiting from the discounted auction of collateral. As long as ezETH remains non-borrowable, the potential for such an attack is, of course, nullified.

When ezETH is used as collateral, the scenario is unfavorable for an attacker. The cost of inflating the price through donations is higher than the benefit gained from increased borrowing power, even under the most extreme conditions (e.g., holding 100% of ezETH supply). For any realistic holding fraction, the cost-benefit ratio of this attack strategy diminishes further, making it economically unviable.

In conclusion, we are confident that the price cap adapter is robust against donation-based price manipulation, and no significant risk to the protocol has been identified.

We attached mathematical reasoning of our conclusion for the collateral safety:
ezETH Price Cap Adapter.pdf (99.9 KB)

2 Likes

Summary

Considering the recent update to the ezETH reward distribution, which now incorporates accrued EIGEN rewards that are sold and compounded into ezETH, we propose updated CAPO parameters.

CAPO

Given that the compounding and distribution of EIGEN rewards represented a 0.21% daily yield, which annualizes to over 70% APY, we recommend using a 14 day MINIMUM_SNAPSHOT_DELAY to smooth the yield. Following our CAPO methodology, we also recommend setting the maxYearlyRatioGrowthPercent at 10.89%.

maxYearlyRatioGrowthPercent ratioReferenceTime MINIMUM_SNAPSHOT_DELAY
10.89% monthly 14 days
2 Likes

After discussing implementation with several service providers, this ARFC has been updated to include the following elements:

  • Increase borrow cap of wstETH to 14000
  • Remove wstETH as a borrowable asset in wstETH/wETH emode

This will allow implementation in sync with expected synergies with other assets in the Lido Instance. It also bundles [ARFC] Chaos Labs Risk Parameter Updates - Increase Borrow caps for wstETH on the Lido Market - 10/20/24 in this onboarding AIP for more efficiency.

4 Likes