Interactive Learn

Popcorn: ERC-4626 Adapter Vault

v0.1.0Available

Block-composed Learn

Building the Popcorn ERC-4626 Adapter Vault

Learning progress is session-only in this preview.
Chapter 1 · Section 1

Wiring the Vault to the Adapter

The Contracts Behind the Vault

Our PopcornVault does not keep user assets idle inside the outer vault. Instead, it forwards those assets to an ERC-4626 adapter that manages the underlying position.

This architecture creates two connected accounting layers.

Users interact with PopcornVault and receive Popcorn shares. PopcornVault interacts with the adapter and receives adapter shares.

Although both tokens are called shares, they represent ownership in different contracts and must not be treated as the same unit.

Diagram showing a user depositing underlying assets into the Popcorn vault. The vault deposits those assets into an ERC-4626 adapter that manages the underlying strategy. The user owns Popcorn vault shares, while the Popcorn vault owns adapter shares.
Assets move through PopcornVault into the ERC-4626 adapter, while ownership at each layer is represented by a separate share token.

Declaring the Asset and Adapter

The outer vault needs references to two contracts.

The first is the underlying ERC-20 asset deposited by users. The second is the adapter, an ERC-4626 vault that receives and manages that asset.

PopcornVault also issues its own ERC-20 share token. These shares represent a user's ownership in the outer vault, not direct ownership of the adapter position.

Both contract references are declared immutable. Once the vault begins issuing shares, changing its underlying asset or adapter would change what the existing shares represent.

CodeOriginal educational source authored for TraceFi.
PopcornVault.solSolidity · Read-only
  1. // SPDX-License-Identifier: MIT
  2. pragma solidity ^0.8.24;
  3. import {ERC20} from
  4. "@openzeppelin/contracts/token/ERC20/ERC20.sol";
  5. import {IERC20} from
  6. "@openzeppelin/contracts/token/ERC20/IERC20.sol";
  7. import {IERC4626} from
  8. "@openzeppelin/contracts/interfaces/IERC4626.sol";
  9. import {SafeERC20} from
  10. "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
  11. contract PopcornVault is ERC20 {
  12. using SafeERC20 for IERC20;
  13. IERC20 public immutable underlying;
  14. IERC4626 public immutable adapter;
  15. constructor(
  16. IERC20 underlying_,
  17. IERC4626 adapter_
  18. ) ERC20("Popcorn Vault Share", "pVAULT") {
  19. underlying = underlying_;
  20. adapter = adapter_;
  21. }
  22. }
Loading PopcornVault.sol source

This initial version of PopcornVault defines the two contract references required by the outer vault.

The underlying variable points to the ERC-20 asset accepted from users. The adapter variable points to the ERC-4626 vault that will manage that asset.

PopcornVault inherits from ERC20 because it issues its own transferable shares to users.

For now, the constructor only stores the two contract references. In the next section, we will validate the adapter's asset and configure the token allowance required for future deposits.

What We Have Built

The outer vault is now connected to its underlying asset and ERC-4626 adapter.

Users interact with PopcornVault, while PopcornVault interacts with the adapter.

Users own Popcorn shares. PopcornVault owns adapter shares, and the adapter manages the underlying assets.

We have not implemented deposit() yet. In the next chapter, we will use the vault's adapter position to calculate totalAssets() and begin implementing the asset-to-share accounting.