Skip to Content
docs

Aave V4 Reserves

Reserves define how a Hub Asset is supplied and borrowed within a specific Spoke.

Reserve Data Structure

Reserve data describes each asset’s lending and borrowing conditions:

  • Identification: IDs, spoke, chain
  • Underlying token information
  • Supply information: APY, liquidity, caps, collateral configuration
  • Borrow information: APY, available liquidity, utilization rates, caps
  • Reserve configuration: collateral factor, liquidation bonus, liquidation fee, collateral risk
  • Reserve status: frozen, paused
  • User incentives: extra APY and borrow discounts (see Incentive Programs)
  • User-specific state: balances, borrowable amounts, collateral usage (when user is specified in request)

The following TypeScript interfaces illustrate the core Reserve type:

interface Reserve {
  __typename: "Reserve";
  id: ReserveId;
  onChainId: OnChainReserveId;
  chain: Chain;
  spoke: Spoke;
  asset: HubAsset;
  summary: ReserveSummary;
  settings: ReserveSettings;
  status: ReserveStatus;
  canBorrow: boolean;
  canSupply: boolean;
  canUseAsCollateral: boolean;
  canSwapFrom: boolean;
  userState: ReserveUserState | null;
}

Listing Available Reserves

Discover all available reserves given some criteria.

Use the useReserves hook (or the imperative useReservesAction variant) in React, the reserves action in TypeScript, or the reserves query in GraphQL to fetch a list of reserves. In Solidity, reserves within a spoke are assigned sequential reserveId values. To retrieve all reserves within a spoke, first obtain the total reserve count and then loop through each reserveId.

import { type ReservesRequest, useReserves } from "@aave/react";

function ReservesList({ request }: { request: ReservesRequest }) {
  const { data, loading, error } = useReserves(request);

  if (loading) return <div>Loading…</div>;

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

  return (
    <div>
      {data.map((reserve) => (
        <div key={reserve.id}>
          <h3>{reserve.asset.underlying.info.name}</h3>
          <p>Spoke: {reserve.spoke.name}</p>
        </div>
      ))}
    </div>
  );
}

useReservesAction doesn’t watch for updates. Use it for on-demand fresh data, such as in an event handler.

You can query reserves by different criteria. In GraphQL, use the query field to select them.

import { chainId } from "@aave/react";

const request: ReservesRequest = {
  query: {
    chainIds: [chainId(1)],
  },
};

Filter reserves by supply, borrow, or collateral.

import { ReservesRequestFilter } from "@aave/react";

// …

const request: ReservesRequest = {
  query: {
    // your query criteria
  },
  filter: ReservesRequestFilter.Supply,
};

Add a user address to return ReserveUserState for each reserve.

Reserves User State
import { evmAddress } from "@aave/react";

// …

const request: ReservesRequest = {
  query: {
    // your query criteria
  },
  user: evmAddress("0x456…"),
};

Sort reserves by asset name, user balance, APYs, collateral factor, or available amounts.

import { OrderDirection } from "@aave/react";

// …

const request: ReservesRequest = {
  query: {
    // your query criteria
  },
  orderBy: { assetName: OrderDirection.Asc },
};

In React and TypeScript, specify a different currency to return fiat amounts in.

import { Currency } from "@aave/react";

// …

const { data, error, loading } = useReserves({
  query: {
    // your query criteria
  },
  currency: Currency.Eur,
});

Fetching a Single Reserve

Get detailed information about a specific reserve.

Use the useReserve hook in React, the reserve action in TypeScript, or the reserve query in GraphQL to fetch a specific reserve.

import { type ReserveRequest, useReserve } from "@aave/react";

function ReserveDetails({ request }: { request: ReserveRequest }) {
  const { data, loading, error } = useReserve(request);

  if (loading) return <p>Loading reserve…</p>;

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

  if (!data) return <p>Reserve not found</p>;

  return (
    <div>
      <h2>Reserve ID: {data.id}</h2>
      <p>Supply APY: {data.summary.supplyApy.normalized.toFixed(2)}%</p>
      <p>Borrow APY: {data.summary.borrowApy.normalized.toFixed(2)}%</p>
    </div>
  );
}

See below for examples of ReserveRequest objects.

import { chainId, evmAddress, type OnChainReserveId } from "@aave/react";

