Skip to Content
docs

Aave V3 Advanced Market Features

Implement advanced Aave features in DeFi applications.

User Transaction History

Track user transaction history across Aave markets with detailed transaction information.

Use the useUserTransactionHistory hook in React, the userTransactionHistory action in TypeScript, or the userTransactionHistory query in GraphQL to fetch paginated transaction history for a user.

const { data, loading, error } = useUserTransactionHistory({
  market: EvmAddress,
  user: EvmAddress,
  chainId: ChainId,
  filter?: UserTransactionType[],
  orderBy?: UserTransactionHistoryRequestOrderBy,
  pageSize?: PageSize,
  cursor?: Cursor,
});

Fetch the history ordered by date, or filter it by transaction type.

import {
  useUserTransactionHistory,
  evmAddress,
  chainId,
  PageSize,
  OrderDirection,
} from "@aave/react";

// …

const { data, loading, error } = useUserTransactionHistory({
  market: evmAddress("0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2"),
  user: evmAddress("0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"),
  chainId: chainId(1),
  orderBy: { date: OrderDirection.Desc },
  pageSize: PageSize.Fifty,
});

if (loading) {
  return <p>Loading transaction history…</p>;
}

if (error) {
  return <p>Error: {error.message}</p>;
}

// data.items: UserTransactionItem[]
// data.pageInfo.next: Cursor | null
// data.pageInfo.prev: Cursor | null

Transaction Types

The user transaction history includes the following transaction types with their specific data:

  • SUPPLY - Asset supply transactions with amount and reserve information
  • WITHDRAW - Asset withdrawal transactions with amount and reserve information
  • BORROW - Asset borrowing transactions with amount and reserve information
  • REPAY - Debt repayment transactions with amount and reserve information
  • USAGE_AS_COLLATERAL - Collateral enable/disable transactions with enabled flag
  • LIQUIDATION_CALL - Liquidation transactions with collateral and debt repaid details

Filtering Options

Use the filter parameter to narrow down transaction results by transaction types:

TSX
filter: ["SUPPLY", "WITHDRAW"];

Available filter values: SUPPLY, WITHDRAW, BORROW, REPAY, USAGE_AS_COLLATERAL, LIQUIDATION_CALL

Ordering Options

Order transactions using the orderBy parameter:

  • date - Order by transaction date (ASC or DESC)

Efficiency Mode (E-Mode)

Efficiency Mode (E-Mode) in Aave optimizes borrowing power for price-correlated assets. This feature is particularly useful when both supplied and borrowed assets share similar economic price movements, such as stablecoins or derivatives that track the same underlying asset. By using E-Mode, users benefit from lower collateral requirements, effectively increasing their available borrowing capacity for correlated assets.

To enable efficiency mode and maximize capital efficiency for correlated assets, follow these steps.

1. Check Available E-Mode Categories

First, check the available E-Mode categories on the market to understand which category to enable.

Given the following market object with available E-Mode categories:

Market
const market: Market = {
  __typename: "Market",
  name: "Aave V3 Ethereum",
  address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
  chain: {
    __typename: "Chain",
    chainId: 1,
    name: "Ethereum",
    // …
  },
  eModeCategories: [
    {
      __typename: "EmodeMarketCategory",
      id: 1,
      label: "Stablecoins",
      maxLTV: {
        __typename: "PercentValue",
        value: "0.97",
        // …
      },
      liquidationThreshold: {
        __typename: "PercentValue",
        value: "0.975",
        // …
      },
      liquidationPenalty: {
        __typename: "PercentValue",
        value: "0.01",
        // …
      },
      reserves: [
        {
          __typename: "EmodeMarketReserveInfo",
          underlyingToken: {
            __typename: "Currency",
            symbol: "USDC",
            name: "USD Coin",
            address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
            // …
          },
          canBeCollateral: true,
          canBeBorrowed: true,
        },
        // … more reserves
      ],
      // …
    },
    // … more categories
  ],
  // …
};

Where each EmodeMarketCategory object has the following properties:

  • maxLTV.value - Maximum borrowing power (% of supplied collateral you can borrow)
  • liquidationThreshold.value - The debt-to-collateral ratio at which a position becomes liquidatable
  • liquidationPenalty.value - How much you lose if liquidation happens (lower = better)
  • reserves[] - an array of EmodeMarketReserveInfo objects, each representing a reserve that indicates if the asset can be used as collateral and/or borrowed in this specific E-Mode.

