Skip to Content
docs

Aave Simple Earn Vault Operations

Execute core vault operations such as deposits and withdrawals. Users can choose to interact with the vault using either the asset amount deposited or the vault shares minted.

Shares start at a 1:1 ratio when the vault launches. As the vault earns interest, each share is worth more of the underlying asset, so a deposit mints fewer shares than the assets it adds.

Identify the Vault

Fetch the vault with the user address to populate userShares. This page uses the following vault in its examples:

Vault
const vault: Vault = {
  __typename: "Vault",
  address: "0x1234567890abcdef1234567890abcdef12345678",
  shareName: "Aave USDC Vault Shares",
  shareSymbol: "avUSDC",
  chainId: 1,
  usedReserve: {
    __typename: "Reserve",
    underlyingToken: {
      __typename: "Currency",
      symbol: "USDC",
      name: "USD Coin",
      address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      // …
    },
    isFrozen: false,
    isPaused: false,
    // …
  },
  userShares: {
    __typename: "UserVaultShares",
    shares: {
      __typename: "TokenAmount",
      amount: {
        __typename: "DecimalValue",
        value: "1000.0", // User has 1000 vault shares
        // …
      },
      // …
    },
    // …
  },
  // …
};

Deposits and mints need the reserve not frozen and not paused. Withdrawals and redeems need it not paused.

Deposit Assets

Depositing assets into an Aave Simple Earn Vault gives the user an amount of vault shares.

To deposit assets into an Aave Simple Earn Vault, follow these steps.

1. Preview the Deposit

First, preview the deposit operation to determine the amount of vault shares that would be received for a given amount of assets. Use the useVaultDepositPreview hook in React, the vaultPreviewDeposit action in TypeScript, or the vaultPreviewDeposit query in GraphQL to preview the deposit operation.

Preview the Deposit
import { bigDecimal, useVaultDepositPreview } from "@aave/react";

// …

const [preview /* , { loading, error } */] = useVaultDepositPreview();

// …

const result = await preview({
  vault: vault.address,
  chainId: vault.chainId,
  amount: bigDecimal(1000), // 1000 USDC
});

// …

if (result.isErr()) {
  console.error(result.error);
} else {
  // result.value: TokenAmount
  console.log(result.value.amount.value); // 975.13408 (shares to receive)
}

2. Prepare the Deposit Execution Plan

Next, create the execution plan for the deposit operation. Use the useVaultDeposit hook in React, the vaultDeposit action in TypeScript, or the vaultDeposit query in GraphQL to create the execution plan for depositing assets into a vault.

Deposits the underlying asset by default. Set asAToken to true to deposit the aToken instead.

Deposit Assets
import { useWalletClient } from "wagmi";
import { useVaultDeposit, bigDecimal, evmAddress } from "@aave/react";

// …

const { data: walletClient } = useWalletClient();

const [deposit, depositing] = useVaultDeposit();

const execute = async () => {
  const result = await deposit({
    chainId: vault.chainId,
    vault: vault.address,
    amount: {
      value: bigDecimal(1000), // 1000 USDC
      // Optional: If set to true, the aToken associated with the vault will be deposited
      // asAToken: false (default)
    },
    depositor: evmAddress(walletClient!.account.address),
  });

  // …
};

3. Process the Deposit Execution Plan

Finally, handle the execution plan.

  • React: Use the useSendTransaction hook for the wallet library of your choice to send the transactions in the execution plan.
  • TypeScript: Use sendWith for your chosen wallet library to send the transactions in the execution plan, and await indexing with client.waitForTransaction.
Viem
import { useWalletClient } from "wagmi";
import { errAsync, useVaultDeposit } from "@aave/react";
import { useSendTransaction } from "@aave/react/viem";

// …

const { data: walletClient } = useWalletClient();

const [deposit, depositing] = useVaultDeposit();
const [sendTransaction, sending] = useSendTransaction(walletClient);

// …

const loading = depositing.loading || sending.loading;
const error = depositing.error || sending.error;

// …

