The following standard adapts ERC-4626 to support multiple assets or entry points for the same share token. This also enables Vaults which don’t have a true share token but rather convert between two arbitrary external tokens.
It adds a new share method to the Vault, to allow the ERC-20 dependency to be externalized.
It also adds Vault-to-Share lookup to the share token.
Lastly, it enforces ERC-165 support for Vaults and the share token.
Motivation
One missing use case that is not supported by ERC-4626 is Vaults which have multiple assets or entry points such as liquidity provider (LP) Tokens. These are generally unwieldy or non-compliant due to the requirement of ERC-4626 to itself be an ERC-20.
Specification
Definitions:
The existing definitions from ERC-4626 apply. In addition, this spec defines:
Multi-Asset Vaults: A Vault which has multiple assets/entry points. The Multi-Asset Vault refers to the group of ERC-7575 contracts with the entry points for a specific asset, linked to one common share token.
Pipe: A converter from one token to another (unidirectional or bidirectional)
Multi-Asset Vaults share a single share token with multiple entry points denominated in different asset tokens.
Multi-Asset Vaults MUST implement the share method on each entry point. The entry points SHOULD NOT be ERC-20.
Pipes
Pipes convert between a single asset and share which are both ERC-20 tokens outside the Vault.
A Pipe MAY be either unidirectional or bidirectional.
A unidirectional Pipe SHOULD implement only the entry function(s) deposit and/or mint, not redeem and/or withdraw.
The entry points SHOULD lock or burn the asset from the msg.sender and mint or transfer the share to the receiver. For bidirectional pipes, the exit points SHOULD lock or burn the share from the owner and mint or transfer the asset to the receiver.
Share-to-Vault lookup
The ERC-20 implementation of share SHOULD implement a vault method, that returns the address of the Vault for a specific asset.
SHOULD emit the VaultUpdate event when a Vault linked to the share changes.
Vaults implementing ERC-7575 MUST implement the ERC-165supportsInterface function. The Vault contract MUST return the constant value true if 0x2f0a18c5 is passed through the interfaceID argument.
The share contract SHOULD implement the ERC-165supportsInterface function. The share token MUST return the constant value true if 0xf815c03d is passed through the interfaceID argument.
This standard is intentionally flexible to support both existing ERC-4626 Vaults easily by the introduction of a single new method, but also flexible to support new use cases by allowing separate share tokens.
By allowing share != address(this), the Vault can have an external contract managing the ERC-20 functionality of the Share. In the case of Multi-Asset, this avoids the confusion that might arise if each Vault itself were required to be an ERC-20, which could confuse integrators and front-ends.
This approach also enables the creation of new types of Vaults, such as Pipes, which facilitate the conversion between two external ERC-20 tokens. These Pipes could be unidirectional (i.e. only for assets to shares via deposit/mint, or shares to assets via redeem/withdraw) or bidirectional for both entry and exit flows.
Including Share-to-Vault lookup optionally
The vault method is included to look up a Vault for a share by its asset, combined with the VaultUpdate event and ERC-165 support. This enables integrations to easily query Multi-Asset Vaults.
This is optional, to maintain backward compatibility with use cases where the share is an existing deployed contract.
Backwards Compatibility
ERC-7575 Vaults are not fully compatible with ERC-4626 because the ERC-20 functionality has been removed.
Reference Implementation
// This code snippet is incomplete pseudocode used for example only and is no way intended to be used in production or guaranteed to be secure
contractShareisERC20{mapping(addressasset=>address)vault;functionupdateVault(addressasset,addressvault_)public{vault[asset]=vault_;emitUpdateVault(asset,vault_);}functionsupportsInterface(bytes4interfaceId)externalpureoverridereturns(bool){returninterfaceId==0xf815c03d||interfaceId==0x01ffc9a7;}}contractTokenAVaultisERC7575{addresspublicshare=address(Share);addresspublicasset=address(TokenA);// ERC4626 implementation
functionsupportsInterface(bytes4interfaceId)externalpureoverridereturns(bool){returninterfaceId==0x2f0a18c5||interfaceId==0x01ffc9a7;}}contractTokenBVaultisERC7575{addresspublicshare=address(Share);addresspublicasset=address(TokenB);// ERC4626 implementation
functionsupportsInterface(bytes4interfaceId)externalpureoverridereturns(bool){returninterfaceId==0x2f0a18c5||interfaceId==0x01ffc9a7;}}
Security Considerations
ERC-20 non-compliant Vaults must take care with supporting a redeem flow where owner is not msg.sender, since the ERC-20 approval flow does not by itself work if the Vault and share are separate contracts. It can work by setting up the Vault as a Trusted Forwarder of the share token, using ERC-2771.