const request: ReserveRequest = {
  query: {
    reserveInput: {
      chainId: chainId(1),
      spoke: evmAddress("0x123…"),
      onChainId: "1" as OnChainReserveId,
    },
  },
};

Finally, in React, you can specify a different time window or currency for the data.

import { TimeWindow } from "@aave/react";

const { data, loading, error } = useReserve({
  query: {
    // your query criteria
  },
  timeWindow: TimeWindow.LastWeek,
});

Borrow APY History

Fetch historical borrow APY data for a specific reserve. By default, Merkl rewards are included in the returned rates; pass includeRewards: false for protocol base rates only.

Use the useBorrowApyHistory hook in React, the borrowApyHistory action in TypeScript, or the borrowApyHistory query in GraphQL to fetch historical borrow APY data.

import { type BorrowApyHistoryRequest, useBorrowApyHistory } from "@aave/react";

function BorrowApy({ request }: { request: BorrowApyHistoryRequest }) {
  const { data, loading, error } = useBorrowApyHistory(request);

  if (loading) return <div>Loading…</div>;

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

  return (
    <div>
      {data.map((sample) => (
        <div key={sample.date.toString()}>
          <p>
            <small>{sample.date.toLocaleDateString()}</small>
            {sample.avgRate.normalized.toFixed(2)}%
          </p>
        </div>
      ))}
    </div>
  );
}

See below for examples of BorrowApyHistoryRequest objects.

import { TimeWindow } from "@aave/react";

const request: BorrowApyHistoryRequest = {
  reserve: reserve.id,
  window: TimeWindow.LastDay,
};

Supply APY History

Fetch historical supply APY data for a specific reserve. By default, Merkl rewards are included in the returned rates; pass includeRewards: false for protocol base rates only.

Use the useSupplyApyHistory hook in React, the supplyApyHistory action in TypeScript, or the supplyApyHistory query in GraphQL to fetch historical supply APY data.

import { type SupplyApyHistoryRequest, useSupplyApyHistory } from "@aave/react";

function SupplyApy({ request }: { request: SupplyApyHistoryRequest }) {
  const { data, loading, error } = useSupplyApyHistory(request);

  if (loading) return <div>Loading…</div>;

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

  return (
    <div>
      {data.map((sample) => (
        <div key={sample.date.toString()}>
          <p>
            <small>{sample.date.toLocaleDateString()}</small>
            {sample.avgRate.normalized.toFixed(2)}%
          </p>
        </div>
      ))}
    </div>
  );
}

See below for examples of SupplyApyHistoryRequest objects.

import { TimeWindow } from "@aave/react";

const request: SupplyApyHistoryRequest = {
  reserve: reserve.id,
  window: TimeWindow.LastDay,
};

Reserve Holders

Fetch a paginated list of the top holders for a specific reserve, filtered by suppliers or borrowers.

Use the useReserveHolders hook in React, the reserveHolders action in TypeScript, or the reserveHolders query in GraphQL to fetch holders for a specific reserve.

import { ReserveHoldersFilter, useReserveHolders } from "@aave/react";

function ReserveHoldersList({ reserveId }: { reserveId: string }) {
  const { data, loading, error } = useReserveHolders({
    reserve: { reserveId },
    filter: ReserveHoldersFilter.Supplied,
  });

  if (loading) return <div>Loading…</div>;

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

  return (
    <div>
      {data.items.map((holder) => (
        <div key={holder.address}>
          <p>{holder.address}</p>
          <p>
            {holder.amount.amount.value.toFixed(4)}{" "}
            {holder.amount.token.info.symbol}
          </p>
          <p>{holder.weight.normalized.toFixed(4)}%</p>
        </div>
      ))}
    </div>
  );
}

Filter by ReserveHoldersFilter.Supplied (default) or ReserveHoldersFilter.Borrowed. In GraphQL, provide these as query variables.

import { ReserveHoldersFilter, useReserveHolders } from "@aave/react";

const { data } = useReserveHolders({
  reserve: { reserveId: reserve.id },
  filter: ReserveHoldersFilter.Supplied,
});

Results are paginated. Use pageSize (PageSize.Ten by default, or PageSize.Fifty) and pass pageInfo.next as cursor to fetch the next page.

Pagination
import { PageSize, useReserveHolders } from "@aave/react";

const { data } = useReserveHolders({
  reserve: { reserveId: reserve.id },
  pageSize: PageSize.Fifty,
  cursor: previousPage.pageInfo.next,
});