const execute = async () => {
  const result = await deposit({
    // …
  }).andThen((plan) => {
    switch (plan.__typename) {
      case "TransactionRequest":
        // Single transaction execution
        return sendTransaction(plan);

      case "ApprovalRequired":
        // Approval + transaction sequence
        return sendTransaction(plan.approval).andThen(() =>
          sendTransaction(plan.originalTransaction)
        );

      case "InsufficientBalanceError":
        return errAsync(
          new Error(`Insufficient balance: ${plan.required.value} required.`)
        );
    }
  });

  if (result.isErr()) {
    console.error("Deposit failed:", result.error);
  } else {
    console.log("Deposit successful with hash:", result.value);
  }
};

In GraphQL, if the response is a TransactionRequest, you can send it directly using the wallet associated with the from address.

TransactionRequest
{
  "data": {
    "vaultDeposit": {
      "to": "0x1234567890abcdef1234567890abcdef12345678",
      "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
      "data": "0x6e553f65000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
      "value": "0",
      "chainId": 1,
      "operation": "VAULT_DEPOSIT"
    }
  }
}

If the response is an ApprovalRequired, you must first send the approval transaction. Once it succeeds, you can then send the originalTransaction.

ApprovalRequired
{
  "data": {
    "vaultDeposit": {
      "__typename": "ApprovalRequired",
      "reason": "Insufficient allowance for ERC-20 token transfer",
      "requiredAmount": {
        "value": "1000.0",
        "decimals": 6
      },
      "currentAllowance": {
        "value": "0.0",
        "decimals": 6
      },
      "approval": {
        "to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
        "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
        "data": "0x095ea7b3000000000000000000000000123456789…",
        "value": "0",
        "chainId": 1,
        "operation": null
      },
      "originalTransaction": {
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
        "data": "0x6e553f65000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
        "value": "0",
        "chainId": 1,
        "operation": "VAULT_DEPOSIT"
      }
    }
  }
}

If the response is an InsufficientBalanceError, inform the user that they don’t have enough balance to deposit the requested amount.

InsufficientBalanceError
{
  "data": {
    "vaultDeposit": {
      "__typename": "InsufficientBalanceError",
      "required": {
        "value": "1000.0",
        "decimals": 6
      },
      "available": {
        "value": "750.0",
        "decimals": 6
      }
    }
  }
}

Mint Vault Shares

Minting vault shares is the process of creating new vault shares by depositing assets into the vault.

To mint vault shares, follow these steps.

1. Preview the Mint

First, preview the mint operation to determine the amount of assets needed to mint the requested amount of vault shares. Use the useVaultMintPreview hook in React, the vaultPreviewMint action in TypeScript, or the vaultPreviewMint query in GraphQL to preview the mint operation.

Preview the Mint
import { bigDecimal, useVaultMintPreview } from "@aave/react";

// …

const [preview /* , { loading, error } */] = useVaultMintPreview();

// …

const result = await preview({
  vault: vault.address,
  chainId: vault.chainId,
  amount: bigDecimal(1000), // 1000 vault shares
});

// …

if (result.isErr()) {
  console.error(result.error);
} else {
  // result.value: TokenAmount
  console.log(result.value.amount.value); // 1025.5 (assets needed)
}

2. Prepare the Mint Execution Plan

Next, create the execution plan for the mint shares operation. Use the useVaultMintShares hook in React, the vaultMintShares action in TypeScript, or the vaultMintShares query in GraphQL to create the execution plan for minting vault shares.

Mint Shares
import { useWalletClient } from "wagmi";
import { useVaultMintShares, bigDecimal, evmAddress } from "@aave/react";

// …

const { data: walletClient } = useWalletClient();

const [mintShares, minting] = useVaultMintShares();

const execute = async () => {
  const result = await mintShares({
    chainId: vault.chainId,
    vault: vault.address,
    shares: {
      amount: bigDecimal(1000), // 1000 vault shares
    },
    minter: evmAddress(walletClient!.account.address),
    // sharesRecipient: evmAddress("0x1234…"), if different from minter
  });

  // …
};

3. Process the Mint Execution Plan

Finally, handle the execution plan.

  • React: Use the useSendTransaction hook for the wallet library of your choice to send the transactions in the execution plan.
  • TypeScript: Use sendWith for your chosen wallet library to send the transactions in the execution plan, and await indexing with client.waitForTransaction.
Viem
import { useWalletClient } from "wagmi";
import { errAsync, useVaultMintShares } from "@aave/react";
import { useSendTransaction } from "@aave/react/viem";

// …

const { data: walletClient } = useWalletClient();

const [mintShares, minting] = useVaultMintShares();
const [sendTransaction, sending] = useSendTransaction(walletClient);

