Token Vaults in the USB-C Era
January 13th, 2024

It’s hard to ignore the fact that DeFi continues to be a significant use case for blockchain. As of this writing, DeFi protocols have over $58 billion in value locked, known as TVL (total value locked). This value comes in the way of digital assets, such as tokens.

This continued demand in DeFi protocols highlights the need for standards like ERC-4626, crucial for ensuring consistency.

In this article, I share my learnings and thoughts around ERC-4626, a standardization for tokenized vaults.

Here’s what we’ll cover.

  • The Composability Nightmare Problem

  • Why the USB-C Era for Token Vaults is Needed

  • The 18 Methods of ERC-4626 (And two of the most important ones)

Before we dive into ERC-4626, here are some important terms that are helpful to understand:

Definitions

Interface: an "interface" acts as a control panel for a program, listing available functions, their required inputs (parameters), and the resulting outputs (return values).

Behavior: refers to how a system or component consistently manages its actions and status, responding to inputs and events.

Adapter Code: is customarily created to transform or adjust one interface or protocol into another, enabling systems or components originally designed to work separately to interact smoothly.

Connectors: serve as universal connection points between systems, enabling communication and data exchange. They act as bridges that link different systems or components.

Composability: represents the ability of various components or systems to seamlessly integrate and operate together, resulting in a harmonious and functional whole.

The Composability Nightmare Problem

Token vaults are used in DeFi to earn rewards on your crypto. They are smart contracts that accept deposits and earn yield (interest). Vaults implement complex strategies, like leveraging, auto-compounding, and diversifying across various protocols in order to get the best return.

This variance in strategy and implementations causes a few problems, putting you right in the middle of what I call a 'composability nightmare’.

In blockchain, composability is important because it allows different protocols and applications to interact seamlessly, creating a more interconnected and functional ecosystem. The way token vaults are currently implemented, with their varied requirements and behaviors, doesn't exactly help in enhancing this composability.

This is like having to buy a new charger every time you upgrade your phone because the old one is obsolete. Can you  imagine how filled your drawers would be? This situation was not only inconvenient but also both time-consuming and costly.

This is how vault tokens work today. Vaults are cell phones- and chargers represent the connectors.

Just as each new phone model often required a different charger back in 2008, DeFi protocols integrating token vaults must continually develop and update specialized ‘chargers’ (adapters and connectors) to accommodate the unique requirements of each vault

This current way has a few drawbacks:

  • Increases the likelihood of errors in code. Protocol engineers must understand various implementations, adding complexity and risk of security costs due to buggy code.

  • Requires increased resources. Time spent learning and implementing the code is an expense to the organization.

Why the USB-C Era for Token Vaults is Needed

ERC-4626 aims to provide a standardized interface and behavior for token vaults.

Let’s first start with illustrating a basic token vault. These are the basic functionalities we’d like to have:

  1. Allow user to deposit

  2. Allow user to withdraw

  3. Read vault balance

  4. Vault manage asset to share amount

Token vaults enter their USB-C era

ERC-4626 is a way to universally implement token vaults, so protocol engineers can easily integrate them with other dapps and tools.

As we've discussed, even basic functionalities in token vaults can be implemented in various ways, leading to complexities. For instance, when considering any standard function within these vaults, questions arise about its structure and parameters. What data should it accept? How should it handle different user scenarios?

You can appreciate how such nuances can quickly escalate into larger composability problems, especially as the vaults grow in complexity.

The 18 Methods of ERC-4626 (And two of the most important ones)

ERC-4626 offers 18 methods and 2 events for developers to easily inherit in their vaults. This standard provides developers a ‘feature ready’ concept. While not primarily focused on security, an increase in security emerged as a beneficial byproduct.

Developed through community proposals and votes, ERC-4626 adheres to good conventions and essential safeguards. It ensures functions have standardized meanings and behaviors. Safeguards, such as the checks and effects pattern, are implemented to prevent malicious actors from exploiting the contract logic before transactions are finalized.

We won’t be reviewing all 18 methods, but we will evaluate the deposit and withdraw methods.

Deposit

Let’s begin with a diagram illustrating the basic user flow of depositing assets into a vault.

I want to deposit $100 USDC. In exchange I will be issued vUSDC (vault tokens) that represent the shares I own in the vault.

  1. Transfer assets to vault

  2. Issue vault tokens

Sounds pretty basic, but let’s dive deeper and see what the code is actually doing. You can find the code to this method here.

  1. Parameters

    The deposit function is called with two parameters, assets and receiver. assets are expected to be a number representing the amount of the token that the depositor wants to deposit. The receiver is the address that will receive the vault tokens.

  2. Calculate and Validate Shares

    This check ensures that the amount of assets about to be deposited will result in the issuance of vault tokens. If the number is greater than 0, it moves onto the next line. If the number is 0, then the transaction will be reverted. Gas will still be paid up to this point.

  3. Transfer Assets to Vault

    In order to securely transfer the assets from the user to the vault, the contract calls the safeTransferFrom method, which is inherited from the ERC-20 standard. Because it facilitates the transfer of assets from the user's control to the contract, the user must first call the approve method on the token contract to grant the vault contract an allowance to use their assets.

  4. Issue Vault Tokens

    This involves another ERC-20 method, where _mint generates a new supply of vault tokens. The new supply, also known as shares, are then sent to the receiver.

  5. Deposit Event

    The contract records the deposit details in an event, capturing the initiator, receiver, and the amounts of assets and shares. Frontend applications can listen to these events to trigger UI updates.

  6. Optional Hook

    Is intended to execute some additional code after the deposit process (including asset transfer and share minting) has been completed.

