Vault Wrapper

If you would like to offer existing IPOR Vault to your customers and be compensated by charging fees, you can use a Vault Wrapper.

Plasma Vault Wrapper allows to charge fees on top of existing vaults and is compatible with every vault that allows for instant withdraw.

You can find ready contract here:

Unexpected error with integration github-files: Integration is not installed on this space

With a corresponding test file:

Unexpected error with integration github-files: Integration is not installed on this space

Quick Start

  • Identify the address of the vault you want to wrap. It can be found on the vault page on the https://app.ipor.io website.

  • Select the WrapperName (ERC20 standard)

  • Select the Ticker (ERC20 standard)

  • Appoint feeAccount - address that will claim the fees

  • select feePercentage for both performance and management fees

    • Fee is defined with 2 decimal places (10000 = 100%)

    • Contract hard caps the fee at 5% for management and 50% on performance

Construct the vault:

wPlasmaVault = new WrappedPlasmaVault(usdc, "WrapperName", "Ticker", address(plasmaVault));
wPlasmaVault.configurePerformanceFee(feeAccount, feePercentage);
wPlasmaVault.configureManagementFee(feeAccount, feePercentage);

Shares

Wrapper itself is a ERC4626 vault and emits it's own shares. Those shares are minted and burned along the shares of underlying vault.

Depositing/Minting and Withdrawing/Redeeming

The Interface allows to define amount of underlying asset to be deposited:

function deposit(
    uint256 assets, 
    address receiver
)

or number of shares to be minted:

function mint(
    uint256 shares, 
    address receiver
)

Likewise, to exit the position, user can either appoint amount of underlying asset to be withdrawn:

function withdraw(
        uint256 assets,
        address receiver,
        address owner
)

or number of shares to be redeemed:

function redeem(
        uint256 shares,
        address receiver,
        address owner
)

Checking the vault share price

As the vault accrue interest, the price of the share accounted in the underlying token changes.

It's important to know that the exchange rate is not updated constantly but rather with every rebalance the amount off assets held in a particular market is updated.

If you would like to simulate the exchange as if the balance was updated you can manually recalculate the cache by dry running update markets and convertToAssets inside of the multicall. Below you can find an example how to do it using JavaScript;

import { Address, PublicClient } from 'viem';
import { plasmaVaultAbi } from 'fusion/plasmaVault/abi/plasmaVaultAbi';
import { MARKET_ID_VALUE } from 'fusion/marketId/marketId';

// Public client helds the chainId
declare const publicClient: PublicClient;

// List of ALL markets that vaults uses
const marketIds: bigint[] = [
  MARKET_ID_VALUE.AAVE_V3,
  MARKET_ID_VALUE.FLUID_INSTADAPP_POOL,
  MARKET_ID_VALUE.FLUID_INSTADAPP_STAKING,
];

export const readTvl = async (address: Address) => {
  const results = await publicClient.multicall({
    contracts: [
      // updateMarketsBalances before to get totalAssets with accrued interest in the markets
      {
        address,
        abi: plasmaVaultAbi,
        functionName: 'updateMarketsBalances',
        args: [marketIds],
      },
      {
        address,
        abi: plasmaVaultAbi,
        functionName: 'convertToAssets',
        args: 1,
      },
    ],
  });

  // We want the totalAssets result
  return results[1].result;
};

Administration

The deployer of the contract becomes the owner automatically. The owner can run the administrative actions, like changing fees or transferring ownership to another account.

Claiming fees

The address appointed as feeAccount will receive fees as shares in the vault. Those shares can be redeemed for the underlying asset of the vault. Simply run theredeem/withdraw function.

Setting fees

function configureManagementFee(
    address feeAccount_, 
    uint256 feeInPercentage_
)
function configurePerformanceFee(
    address feeAccount_, 
    uint256 feeInPercentage_
)

Transferring ownership

The ownership of the wrapper can be made by executing 2-step transfer process:

function transferOwnership(
    address newOwner
)

And as a new owner

function acceptOwnership()

Changing feeAccount

You can change the account that can claim fees along with setting the fee rate.

function configurePerformanceFee(
    address feeAccount, 
    uint256 feeInPercentage
)

Last updated