ERC4626: A new standard for tokenized vaults
ERC token standards
We’ve heard about the ERC20 and ERC721 token standards. And in case you’re not familiar with them, here is a quick refresh:
- ERC20: an implementation for tokens that includes methods like
transfer
,approve
,allowance
,totalSupply
, andbalanceOf
. It’s used as a base for hundreds of tokens like USDC, WBTC, or LINK. - ERC721: an implementation for Non Fungible Tokens (NFTs) used for assets and collections like Bored Ape Yatch Club (BAYC) or Moonbirds traded in OpenSea and other marketplaces.
They are the building blocks that allowed hundreds of apps to appear in recent years and the main reason behind the ICO era of 2018 and the NFT boom in the last two years.
These standards gave developers a starting point for their apps and allowed them to create tokens in just a few minutes. The ERC4626 is a new extension of the ERC20 and it will give a fresh perspective to the DeFi space.
ERC4626 in a nutshell
A tokenized vault holds a specific ERC20 token and gives shares to the users that deposit assets in it. When a user deposits funds, the vault will mint a specific number of shares for the user. When the user withdraws tokens from the vault, the correspondent amount of shares will be burnt.
The ERC4626 contract inherits from the ERC20 contract to manage the shares that will be minted and burnt when the users interact with the vault. It’ll do so by calling the methods mint
and burn
from ERC20.
This means that other methods like balanceOf
and totalSupply
can be used. In addition, as shares are ERC20 tokens, they can be transferred using the native transfer
method (or transferFrom
), unless the vault is created as non-transferrable.
ERC 4626 Methods
Here are some of the most important methods in the ERC4626 tokenized vault contract:
constructor(ERC20 asset, string name, string symbol)
The constructor that initializes an ERC4626 vault upon deployment receives three parameters:
- asset — is the underlying token that will be stored in the vault
- name — the name of the vault
- symbol — the symbol of the shares minted for the users
asset()
The asset
method returns the address of the ERC20 token that is deposited in the vault by the users.
deposit(uint assets, address receiver)
The deposit
method is used to deposit the exact amount of assets
in the vault and mint a corresponding number of shares for the receiver
.
As the token will be transferred to the vault, this requires that the user had approved for the tokens to be transferred in advance via the approve
or transferFrom
ERC20 methods.
The methods maxDeposit
returns the maximum amount of tokens that can be deposited in the vault. The previewDeposit
method allows users to simulate the deposit and returns the number of shares that the user would receive.
mint(uint shares, address receiver)
Similar to the deposit
method but in this case, it receives as a parameter the number of shares
to mint.
The maxMint
and previewMint
methods are also available.
withdraw(uint assets, address receiver, address owner)
The withdraw
method burns the corresponding number of shares required to send the indicated amount of the original asset to the receiver.
The maxWithdraw
method returns the maximum number of tokens that the user is allowed to withdraw. The previewWithdraw
allows users to simulate the withdrawal and returns the number of shares that would be burned in the withdrawal.
redeem(uint shares, address receiver, address owner)
Similar to the withdraw
method although it receives as a parameter the number of shares
to burn.
The maxRedeed
and previewRedeem
methods are also available.
Events
The ERC4626 tokenized vault has just two events:
- Deposit: emitted from the
deposit
andmint
methods. - Withdraw: emitted from the
withdraw
andredeem
methods.
Contract interface
Here is the full contract interface for the ERC4626, which includes all the methods and events:
interface IERC4626 {
function asset() external view returns (address assetTokenAddress);
function totalAssets() external view returns (uint256 totalManagedAssets);
function convertToShares(uint256 assets) external view returns (uint256 shares);
function convertToAssets(uint256 shares) external view returns (uint256 assets);
function maxDeposit(address receiver) external view returns (uint256 maxAssets);
function previewDeposit(uint256 assets) external view returns (uint256 shares);
function deposit(uint256 assets, address receiver) external returns (uint256 shares);
function maxMint(address receiver) external view returns (uint256 maxShares);
function previewMint(uint256 shares) external view returns (uint256 assets);
function mint(uint256 shares, address receiver) external returns (uint256 assets);
function maxWithdraw(address owner) external view returns (uint256 maxAssets);
function previewWithdraw(uint256 assets) external view returns (uint256 shares);
function withdraw(uint256 assets, address receiver, address owner) external returns (uint256 shares);
function maxRedeem(address owner) external view returns (uint256 maxShares);
function previewRedeem(uint256 shares) external view returns (uint256 assets);
function redeem(uint256 shares, address receiver, address owner) external returns (uint256 assets);
event Deposit(address indexed caller, address indexed owner, uint256 assets, uint256 shares);
event Withdraw(address indexed caller, address indexed receiver, address indexed owner, uint256 assets, uint256 shares);
}
Example implementation
The ERC4626 specification is completed and you can find all the details here. Based on that, a pull request was created in the OpenZeppelin repository which was finally merged on June 1st, 2022. The tokenized vault is an ERC20 extension so you can import it from :
openzeppelin-contracts/contracts/token/ERC20/extensions/ERC4626.sol
You can find the full contract here.
As the specification is already completed, there are teams already working with it. For example, Rari Capital has a GitHub repo with the ERC4626 contract and an example implementation.
In that example, you can see how they’ve extended the contract to include fees, an authentication system that sets the contract deployer as the owner of the vault, more events, etc.
If it looks too complex, check out the Vault’s test file to understand how to interact with the Vault contract. You can run the tests locally using Foundry (check out our intro to Foundry here).
Conclusion
The adoption of this standard is promising, and I’ve already found one version written in Vyper by fubuloubu and another one written in Cairo.
There are also some tools under development, like this ERC4626 router by fei-protocol that can perform multicalls to different vaults.
By using a standard token, interoperability between protocols will be improved, aggregators will be easier to build, and applications will be more secure. Now it’s your time to start building with it 🤙
- Discover how you can save thousands in infra costs every month with our unbeatable pricing on the most complete Web3 development platform.
- Input your workload and see how affordable Chainstack is compared to other RPC providers.
- Connect to Ethereum, Solana, BNB Smart Chain, Polygon, Arbitrum, Base, Optimism, Avalanche, TON, Ronin, zkSync Era, Starknet, Scroll, Aptos, Fantom, Cronos, Gnosis Chain, Klaytn, Moonbeam, Celo, Aurora, Oasis Sapphire, Polygon zkEVM, Bitcoin and Harmony mainnet or testnets through an interface designed to help you get the job done.
- To learn more about Chainstack, visit our Developer Portal or join our Discord server and Telegram group.
- Are you in need of testnet tokens? Request some from our faucets. Multi-chain faucet, Sepolia faucet, Holesky faucet, BNB faucet, zkSync faucet, Scroll faucet.
Have you already explored what you can achieve with Chainstack? Get started for free today.