Usual Tech Docs
Usual WebsiteGeneral DocsContract DeploymentsAuditsAccess dApp
  • 🚀GM GM
    • Usual Tech Hub
  • 🔭Overview
    • Usual Protocol Primer
    • Features
      • Mint & Redeem Engine
      • USD0
      • USD0++
      • USUAL
      • USUAL*
      • USUALx (USUAL staking)
      • USUAL distribution
      • USUAL Airdrop
      • Usual USD0++ Investment Vault
    • Architecture
      • Role Management
      • USUAL Distribution Model
  • ⛓️Smart Contracts
    • Protocol Contracts
      • DaoCollateral
      • Swapper Engine
      • USUAL staking
      • USUAL* Vested Allocation Staking
      • USUAL Distribution
        • Distribution Module
        • Yield Module
      • Airdrop Module
    • Token Contracts
      • USD0
      • USD0++
      • USUAL
      • USUAL*
      • USUALx
      • Usual USD0++ Investment Vault
        • VaultRouter
    • Utility Contracts
      • ClassicalOracle
      • Abstract Oracle
      • Chainlink Oracles
      • Pyth Oracles
      • RedStone Oracles
    • Real World Assets
      • USYC (by Hashnote)
      • M (by M0)
        • UsualM
      • USDtb
    • Contract Deployments
  • 🛡️Security & Audits
    • Security Practices
    • Testing Framework
    • Monitoring Framework
    • Audits
    • Bug Bounty
  • 🧩Integrations
    • Integrate USD0++
      • Reward redistribution by integration partner
      • Claim Address Redirect
      • Daily Distribution powered by Brevis (coming soon)
  • 📚Resources
    • Community & Support
    • References
  • 📖Support
    • FAQ
    • Glossary
  • ⚖️Legal
    • Terms of Services
    • Legal Notice
    • Privacy Policy
Powered by GitBook
On this page
  • High-Level Overview
  • Contract Summary
  • Functionality Breakdown
  • Security Analysis

Was this helpful?

  1. Smart Contracts
  2. Token Contracts
  3. Usual USD0++ Investment Vault

VaultRouter

High-Level Overview

The VaultRouter contract serves as an intermediary for interacting with the WrappedDollarVault. It facilitates deposits, withdrawals, and other operations by abstracting the complexities of approvals and token swaps. The router ensures that arbitrary tokens can be used as input, while the vault operates exclusively with USD-denominated ERC4626 tokens.

The router is tightly integrated with the WrappedDollarVault and requires registration via the setRouter() function in the vault. Only registered routers can interact with the vault, ensuring controlled access and preventing unauthorized operations.

The router implementation used by the investment vault aims to swap USD0++ to yield bearing token when depositing into the vault and swap back to USD0++ when withdrawing from the vault.

Contract Summary

The contract provides the following main functions:

  • deposit: Swaps arbitrary tokens for the vault's underlying asset and deposits them into the vault.

  • withdraw: Withdraws assets from the vault and swaps them for arbitrary tokens.

  • depositWithPermit: Allows gasless approval of tokens and deposits them into the vault.

  • withdrawWithPermit: Allows gasless approval of tokens and withdraw them from the vault.

Inherited Contracts

  • ReentrancyGuard: Prevents reentrancy attacks in critical functions.

  • Pausable: Enables emergency halt of contract operations.

Functionality Breakdown

1. Access Control and Security

  • Router Registration: The router must be registered with the vault via the setRouter() function. This ensures only authorized routers can interact with the vault.

  • Reentrancy Protection: All critical functions are protected against reentrancy attacks using the nonReentrant modifier.

2. Token Swapping

  • Arbitrary Token Support: The router integrates with external decentralized exchanges (DEXs) to swap arbitrary tokens for the vault's underlying asset. However in the current implementation we use paraswap.

  • Permit Support: Enables gasless approvals for tokens using the permit function, reducing friction for users.

3. Deposit and Withdrawal

  • Deposit: Users can deposit USD0++ or SUSDS tokens into the vault by swapping them for the vault underlying asset. The router handles the swap and deposit process seamlessly.

  • Withdraw: Users can withdraw assets from the vault and swap them for USD0++ tokens. The router ensures the correct amount of tokens is returned after fees.

4. Upgradability and Maintenance

  • Modular Design: The router is designed to work with any WrappedDollarVault vault, allowing flexibility for future upgrades.

  • VaultRouter: The contract can be paused and a new router can be setup in the Vault. this allow for easy upgrade.

Security Analysis

Method: Deposit

Swaps USD0++ or USDS tokens for the vault's underlying asset and deposits them into the vault. This function ensures that users can interact with the vault using arbitrary tokens, abstracting the complexity of token swaps.

function deposit(
        IParaSwapAugustus augustus,
        IERC20 tokenIn,
        uint256 amountIn,
        uint256 minTokensToReceive,
        uint256 minSharesToReceive,
        address receiver,
        bytes calldata swapData
    )
        public
        payable
        whenNotPaused
        nonReentrant
        returns (uint256 sharesReceived)
    {
        if (tokenIn != USD0PP && tokenIn != SUSDS) {
            revert InvalidInputToken(address(tokenIn));
        }
        if (receiver == address(0)) {
            revert NullAddress();
        }
        uint256 tokensAmount = _convertToTokens(
            augustus, tokenIn, amountIn, minTokensToReceive, swapData
        );

        sharesReceived = VAULT.deposit(tokensAmount, receiver);
        if (sharesReceived < minSharesToReceive) {
            revert InsufficientSharesReceived();
        }
        emit Deposit(receiver, address(tokenIn), amountIn, sharesReceived);
        return sharesReceived;
    }