// …

const loading = minting.loading || sending.loading;
const error = minting.error || sending.error;

// …

const execute = async () => {
  const result = await mintShares({
    // …
  }).andThen((plan) => {
    switch (plan.__typename) {
      case "TransactionRequest":
        // Single transaction execution
        return sendTransaction(plan);

      case "ApprovalRequired":
        // Approval + transaction sequence
        return sendTransaction(plan.approval).andThen(() =>
          sendTransaction(plan.originalTransaction)
        );

      case "InsufficientBalanceError":
        return errAsync(
          new Error(`Insufficient balance: ${plan.required.value} required.`)
        );
    }
  });

  if (result.isErr()) {
    console.error("Mint shares failed:", result.error);
  } else {
    console.log("Mint shares successful with hash:", result.value);
  }
};

In GraphQL, if the response is a TransactionRequest, you can send it directly using the wallet associated with the from address.

TransactionRequest
{
  "data": {
    "vaultMintShares": {
      "to": "0x1234567890abcdef1234567890abcdef12345678",
      "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
      "data": "0x94bf804d000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
      "value": "0",
      "chainId": 1,
      "operation": "VAULT_DEPOSIT"
    }
  }
}

If the response is an ApprovalRequired, you must first send the approval transaction. Once it succeeds, you can then send the originalTransaction.

ApprovalRequired
{
  "data": {
    "vaultMintShares": {
      "__typename": "ApprovalRequired",
      "reason": "Insufficient allowance for ERC-20 token transfer",
      "requiredAmount": {
        "value": "1025.5",
        "decimals": 6
      },
      "currentAllowance": {
        "value": "0.0",
        "decimals": 6
      },
      "approval": {
        "to": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
        "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
        "data": "0x095ea7b3000000000000000000000000123456789…",
        "value": "0",
        "chainId": 1,
        "operation": null
      },
      "originalTransaction": {
        "to": "0x1234567890abcdef1234567890abcdef12345678",
        "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
        "data": "0x94bf804d000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
        "value": "0",
        "chainId": 1,
        "operation": "VAULT_DEPOSIT"
      }
    }
  }
}

If the response is an InsufficientBalanceError, inform the user that they don’t have enough balance to mint the requested amount of shares.

InsufficientBalanceError
{
  "data": {
    "vaultMintShares": {
      "__typename": "InsufficientBalanceError",
      "required": {
        "value": "1025.5",
        "decimals": 6
      },
      "available": {
        "value": "750.0",
        "decimals": 6
      }
    }
  }
}

Withdraw Assets

Withdrawing assets from an Aave Simple Earn Vault gives the user an amount of assets. The corresponding amount of vault shares is burned.

To withdraw assets from an Aave Simple Earn Vault, follow these steps.

1. Preview the Withdraw

First, preview the withdraw operation to determine the amount of shares that will be burned for a given amount of assets. Use the useVaultWithdrawPreview hook in React, the vaultPreviewWithdraw action in TypeScript, or the vaultPreviewWithdraw query in GraphQL to preview the withdraw operation.

Preview the Withdraw
import { bigDecimal, useVaultWithdrawPreview } from "@aave/react";

// …

const [preview /* , { loading, error } */] = useVaultWithdrawPreview();

// …

const result = await preview({
  vault: vault.address,
  chainId: vault.chainId,
  amount: bigDecimal(1000), // 1000 USDC
});

// …

if (result.isErr()) {
  console.error(result.error);
} else {
  // result.value: TokenAmount
  console.log(result.value.amount.value); // 975.134081 (shares to burn)
}

2. Prepare the Withdraw Transaction

Next, create the transaction request for the withdrawal operation. Use the useVaultWithdraw hook in React, the vaultWithdraw action in TypeScript, or the vaultWithdraw query in GraphQL to create the transaction request for withdrawing assets from a vault.

Withdraws the underlying asset by default. Set asAToken to true to withdraw the aToken instead.

Withdraw Assets
import { useWalletClient } from "wagmi";
import { useVaultWithdraw, bigDecimal, evmAddress } from "@aave/react";

// …

const { data: walletClient } = useWalletClient();

const [withdraw, withdrawing] = useVaultWithdraw();