This method's construction was no accident. It follows best practices by using secure asset transfer methods, implementing checks for share calculation, and utilizing event logging for transparency.

Withdraw

Let's start by visualizing the basic process of withdrawing assets from a vault.

I want to withdraw $50 USDC. When I initiate the transaction, the vault will then burn the corresponding vault tokens in comparison to the value of my request withdraw.

Here’s what happens on a high level.

  1. Burn Vault Tokens

  2. Transfer Assets

Let’s take a deep dive into the code. You can find the code to this method here.

  1. Parameters

    The withdraw function takes three parameters: assets, receiver, and owner. Assets is the amount of USDC I wish to withdraw. The receiver is the address that will receive the assets, and owner is the address that owns the vault tokens to be burned

  2. Calculate Shares for Assets

    First, the contract calculates the number of shares equivalent to the assets I want to withdraw using previewWithdraw(assets). This determines how many of my vault tokens (vUSDC) are needed for the withdrawal.

  3. Ownership Verification

    The contract checks if I am the owner of the vault tokens. If not, it proceeds to the next step.

  4. Authorized Withdrawal Check

    If I'm not the owner, the contract calculates how many shares I am authorized to withdraw on behalf of the owner. This step involves checking the allowance set by the owner for my address.

  5. Permission Validation

    The contract ensures I have the owner's permission to withdraw the specified amount. If the allowance is sufficient, it's reduced by the number of shares being withdrawn.

  6. Optional Hook

    Before the actual withdrawal, an optional hook can execute additional logic.

  7. Burn Vault Tokens

    Next, the contract burns the calculated number of vault tokens (vUSDC) from the owner's balance. This step reduces the total supply of vault tokens in circulation.

  8. Withdraw Event

    The contract records the withdrawal details in an event, noting who initiated the withdrawal, who is receiving the assets, and the amounts involved. Frontend applications can listen to these events to trigger UI updates.

  9. Transfer Assets

    Finally, the assets (USDC) are transferred from the vault to the receiver's address using the safeTransfer method. Unlike the deposit function, where safeTransferFrom is used to pull assets from the user's account with their permission, safeTransfer is employed here because the assets are being pushed from the vault's own balance to the receiver. This method simplifies the process, as it doesn't require the prior approval step that safeTransferFrom requires.

The withdraw method's design is intentional, ensuring security with strict checks and clear event logging, embodying best practices for efficient and transparent transactions.

Real Use Case

Now that we have looked at each part of the process, let's explore a real-world implementation of an ERC-4626 vault. We'll be reviewing the AaveV3ERC4626Reinvestment contract, which is deployed on the Polygon network. Aave is a well-known DeFi lending platform.

Aave's implementation in this contract demonstrates the process of earning additional rewards through Aave's liquidity mining programs.

We'll highlight the differences in these implementations.

In Solidity, when a function inherited from a parent contract is customized, it uses the 'override' keyword to indicate that the function in the child contract is intended to override a function from the parent contract. While the deposit function remains unchanged in this contract, the afterDeposit method – the optional hook we briefly discussed earlier – is overridden.

afterDeposit

Let’s begin by reviewing how afterDeposit receives custom logic to enhance the functionality of this vault.

  1. Approval and Asset Transfer: Before depositing assets into Aave, the function first ensures that the vault contract has permission to use the user's assets. It does this by calling the safeApprove method on the token contract (asset). This step is essential because it allows the vault contract to move the user's assets.

  2. Deposit into Aave: Once the approval is in place, the function calls the supply method on the lendingPool contract. This action deposits the specified assets into Aave, making them available for lending and yield generation within the Aave protocol. The address(this) parameter designates the vault contract as the depositor, and 0 indicates no additional specific instruction for this deposit.

Withdraw

Alright, now let's review the withdraw function; this function is also overridden, and you can see it's implementing custom functionality.

  1. Approval and Asset Transfer: In this step, the afterDeposit function begins by ensuring that the vault contract has the necessary permission to use the user's assets. This is achieved by invoking the safeApprove method on the token contract (referred to as asset). The purpose of this step is to authorize the vault contract to manage the user's assets securely.

  2. Asset Redemption: Following the approval, the function proceeds to deposit the specified assets into the Aave protocol. This is accomplished by calling the supply method on the lendingPool contract. This action effectively moves the assets into Aave, where they can be utilized for lending and yield generation within the Aave ecosystem.

Thoughts

I’m extremely bullish on this standard. It represents a significant step forward in addressing the complexities and fragmentation we currently see in DeFi.

Here is why:

  1. L2 Adoption: ERC-4626 simplifies integration with L2 networks, enhancing the DeFi experience for users.

  2. Trust and Innovation: It fosters trust and encourages innovation within the DeFi community by establishing common standards for security and functionality.

  3. Streamlined Development: ERC-4626 simplifies the development process, enhances security, and allows developers to focus on refining strategies and building better DeFi applications.

Now we have gained a clear understanding of what token vaults are, recognized the importance of standardization, and grasped how ERC-4626 significantly contributes to enhancing consistency and efficiency within the DeFi ecosystem.

If you're curious about the adoption of this standard, currently, there are over 100 vaults that are ERC-4626 compliant.

Subscribe to Vanes
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.
More from Vanes

Skeleton

Skeleton

Skeleton