TLDR: ERC-4626 is a standard for tokenized vaults.
Before the introduction of ERC-4626, every vault had its own distinctive specification and implementation details. This made integration difficult, error prone, and wasteful.
ERC-4626 attempts to solve this problem by introducing a standard specification to lower integration efforts and create more consistent and robust implementation patterns, just like ERC-20.
What Is ERC-4626?
ERC-4626 is a standard that improves the technical parameters of yield-bearing vaults. It provides a standard API for tokenized yield-bearing vaults that represent shares of a single underlying ERC-20 token.
Tokenized vaults have become an extremely common pattern across DeFi. Yield aggregators, lending markets, staking derivatives, and many more dApps utilize and rely on tokenized vaults. Examples of tokenized vaults include Yearn and Balancer. As a yield aggregator, Yearn vaults enable users to deposit digital assets and receive yield. Balancer, an automated portfolio manager and liquidity provider, relies on vaults at the core of its business logic. These vaults manage tokens in various pools. At the same time, they separate the token accounting and management from the pool logic.
Protocols tokenize their vaults to enhance liquidity and flexibility. Tokenized vaults allow for easy trading and utilization of assets across DeFi platforms. Additionally, they enable the creation of diverse, interconnected financial products. The industry has continually advocated for this paradigm, often referred to as “Money Legos”.
However, composability without proper adaptability or standardization creates challenges. It not only makes it difficult for developers to conform to industry standards like ERC-20 but also confuses new developers. Without proper adaptability or standardization, it is difficult to review new changes and verify the implementation details of an integration.
ERC-4626 has been proposed to solve this problem and simplify integration while allowing DeFi players to eventually adopt a more secure and robust unified specification for vaults. This will also in turn reduce the attack surfaces protocols need to cover while integrating tokens across multiple protocols.
What Security Issues Does ERC-4626 Prevent?
By providing a uniform standard for projects to follow, ERC-4626 speeds up the building of cross-protocol integrations. A familiar, uniform standard is also easier for developers to reason about, which makes coding mistakes less likely. This helps prevent composability issues. Standardization also prevents duplication of work, since the community only needs to design the vaults once, rather than individually for every protocol. And since that design work is often error prone, it helps avoid repeating well-established yet common design pitfalls.
We will go over two case studies here to showcase what sort of issues ERC-4626 can prevent.
Rari Capital Incident
Rari Capital was hacked for approximately $11 million worth of tokens, which amounted to 60% of all users’ funds in the Rari Capital Ethereum Pool.
In summary, Rari Capital was hacked due to an insecure cross-protocol implementation. Its Ethereum Pool deposited ETH into Alpha Finance’s ibETH token contract as a yield-generating strategy. This specific strategy tracked the value of its
ibETH/ETH rate through the
ibETH.totalETH() / ibETH.totalSupply() formula. This can have an incorrect output in a scenario such as that in this attack, for example while invoking the
ibETH.work() function, as debt value can get artificially inflated.
The attacker simply called the
withdraw() functions in the RariFundManager contract repeatedly, draining the Rari Fund Manager. The
withdraw() functions would need to get the balance of the pool in order to calculate the number of REPT tokens to be issued to the caller or the amount of ETH to be issued to the caller, respectively. This operation, in turn, would invoke the
getBalance() function from the Alpha pool, calling the ibETH contract and its
totalETH() function. Rari was unaware of the possibility of manipulating this function.
There is another function in the ibETH contract:
ibETH.work(). This function can call any contract specified by the user. This makes it possible for the
withdraw() functions from Rari to become reentrant and called multiple times.
work() function is a
payable function, meaning that users can control the amount of ETH in the ibETH contract through the
work() function, thereby changing the value returned by the
totalETH() function. Even worse, the
work() function also supports calling any other contracts such as RariFundManager.
Through this function, the attacker can again send ETH and inflate the
totalETH amount in the ibETH contract and, in return, redeem more assets while invoking
withdraw from the RariFundManager contract.
The excerpt below from the postmortem speaks very clearly about the importance of the ERC-4626 proposal, in terms of adopting more unified specifications for integrations in order to avoid attack scenarios such as this.
*To avoid issues like this in the future, we will be implementing the following additional security measures:
- Enlist the protocols we integrate to review our integrations of them for security. This is by far the most important security measure, as the protocols themselves know the code they wrote better than anyone else.*
The incident underscores the critical risks of inadequate integration and incompatible designs in DeFi contracts. It highlights how a standard like ERC-4626, promoting uniform behavior and mutual understanding, could prevent such attacks by adding an essential layer of security and predictability.
Cream Finance Incident
Cream Finance was exploited in a sophisticated attack that took advantage of two fundamental weaknesses in the platform, a manipulatable hybrid oracle and an uncapped supply of tokens. The critical component of the attack was the manipulation of the hybrid oracle, which influenced the perceived value of the yUSD tokens. This was achieved when the attacker sent a substantial amount of Yearn 4-Curve tokens to the yUSD vault, altering the exchange rate that the vault reported and, consequently, the oracle's perceived value of the yUSD tokens.
The key lesson here is the importance of a robust and nonmanipulable price oracle for the stability of DeFi protocols. Time-weighted average price (TWAP) oracles, which calculate average prices over a specific period, could have helped prevent this hack as they're more resilient to sudden price manipulation. This unfortunate event underscores the crucial role of secure and reliable oracles in ensuring the health and robustness of DeFi ecosystems.
With ERC-4626, protocols are now encouraged to implement the
convert method as using a time-weighted average price in converting between assets and shares.
These, alongside other vulnerable patterns, can be accounted for and mitigated with the help of careful adoption and implementation of ERC-4626.
Potential Security Pitfalls Under ERC-4626
There are always tradeoffs. With tokenized vaults, it is important to take caution for potential pitfalls when integrating them into smart contracts.
If the vault is intended to support
feeOnTransfer tokens, check that the amounts and shares in the vault are in their expected ranges, respectively, when a fee is subtracted upon a transfer of assets.
Proper Use of
convertTo functions should eliminate the need for any use of an EIP-4626 vault’s
decimals variable, it is still strongly recommended to mirror the underlying token’s
decimals whenever feasible. This practice helps eliminate potential sources of confusion and simplifies integration across various front ends and for off-chain users.
According to the spec, Vault implementers should be aware of the need for specific, opposing rounding directions across the different mutable and view methods, as it is considered most secure to favor the vault itself during calculations over its users:
- If (1) it’s calculating how many shares to issue to a user for a certain amount of the underlying tokens they provide or (2) it’s determining the amount of the underlying tokens to transfer to them for returning a certain amount of shares, it should round down.
- If (1) it’s calculating the amount of shares a user has to supply to receive a given amount of the underlying tokens or (2) it’s calculating the amount of underlying tokens a user has to provide to receive a certain amount of shares, it should round up.
The only functions where the preferred rounding direction would be ambiguous are the
convertTo functions. To ensure consistency across all EIP-4626 vault implementations, it is specified that these functions MUST both always round down. Integrators may wish to mimic rounding up versions of these functions themselves, for example by adding one Wei to the result.
What You Give Is Not (Necessarily) What You Get
The amount of underlying assets a user may receive through redeeming their shares in the vault (
previewRedeem) can be significantly different than the amount that would be taken from them when minting the same quantity of shares (
previewMint). The differences may be small (e.g., if due to rounding error) or significant (e.g., if a vault implements withdrawal or deposit fees). Therefore, integrators should take care to use the preview function most relevant to their use case and never assume they are interchangeable.
Overriding Core Functionality
To implement or extend intended functionalities, utilizing existing hooks is the suggested approach rather than altering core functions. This practice ensures a more manageable trace for effective code testing and auditing.
The Zero Share Case
The original spec for ERC-4626 has not outlined how to handle the edge cases in which there are zero numbers of shares available in a vault and whether the vault should work as normal or revert. This can turn into a potential source of confusion and error.
Vaults as Price Oracles
With regards to the risk of oracle price manipulation attacks, the
preview methods return values that are as close as possible to exact as possible. For that reason, they are manipulatable by altering the on-chain conditions and are not always safe to be used as price oracles. The 4626 spec includes
convert methods and a
totalAssets method that are allowed to be inexact and therefore can be implemented as robust price oracles. For example, it would be correct to implement the
convert methods using a time-weighted average price in converting between assets and shares.
An integrator must review any implementation of a tokenized vault before further integration, as potentially malicious implementations available out there can look like conforming to the interface while consisting of completely different design specifications in their core functions.
EOA Direct Access
If a vault is meant to be directly accessed through EOAs, its implementation needs to have functions available to accommodate slippage loss or unexpected deposit/withdraw limits. Unlike smart contracts, EOAs have no fail-safe mechanism for transaction reversion if the exact output is not achieved while invoking the four core functions.
As more actors start to adopt ERC-4626 standard, we will get to see more extensions implemented for the standard. For instance, Superform has developed an experimental MultiVault extension to support multiple assets with separate accounting within one vault contract. Naturally, the more an implementation deviates from the original standard, the higher the likelihood of introducing new vulnerabilities. Developers and auditors can find their very own optimum based on their use case in terms of how much deviation is actually worth the risk.
It is important to note that it is not minimal additions per protocol that will lead to catastrophic events but the sum of them while integrated together.
The potential attack vectors mentioned above are some of the more discussed issues surrounding the 4626 standard. As the rate of adoption increases, we will definitely get to explore more angles of implementations of and integrations with 4626 vaults.