Description

The deposit function allows users to deposit an ERC20 token into the vault by first swapping it for the vault's underlying asset using ParaSwap. The swapped assets are then deposited into the vault, and the user receives vault shares in return. This function ensures that users can interact with the vault using arbitrary tokens, abstracting the complexity of token swaps. The function is protected by a nonReentrant modifier to prevent reentrancy attacks during the swap and deposit process. It returns the number of vault shares minted and sent to the receiver.

16-21 Input Validation:

  • Ensures augustus, tokenIn, and receiver are valid addresses.

  • Ensures amountIn is greater than zero to prevent invalid deposits.

22-23 Swap Execution:

  • Interacts with ParaSwap to swap tokenIn for the vault's underlying asset using the provided swapData.

  • Ensures the received tokens meet or exceed minTokensToReceive, reverting if the condition is not met to protect users from unfavorable swaps.

26-29 Deposit Execution:

  • Deposits the swapped assets into the vault on behalf of the receiver.

  • Ensures the resulting vault shares meet or exceed minSharesToReceive, reverting if the condition is not met to protect users from unfavorable deposits.

30 Event Emission:

  • Emits a Deposit event with details of the operation, including the receiver, tokenIn, amountIn, and sharesReceived.


Method: depositWithPermit

Executes a permit before depositing it into the vault.

     function depositWithPermit(
        IParaSwapAugustus augustus,
        IERC20 tokenIn,
        uint256 amountIn,
        uint256 minTokensToReceive,
        uint256 minSharesToReceive,
        address receiver,
        bytes calldata swapData,
        PermitParams calldata permitParams
    )
        public
        whenNotPaused
        returns (uint256 sharesReceived)
    {
        try ERC20Permit(address(tokenIn)).permit(
            _msgSender(),
            address(this),
            permitParams.value,
            permitParams.deadline,
            permitParams.v,
            permitParams.r,
            permitParams.s
        ) { } catch { } // solhint-disable-line no-empty-blocks

        return deposit(
            augustus,
            tokenIn,
            amountIn,
            minTokensToReceive,
            minSharesToReceive,
            receiver,
            swapData
        );
    }

15-23 Permit Execution:

  • Uses the provided permitParams to approve the router for spending tokenIn without requiring a separate transaction.

25-32 Deposit Execution:

  • Deposits the swapped assets into the vault.

  • Ensures the resulting shares meet or exceed minSharesToReceive.


Method: withdraw

Withdraws assets from the vault and converts them to USD0++.

  function withdraw(
        IParaSwapAugustus augustus,
        uint256 assets,
        uint256 minUSD0ppToReceive,
        address receiver,
        bytes calldata swapData
    )
        public
        whenNotPaused
        nonReentrant
        returns (uint256 amountUSD0pp)
    {
        if (receiver == address(0)) {
            revert NullAddress();
        }

        VAULT.withdraw(assets, address(this), _msgSender());

        amountUSD0pp = _convertTokensToUSD0pp(
            augustus, assets, minUSD0ppToReceive, swapData
        );

        USD0PP.safeTransfer(receiver, amountUSD0pp);
        emit Withdraw(receiver, assets, amountUSD0pp);
        return amountUSD0pp;
    }

Description

The withdraw function allows users to withdraw assets from the vault and convert them to USD0++ using ParaSwap. The withdrawn assets are swapped for USD0++ and the resulting amount are sent to the specified receiver. It returns the amount of USD0PP received by the receiver.

13-15 Input Validation:

  • Ensures receiver is a valid addresses.

17 Withdrawal Execution:

  • Withdraws the specified assets from the vault.

19-20 Swap Execution:

  • Interacts with ParaSwap to swap the withdrawn assets for USD0++.

  • Ensures the received USD0++ meets or exceeds minUSD0ppToReceive.

24 Event Emission:

  • Emits a Withdraw event with details of the operation.


Method: withdrawWithPermit

Executes a permit and withdraws assets from the vault, converting them to USD0++.

function withdrawWithPermit(
    IParaSwapAugustus augustus,
    uint256 assets,
    uint256 minUSD0ppToReceive,
    address receiver,
    bytes calldata swapData,
    PermitParams calldata permitParams
) external returns (uint256 amountUSD0pp){
     try ERC20Permit(address(VAULT)).permit(
            _msgSender(),
            address(this),
            permitParams.value,
            permitParams.deadline,
            permitParams.v,
            permitParams.r,
            permitParams.s
        ) { } catch { } // solhint-disable-line no-empty-blocks

        return
            withdraw(augustus, assets, minUSD0ppToReceive, receiver, swapData);
    } 

9-17 Permit Execution:

  • Uses the provided permitParams to approve the router for spending vault shares without requiring a separate transaction.

19-20 Withdraw Execution

  • Call the vault's withdraw function

PreviousUsual USD0++ Investment VaultNextUtility Contracts

Last updated 1 month ago

Was this helpful?

⛓️