2. Prepare the Transaction Request

Next, we can proceed with creating the transaction request for the desired E-Mode operation. Use the useUserEMode hook in React, the userSetEmode action in TypeScript, or the userSetEmode query in GraphQL to create the transaction request for enabling or disabling efficiency mode.

import { useWalletClient } from "wagmi";
import { useUserEMode, evmAddress } from "@aave/react";

// …

const { data: walletClient } = useWalletClient();

const [setEmode, settingEmode] = useUserEMode();

const execute = async () => {
  const result = await setEmode({
    market: market.address,
    user: evmAddress(walletClient!.account.address),
    categoryId: 1, // Enable category 1 (Stablecoins)
    chainId: market.chain.chainId,
  });

  // …
};

3. Send the 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 { useUserEMode } from "@aave/react";
import { useSendTransaction } from "@aave/react/viem";

// …

const { data: walletClient } = useWalletClient();

const [setEmode, settingEmode] = useUserEMode();
const [sendTransaction, sending] = useSendTransaction(walletClient);

// …

// Optional: combine loading states
const loading = settingEmode.loading || sending.loading;
const error = settingEmode.error || sending.error;

// …

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

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

Liquidations

Liquidate undercollateralized positions to earn liquidation bonuses and help maintain protocol stability.

1. Identify an Undercollateralized Position

First, identify a target user with a health factor below 1.0, and one of their borrow positions that is eligible for liquidation.

TypeScript
const targetUser = evmAddress("0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234");

Given the following user borrow position:

MarketUserReserveBorrowPosition
const position: MarketUserReserveBorrowPosition = {
  __typename: "MarketUserReserveBorrowPosition",
  market: {
    __typename: "MarketInfo",
    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
    chain: { chainId: 1 },
    // …
  },
  currency: {
    __typename: "Currency",
    symbol: "WETH",
    name: "Wrapped Ether",
    address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
    // …
  },
  debt: {
    __typename: "TokenAmount",
    amount: {
      __typename: "DecimalValue",
      value: "1.5",
      raw: "1500000000000000000",
      decimals: 18,
      // …
    },
    // …
  },
  // …
};

Finding users with a health factor below 1.0 is out of scope for this guide.

2. Choose the Collateral to Receive

Next, choose which of the target user’s collateral assets to receive, including the liquidation bonus.

Given the following collateral position:

MarketUserReserveSupplyPosition
const collateral: MarketUserReserveSupplyPosition = {
  __typename: "MarketUserReserveSupplyPosition",
  market: {
    __typename: "MarketInfo",
    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
    chain: { chainId: 1 },
    // …
  },
  currency: {
    __typename: "Currency",
    symbol: "USDC",
    name: "USD Coin",
    address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    // …
  },
  isCollateral: true,
  canBeCollateral: true,
  // …
};

3. Prepare the Transaction Request

Then, create the transaction request for the liquidation operation. Use the useLiquidate hook in React, the liquidate action in TypeScript, or the liquidate query in GraphQL to create the transaction request for liquidating the undercollateralized position.

Liquidate Position
import { useLiquidate } from "@aave/react";

// …

const [liquidate, liquidating] = useLiquidate();

const execute = async () => {
  const result = await liquidate({
    chainId: position.market.chain.chainId,
    market: position.market.address,
    user: targetUser,
    underlyingToken: position.currency.address,
    debtToCover: { max: true }, // Liquidate maximum debt
    collateralToken: collateral.currency.address,
    receiveAToken: false, // Receive the underlying collateral token
  });

  // …
};

4. Send the Transaction

Finally, send the transaction to execute the liquidation.

  • 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 { useLiquidate } from "@aave/react";
import { useSendTransaction } from "@aave/react/viem";

// …

const { data: walletClient } = useWalletClient();

const [liquidate, liquidating] = useLiquidate();
const [sendTransaction, sending] = useSendTransaction(walletClient);

// …

// Optional: combine loading states
const loading = liquidating.loading || sending.loading;
const error = liquidating.error || sending.error;

// …

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

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