const execute = async () => {
  const result = await withdraw({
    chainId: vault.chainId,
    vault: vault.address,
    amount: {
      value: bigDecimal(500), // 500 USDC
      // Optional: If set to true, the aToken associated with the vault will be withdrawn
      // asAToken: false (default)
    },
    sharesOwner: evmAddress(walletClient!.account.address),
    // recipient: evmAddress("0x1234…"), if different from sharesOwner
  });

  // …
};

3. Send the Withdraw Transaction

Finally, send the transaction.

  • React: Use the useSendTransaction hook for the wallet library of your choice to send the transaction.
  • TypeScript: Use sendWith for your chosen wallet library to initiate the transaction, and await indexing with client.waitForTransaction.
  • GraphQL: The response is a TransactionRequest that can be sent directly using the wallet associated with the from address.
Viem
import { useWalletClient } from "wagmi";
import { useVaultWithdraw } from "@aave/react";
import { useSendTransaction } from "@aave/react/viem";

// …

const { data: walletClient } = useWalletClient();

const [withdraw, withdrawing] = useVaultWithdraw();
const [sendTransaction, sending] = useSendTransaction(walletClient);

const loading = withdrawing.loading || sending.loading;
const error = withdrawing.error || sending.error;

// …

const execute = async () => {
  const result = await withdraw({
    // …
  }).andThen(sendTransaction);

  if (result.isErr()) {
    console.error("Withdrawal failed:", result.error);
  } else {
    console.log("Withdrawal successful with hash:", result.value);
  }
};

Redeem Vault Shares

Redeeming vault shares is the process of burning vault shares and receiving the underlying assets.

To redeem vault shares, follow these steps.

1. Preview the Redeem

First, preview the redeem operation to determine the amount of assets that will be received for a given amount of shares burned. Use the useVaultRedeemPreview hook in React, the vaultPreviewRedeem action in TypeScript, or the vaultPreviewRedeem query in GraphQL to preview the redeem operation.

Preview the Redeem
import { bigDecimal, useVaultRedeemPreview } from "@aave/react";

// …

const [preview /* , { loading, error } */] = useVaultRedeemPreview();

// …

const result = await preview({
  vault: vault.address,
  chainId: vault.chainId,
  amount: bigDecimal(1000), // 1000 vault shares
});

// …

if (result.isErr()) {
  console.error(result.error);
} else {
  // result.value: TokenAmount
  console.log(result.value.amount.value); // 1025.5 (assets to receive)
}

2. Prepare the Redeem Transaction

Next, create the transaction request for the redeem operation. Use the useVaultRedeemShares hook in React, the vaultRedeemShares action in TypeScript, or the vaultRedeemShares query in GraphQL to create the transaction request for redeeming vault shares.

Redeem Shares
import { useWalletClient } from "wagmi";
import { useVaultRedeemShares, bigDecimal, evmAddress } from "@aave/react";

// …

const { data: walletClient } = useWalletClient();

const [redeemShares, redeeming] = useVaultRedeemShares();

const execute = async () => {
  const result = await redeemShares({
    chainId: vault.chainId,
    vault: vault.address,
    shares: {
      amount: bigDecimal(1000), // 1000 vault shares
    },
    sharesOwner: evmAddress(walletClient!.account.address),
    // recipient: evmAddress("0x1234…"), if different from sharesOwner
  });

  // …
};

3. Send the Redeem Transaction

Finally, send the transaction.

  • React: Use the useSendTransaction hook for the wallet library of your choice to send the transaction.
  • TypeScript: Use sendWith for your chosen wallet library to initiate the transaction, and await indexing with client.waitForTransaction.
  • GraphQL: The response is a TransactionRequest that can be sent directly using the wallet associated with the from address.
Viem
import { useWalletClient } from "wagmi";
import { useVaultRedeemShares } from "@aave/react";
import { useSendTransaction } from "@aave/react/viem";

// …

const { data: walletClient } = useWalletClient();

const [redeemShares, redeeming] = useVaultRedeemShares();
const [sendTransaction, sending] = useSendTransaction(walletClient);

const loading = redeeming.loading || sending.loading;
const error = redeeming.error || sending.error;

// …

const execute = async () => {
  const result = await redeemShares({
    // …
  }).andThen(sendTransaction);

  if (result.isErr()) {
    console.error("Redeem shares failed:", result.error);
  } else {
    console.log("Redeem shares successful with hash:", result.value);
  }
};