# 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](./incentives))
- User-specific state: balances, borrowable amounts, collateral usage (when user is specified in request)

<tabgroup>
<tab label="TypeScript">

The following TypeScript interfaces illustrate the core Reserve type:

```ts title="Reserve"
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;
}
```

```ts title="ReserveSummary"
interface ReserveSummary {
  __typename: "ReserveSummary";
  supplied: Erc20Amount;
  borrowed: Erc20Amount;
  supplyApy: PercentNumber;
  borrowApy: PercentNumber;
  rewards: Reward[];
}
```

```ts title="ReserveSettings"
interface ReserveSettings {
  __typename: "ReserveSettings";
  collateralFactor: PercentNumber;
  maxLiquidationBonus: PercentNumber;
  liquidationFee: PercentNumber;
  collateralRisk: PercentNumber;
  borrowable: boolean;
  collateral: boolean;
  suppliable: boolean;
  receiveSharesEnabled: boolean;
  latestDynamicConfigKey: DynamicConfigKey;
  borrowCap: Erc20Amount;
  supplyCap: Erc20Amount;
}
```

```ts title="ReserveStatus"
interface ReserveStatus {
  __typename: "ReserveStatus";
  frozen: boolean;
  paused: boolean;
  active: boolean;
}
```

```ts title="ReserveUserState"
interface ReserveUserState {
  __typename: "ReserveUserState";
  balance: Erc20Amount;
  suppliable: Erc20Amount;
  borrowable: Erc20Amount;
  borrowApy: PercentNumber;
  collateralFactor: PercentNumber;
  maxLiquidationBonus: PercentNumber;
  liquidationFee: PercentNumber;
  dynamicConfigKey: DynamicConfigKey;
}
```

</tab>
<tab label="GraphQL">

The following GraphQL fragments illustrate the core Reserve type:

```graphql title="Reserve"
fragment Reserve on Reserve {
  __typename
  id
  onChainId
  spoke {
    ...Spoke
  }
  chain {
    ...Chain
  }
  summary {
    ...ReserveSummary
  }
  settings {
    ...ReserveSettings
  }
  status {
    ...ReserveStatus
  }
  canBorrow
  canSupply
  canUseAsCollateral
  canSwapFrom
  userState {
    ...ReserveUserState
  }
  asset {
    ...HubAsset
  }
}
```

```graphql title="ReserveSummary"
fragment ReserveSummary on ReserveSummary {
  __typename
  supplied {
    ...Erc20Amount
  }
  borrowed {
    ...Erc20Amount
  }
  supplyApy {
    ...PercentNumber
  }
  borrowApy {
    ...PercentNumber
  }
  rewards {
    ...Reward
  }
}
```

```graphql title="ReserveSettings"
fragment ReserveSettings on ReserveSettings {
  __typename
  collateralFactor {
    ...PercentNumber
  }
  maxLiquidationBonus {
    ...PercentNumber
  }
  liquidationFee {
    ...PercentNumber
  }
  collateralRisk {
    ...PercentNumber
  }
  borrowable
  collateral
  suppliable
  receiveSharesEnabled
  latestDynamicConfigKey
  borrowCap {
    ...Erc20Amount
  }
  supplyCap {
    ...Erc20Amount
  }
}
```

```graphql title="ReserveStatus"
fragment ReserveStatus on ReserveStatus {
  __typename
  frozen
  paused
  active
}
```

```graphql title="ReserveUserState"
fragment ReserveUserState on ReserveUserState {
  __typename
  balance {
    ...Erc20Amount
  }
  suppliable {
    ...Erc20Amount
  }
  borrowable {
    ...Erc20Amount
  }
  borrowApy {
    ...PercentNumber
  }
  collateralFactor {
    ...PercentNumber
  }
  maxLiquidationBonus {
    ...PercentNumber
  }
  liquidationFee {
    ...PercentNumber
  }
  dynamicConfigKey
}
```

</tab>
<tab label="Solidity">

Reserves live inside the spoke contract and are exposed through the `ISpoke` interface. Each reserve stores links back to its Hub Asset plus configuration flags that control supply, borrow, and collateral behavior. Dynamic parameters such as collateral factor or liquidation bonus are kept in dedicated structs.

```solidity title="Reserve Struct"
struct Reserve {
  address underlying;
  IHubBase hub;
  uint16 assetId;
  uint8 decimals;
  uint24 collateralRisk;
  ReserveFlags flags;
  uint32 dynamicConfigKey;
}
```

```solidity title="ReserveConfig Struct"
struct ReserveConfig {
  uint24 collateralRisk;
  bool paused;
  bool frozen;
  bool borrowable;
  bool receiveSharesEnabled;
}
```

```solidity title="DynamicReserveConfig Struct"
struct DynamicReserveConfig {
  uint16 collateralFactor;
  uint32 maxLiquidationBonus;
  uint16 liquidationFee;
}
```

</tab>
</tabgroup>
## 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`.

<tabgroup>
<tab label="React">

```tsx title="Loading State"
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>
          Spoke: {reserve.spoke.name}
        </div>
      ))}
    </div>
  );
}
```

```tsx title="React Suspense"
import { type ReservesRequest, useReserves } from "@aave/react";

function ReservesList({ request }: { request: ReservesRequest }) {
  const { data } = useReserves({
    ...request,
    suspense: true,
  });

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

```tsx title="Imperative Read"
import { type ReservesRequest, useReservesAction } from "@aave/react";

// …

const [fetch, { called, data, error, loading }] = useReservesAction();

const handler = async (request: ReservesRequest) => {
  const result = await fetch(request);

  if (result.isOk()) {
    console.log(result.value); // Reserve[]
  } else {
    console.error(result.error);
  }
};
```

</tab>
<tab label="TypeScript">

```ts title="Reserves"
import { chainId } from "@aave/client";
import { reserves } from "@aave/client/actions";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    chainIds: [chainId(1)],
  },
});

if (result.isOk()) {
  console.log(result.value); // Reserve[]
} else {
  console.error(result.error);
}
```

```ts title="client.ts"
import { AaveClient } from "@aave/client";

export const client = AaveClient.create();
```

</tab>
<tab label="GraphQL">

```graphql title="Query"
query ($request: ReservesRequest!) {
  value: reserves(request: $request) {
    ...Reserve
  }
}
```

</tab>
<tab label="Solidity">

```solidity title="Get All Spoke Reserves"
import { ISpoke } from "aave-v4/src/spoke/interfaces/ISpoke.sol";

contract SpokeReader {
  function getSpokeReserves(
    address spokeAddress
  ) external view returns (ISpoke.Reserve[] memory) {
    ISpoke spoke = ISpoke(spokeAddress);
    uint256 reserveCount = spoke.getReserveCount();

    ISpoke.Reserve[] memory reserves = new ISpoke.Reserve[](reserveCount);

    for (uint256 reserveId = 0; reserveId < reserveCount; reserveId++) {
      reserves[reserveId] = spoke.getReserve(reserveId);
    }

    return reserves;
  }
}
```

</tab>
</tabgroup>
> [!NOTE]
> `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.

<tabgroup>
<tab label="React">

```tsx title="By Chains"
import { chainId } from "@aave/react";

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

```tsx title="By Tokens"
import { evmAddress, chainId } from "@aave/react";

const request: ReservesRequest = {
  query: {
    tokens: [
      {
        address: evmAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC
        chainId: chainId(1),
      },
      {
        address: evmAddress("0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f"), // GHO
        chainId: chainId(1),
      },
    ],
  },
};
```

```tsx title="By Spoke Token"
import { evmAddress } from "@aave/react";

const request: ReservesRequest = {
  query: {
    spokeToken: {
      spoke: spoke.id, // spoke: Spoke
      token: evmAddress("0x123…"),
    },
  },
};
```

```tsx title="By Hub Token"
import { evmAddress, chainId } from "@aave/react";

const request: ReservesRequest = {
  query: {
    hubToken: {
      chainId: chainId(1),
      hub: evmAddress("0x456…"),
      token: evmAddress("0x123…"),
    },
  },
};
```

```tsx title="By Hub ID"
const request: ReservesRequest = {
  query: {
    hubId: hub.id, // hub: Hub
  },
};
```

```tsx title="By Hub Address"
import { evmAddress, chainId } from "@aave/react";

const request: ReservesRequest = {
  query: {
    hub: {
      chainId: chainId(1),
      address: evmAddress("0x456…"),
    },
  },
};
```

```tsx title="By Spoke ID"
const request: ReservesRequest = {
  query: {
    spokeId: spoke.id, // spoke: Spoke
  },
};
```

```tsx title="By Spoke Address"
import { evmAddress, chainId } from "@aave/react";

const request: ReservesRequest = {
  query: {
    spoke: {
      address: evmAddress("0x123…"),
      chainId: chainId(1),
    },
  },
};
```

```tsx title="By User Position"
const request: ReservesRequest = {
  query: {
    userPositionId: position.id, // position: UserPosition
  },
};
```

```tsx title="By Categories"
import { TokenCategory, chainId } from "@aave/react";

const request: ReservesRequest = {
  query: {
    chainTokenCategories: [
      {
        chainId: chainId(1),
        categories: [TokenCategory.Stablecoin, TokenCategory.EthCorrelated],
      },
    ],
  },
};
```

```tsx title="By Token Info"
const request: ReservesRequest = {
  query: {
    tokenInfo: tokenInfo.id, // tokenInfo: TokenInfo
  },
};
```

```tsx title="By Symbol"
import { chainId } from "@aave/react";

const request: ReservesRequest = {
  query: {
    symbolChainIds: {
      symbol: "USDC",
      chainIds: [chainId(1), chainId(43114)], // optional; omit to match all chains
    },
  },
};
```

</tab>
<tab label="TypeScript">

```ts title="By Chains"
import { reserves } from "@aave/client/actions";
import { chainId } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    chainIds: [chainId(1)],
  },
});

if (result.isOk()) {
  console.log(result.value); // result.value: Reserve[]
} else {
  console.error(result.error);
}
```

```ts title="By Tokens"
import { reserves } from "@aave/client/actions";
import { chainId, evmAddress } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    tokens: [
      {
        address: evmAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC
        chainId: chainId(1),
      },
      {
        address: evmAddress("0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f"), // GHO
        chainId: chainId(1),
      },
    ],
  },
});
```

```ts title="By Spoke Token"
import { reserves } from "@aave/client/actions";
import { evmAddress } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    spokeToken: {
      spoke: spoke.id, // spoke: Spoke
      token: evmAddress("0x123…"),
    },
  },
});
```

```ts title="By Hub Token"
import { reserves } from "@aave/client/actions";
import { chainId, evmAddress } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    hubToken: {
      chainId: chainId(1),
      hub: evmAddress("0x456…"),
      token: evmAddress("0x123…"),
    },
  },
});
```

```ts title="By Hub ID"
import { reserves } from "@aave/client/actions";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    hubId: hub.id, // hub: Hub
  },
});
```

```ts title="By Hub Address"
import { reserves } from "@aave/client/actions";
import { chainId, evmAddress } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    hub: {
      chainId: chainId(1),
      address: evmAddress("0x456…"),
    },
  },
});
```

```ts title="By Spoke ID"
import { reserves } from "@aave/client/actions";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    spokeId: spoke.id, // spoke: Spoke
  },
});
```

```ts title="By Spoke Address"
import { reserves } from "@aave/client/actions";
import { chainId, evmAddress } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    spoke: {
      address: evmAddress("0x123…"),
      chainId: chainId(1),
    },
  },
});
```

```ts title="By User Position"
import { reserves } from "@aave/client/actions";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    userPositionId: position.id, // position: UserPosition
  },
});
```

```ts title="By Categories"
import { reserves } from "@aave/client/actions";
import { TokenCategory, chainId } from "@aave/client";
import { client } from "./client";

const result = await reserves(client, {
  query: {
    chainTokenCategories: [
      {
        chainId: chainId(1),
        categories: [TokenCategory.Stablecoin, TokenCategory.EthCorrelated],
      },
    ],
  },
});
```

```ts title="By Token Info"
import { reserves } from "@aave/client/actions";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    tokenInfo: tokenInfo.id, // tokenInfo: TokenInfo
  },
});
```

```ts title="By Symbol"
import { reserves } from "@aave/client/actions";
import { chainId } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    symbolChainIds: {
      symbol: "USDC",
      chainIds: [chainId(1), chainId(43114)], // optional; omit to match all chains
    },
  },
});
```

```ts title="client.ts"
import { AaveClient } from "@aave/client";

export const client = AaveClient.create();
```

</tab>
<tab label="GraphQL">

```json title="By Chains"
{
  "request": {
    "query": {
      "chainIds": [1]
    }
  }
}
```

```json title="By Tokens"
{
  "request": {
    "query": {
      "tokens": [
        {
          "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
          "chainId": 1
        },
        {
          "address": "0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f",
          "chainId": 1
        }
      ]
    }
  }
}
```

```json title="By Spoke Token"
{
  "request": {
    "query": {
      "spokeToken": {
        "spoke": "SGVsbG8h",
        "token": "0x123…"
      }
    }
  }
}
```

```json title="By Hub Token"
{
  "request": {
    "query": {
      "hubToken": {
        "chainId": 1,
        "hub": "0x456…",
        "token": "0x123…"
      }
    }
  }
}
```

```json title="By Hub ID"
{
  "request": {
    "query": {
      "hubId": "SGVsbG8h"
    }
  }
}
```

```json title="By Hub Address"
{
  "request": {
    "query": {
      "hub": {
        "chainId": 1,
        "address": "0x456…"
      }
    }
  }
}
```

```json title="By Spoke ID"
{
  "request": {
    "query": {
      "spokeId": "SGVsbG8h"
    }
  }
}
```

```json title="By Spoke Address"
{
  "request": {
    "query": {
      "spoke": {
        "address": "0x123…",
        "chainId": 1
      }
    }
  }
}
```

```json title="By User Position"
{
  "request": {
    "query": {
      "userPositionId": "SGVsbG8h"
    }
  }
}
```

```json title="By Categories"
{
  "request": {
    "query": {
      "chainTokenCategories": [
        {
          "chainId": 1,
          "categories": ["STABLECOIN", "ETH_CORRELATED"]
        }
      ]
    }
  }
}
```

```json title="By Token Info"
{
  "request": {
    "query": {
      "tokenInfo": "SGVsbG8h"
    }
  }
}
```

```json title="By Symbol"
{
  "request": {
    "query": {
      "symbolChainIds": {
        "symbol": "USDC",
        "chainIds": [1, 43114]
      }
    }
  }
}
```

</tab>
</tabgroup>
Filter reserves by supply, borrow, or collateral.

<tabgroup>
<tab label="React">

```tsx title="Supply Reserves"
import { ReservesRequestFilter } from "@aave/react";

// …

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

```tsx title="Collateral Reserves"
import { ReservesRequestFilter } from "@aave/react";

// …

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

```tsx title="Borrow Reserves"
import { ReservesRequestFilter } from "@aave/react";

// …

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

</tab>
<tab label="TypeScript">

```ts title="Supply Reserves"
import { reserves } from "@aave/client/actions";
import { ReservesRequestFilter } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    // your query criteria
  },
  filter: ReservesRequestFilter.Supply,
});
```

```ts title="Collateral Reserves"
import { reserves } from "@aave/client/actions";
import { ReservesRequestFilter } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    // your query criteria
  },
  filter: ReservesRequestFilter.Collateral,
});
```

```ts title="Borrow Reserves"
import { reserves } from "@aave/client/actions";
import { ReservesRequestFilter } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    // your query criteria
  },
  filter: ReservesRequestFilter.Borrow,
});
```

</tab>
<tab label="GraphQL">

```json title="Supply Reserves"
{
  "request": {
    "query": {
      "spoke": {
        "address": "0x123…",
        "chainId": 1
      }
    },
    "filter": "SUPPLY"
  }
}
```

```json title="Collateral Reserves"
{
  "request": {
    "query": {
      "spoke": {
        "address": "0x123…",
        "chainId": 1
      }
    },
    "filter": "COLLATERAL"
  }
}
```

```json title="Borrow Reserves"
{
  "request": {
    "query": {
      "spoke": {
        "address": "0x123…",
        "chainId": 1
      }
    },
    "filter": "BORROW"
  }
}
```

</tab>
</tabgroup>
Add a user address to return `ReserveUserState` for each reserve.

<tabgroup>
<tab label="React">

```tsx title="Reserves User State"
import { evmAddress } from "@aave/react";

// …

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

</tab>
<tab label="TypeScript">

```ts title="Reserves User State"
import { reserves } from "@aave/client/actions";
import { evmAddress } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    // your query criteria
  },
  user: evmAddress("0x456…"),
});
```

</tab>
<tab label="GraphQL">

```json title="With User"
{
  "request": {
    "query": {
      "spoke": {
        "address": "0x123…",
        "chainId": 1
      }
    },
    "user": "0x456…"
  }
}
```

</tab>
</tabgroup>
Sort reserves by asset name, user balance, APYs, collateral factor, or available amounts.

<tabgroup>
<tab label="React">

```tsx title="Asset Name"
import { OrderDirection } from "@aave/react";

// …

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

```tsx title="User Balance"
import { evmAddress, OrderDirection } from "@aave/react";

// …

const request: ReservesRequest = {
  query: {
    // your query criteria
  },
  orderBy: { userBalance: OrderDirection.Asc },
  user: evmAddress("0x456…"),
};
```

```tsx title="Supply APY"
import { OrderDirection, ReservesRequestFilter } from "@aave/react";

// …

const request: ReservesRequest = {
  query: {
    // your query criteria
  },
  filter: ReservesRequestFilter.Supply,
  orderBy: { supplyApy: OrderDirection.Desc },
};
```

```tsx title="Borrow APY"
import { OrderDirection, ReservesRequestFilter } from "@aave/react";

// …

const request: ReservesRequest = {
  query: {
    // your query criteria
  },
  filter: ReservesRequestFilter.Borrow,
  orderBy: { borrowApy: OrderDirection.Asc },
};
```

```tsx title="Collateral Factor"
import { OrderDirection } from "@aave/react";

// …

const request: ReservesRequest = {
  query: {
    // your query criteria
  },
  orderBy: { collateralFactor: OrderDirection.Desc },
};
```

```tsx title="Supply Available"
import { OrderDirection, ReservesRequestFilter } from "@aave/react";

// …

const request: ReservesRequest = {
  query: {
    // your query criteria
  },
  filter: ReservesRequestFilter.Supply,
  orderBy: { supplyAvailable: OrderDirection.Desc },
};
```

```tsx title="Borrow Available"
import { OrderDirection, ReservesRequestFilter } from "@aave/react";

// …

const request: ReservesRequest = {
  query: {
    // your query criteria
  },
  filter: ReservesRequestFilter.Borrow,
  orderBy: { borrowAvailable: OrderDirection.Desc },
};
```

</tab>
<tab label="TypeScript">

```ts title="Asset Name"
import { reserves } from "@aave/client/actions";
import { OrderDirection } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    // your query criteria
  },
  orderBy: { assetName: OrderDirection.Asc },
});
```

```ts title="User Balance"
import { reserves } from "@aave/client/actions";
import { evmAddress, OrderDirection } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    // your query criteria
  },
  orderBy: { userBalance: OrderDirection.Asc },
  user: evmAddress("0x456…"),
});
```

```ts title="Supply APY"
import { reserves } from "@aave/client/actions";
import { OrderDirection, ReservesRequestFilter } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    // your query criteria
  },
  filter: ReservesRequestFilter.Supply,
  orderBy: { supplyApy: OrderDirection.Desc },
});
```

```ts title="Borrow APY"
import { reserves } from "@aave/client/actions";
import { OrderDirection, ReservesRequestFilter } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    // your query criteria
  },
  filter: ReservesRequestFilter.Borrow,
  orderBy: { borrowApy: OrderDirection.Asc },
});
```

```ts title="Collateral Factor"
import { reserves } from "@aave/client/actions";
import { OrderDirection } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    // your query criteria
  },
  orderBy: { collateralFactor: OrderDirection.Desc },
});
```

```ts title="Supply Available"
import { reserves } from "@aave/client/actions";
import { OrderDirection, ReservesRequestFilter } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    // your query criteria
  },
  filter: ReservesRequestFilter.Supply,
  orderBy: { supplyAvailable: OrderDirection.Desc },
});
```

```ts title="Borrow Available"
import { reserves } from "@aave/client/actions";
import { OrderDirection, ReservesRequestFilter } from "@aave/client";

import { client } from "./client";

const result = await reserves(client, {
  query: {
    // your query criteria
  },
  filter: ReservesRequestFilter.Borrow,
  orderBy: { borrowAvailable: OrderDirection.Desc },
});
```

</tab>
<tab label="GraphQL">

```json title="AssetName"
{
  "request": {
    "query": {
      "spoke": {
        "address": "0x123…",
        "chainId": 1
      }
    },
    "orderBy": { "assetName": "ASC" }
  }
}
```

```json title="User Balance"
{
  "request": {
    "query": {
      "spoke": {
        "address": "0x123…",
        "chainId": 1
      }
    },
    "user": "0x456…",
    "orderBy": { "userBalance": "ASC" }
  }
}
```

```json title="Supply APY"
{
  "request": {
    "query": {
      "spoke": {
        "address": "0x123…",
        "chainId": 1
      }
    },
    "filter": "SUPPLY",
    "orderBy": { "supplyApy": "DESC" }
  }
}
```

```json title="Borrow APY"
{
  "request": {
    "query": {
      "spoke": {
        "address": "0x123…",
        "chainId": 1
      }
    },
    "filter": "BORROW",
    "orderBy": { "borrowApy": "ASC" }
  }
}
```

```json title="Collateral Factor"
{
  "request": {
    "query": {
      "spoke": {
        "address": "0x123…",
        "chainId": 1
      }
    },
    "orderBy": { "collateralFactor": "DESC" }
  }
}
```

```json title="Supply Available"
{
  "request": {
    "query": {
      "spoke": {
        "address": "0x123…",
        "chainId": 1
      }
    },
    "filter": "SUPPLY",
    "orderBy": { "supplyAvailable": "DESC" }
  }
}
```

```json title="Borrow Available"
{
  "request": {
    "query": {
      "spoke": {
        "address": "0x123…",
        "chainId": 1
      }
    },
    "filter": "BORROW",
    "orderBy": { "borrowAvailable": "DESC" }
  }
}
```

</tab>
</tabgroup>
In React and TypeScript, specify a different currency to return fiat amounts in.

<tabgroup>
<tab label="React">

```tsx title="Declarative Read"
import { Currency } from "@aave/react";

// …

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

```tsx title="Imperative Read"
import { Currency } from "@aave/react";

const [fetch, { called, data, error, loading }] = useReservesAction({
  currency: Currency.Eur,
});
```

</tab>
<tab label="TypeScript">

```ts title="Custom Currency"
import { reserves } from "@aave/client/actions";
import { Currency } from "@aave/client";

import { client } from "./client";

const result = await reserves(
  client,
  {
    // your request
  },
  {
    currency: Currency.Eur,
  },
);
```

</tab>
</tabgroup>
## 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.

<tabgroup>
<tab label="React">

```tsx title="Loading State"
import { type ReserveRequest, useReserve } from "@aave/react";

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

  if (loading) return Loading reserve…;

  if (error) return Error: {error.message};

  if (!data) return Reserve not found;

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

```tsx title="React Suspense"
import { type ReserveRequest, useReserve } from "@aave/react";

function ReserveDetails({ request }: { request: ReserveRequest }) {
  const { data } = useReserve({
    ...request,
    suspense: true,
  });

  if (!data) return Reserve not found;

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

</tab>
<tab label="TypeScript">

```ts title="Reserve"
import { reserveId } from "@aave/client";
import { reserve } from "@aave/client/actions";

import { client } from "./client";

const result = await reserve(client, {
  query: {
    reserveId: reserveId("SGVsbG8h"),
  },
});

if (result.isOk()) {
  console.log(result.value); // Reserve | null
} else {
  console.error(result.error);
}
```

```ts title="client.ts"
import { AaveClient } from "@aave/client";

export const client = AaveClient.create();
```

</tab>
<tab label="GraphQL">

```graphql title="Query"
query ($request: ReserveRequest!) {
  value: reserve(request: $request) {
    ...Reserve
  }
}
```

</tab>
</tabgroup>
See below for examples of `ReserveRequest` objects.

<tabgroup>
<tab label="React">

```tsx title="By OnChain ID"
import { chainId, evmAddress, type OnChainReserveId } from "@aave/react";

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

```tsx title="By Reserve ID"
import { ReserveId } from "@aave/react";

const request: ReserveRequest = {
  query: {
    reserveId: "SGVsbG8h" as ReserveId,
  },
};
```

```tsx title="With User State"
import { evmAddress } from "@aave/react";

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

</tab>
<tab label="TypeScript">

```ts title="By OnChain ID"
import { reserve } from "@aave/client/actions";
import { chainId, evmAddress, type OnChainReserveId } from "@aave/client";
import { client } from "./client";

const result = await reserve(client, {
  query: {
    reserveInput: {
      chainId: chainId(1),
      spoke: evmAddress("0x123…"),
      onChainId: "1" as OnChainReserveId,
    },
  },
});

if (result.isOk()) {
  console.log(result.value); // Reserve | null - null if not found
} else {
  console.error(result.error);
}
```

```ts title="By Reserve ID"
import { reserve } from "@aave/client/actions";
import { type ReserveId } from "@aave/client";

import { client } from "./client";

// const id: ReserveId = "SGVsbG8h";

const result = await reserve(client, {
  query: { reserveId: id },
});
```

```ts title="With User State"
import { reserve } from "@aave/client/actions";
import { evmAddress } from "@aave/client";
import { client } from "./client";

const result = await reserve(client, {
  query: {
    // your query criteria
  },
  user: evmAddress("0x456…"),
});
```

</tab>
<tab label="GraphQL">

```json title="By OnChain ID"
{
  "request": {
    "query": {
      "reserveInput": {
        "chainId": 1,
        "spoke": "0x123…",
        "onChainId": "1"
      }
    }
  }
}
```

```json title="By Reserve ID"
{
  "request": {
    "query": {
      "reserveId": "SGVsbG8h"
    }
  }
}
```

```json title="With User State"
{
  "request": {
    "query": {
      "reserveId": "SGVsbG8h"
    },
    "user": "0x456…"
  }
}
```

</tab>
</tabgroup>
Finally, in React, you can specify a different time window or currency for the data.

<tabgroup>
<tab label="React">

```tsx title="Custom Time Window"
import { TimeWindow } from "@aave/react";

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

```tsx title="Custom Currency"
import { Currency } from "@aave/react";

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

</tab>
</tabgroup>
## 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.

<tabgroup>
<tab label="React">

```tsx title="Loading State"
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>
  );
}
```

```tsx title="React Suspense"
import { type BorrowApyHistoryRequest, useBorrowApyHistory } from "@aave/react";

function BorrowApy({ request }: { request: BorrowApyHistoryRequest }) {
  const { data } = useBorrowApyHistory({
    ...request,
    suspense: true,
  });

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

</tab>
<tab label="GraphQL">

```graphql title="Query"
query ($request: BorrowApyHistoryRequest!) {
  borrowApyHistory(request: $request) {
    date
    avgRate {
      onChainValue
      decimals
      value
      normalized
    }
  }
}
```

</tab>
</tabgroup>
See below for examples of `BorrowApyHistoryRequest` objects.

<tabgroup>
<tab label="React">

```tsx title="By Reserve ID"
import { TimeWindow } from "@aave/react";

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

```tsx title="Custom Time Window"
import { TimeWindow } from "@aave/react";

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

```tsx title="Protocol Rates Only"
const request: BorrowApyHistoryRequest = {
  reserve: reserve.id,
  includeRewards: false, // exclude Merkl rewards from the rates
};
```

</tab>
<tab label="TypeScript">

```ts title="By Reserve ID"
import { borrowApyHistory } from "@aave/client/actions";
import { TimeWindow } from "@aave/client";
import { client } from "./client";

const result = await borrowApyHistory(client, {
  reserve: reserve.id,
  window: TimeWindow.LastDay,
});

if (result.isOk()) {
  console.log(result.value); // ApySample[]
} else {
  console.error(result.error);
}
```

```ts title="Custom Time Window"
import { borrowApyHistory } from "@aave/client/actions";
import { TimeWindow } from "@aave/client";
import { client } from "./client";

const result = await borrowApyHistory(client, {
  reserve: reserve.id,
  window: TimeWindow.LastWeek,
});
```

```ts title="Protocol Rates Only"
import { borrowApyHistory } from "@aave/client/actions";
import { client } from "./client";

const result = await borrowApyHistory(client, {
  reserve: reserve.id,
  includeRewards: false, // exclude Merkl rewards from the rates
});
```

</tab>
<tab label="GraphQL">

```json title="By Reserve ID"
{
  "request": {
    "reserve": "SGVsbG8h",
    "window": "LAST_DAY"
  }
}
```

```json title="Custom Time Window"
{
  "request": {
    "reserve": "SGVsbG8h",
    "window": "LAST_WEEK"
  }
}
```

```json title="Protocol Rates Only"
{
  "request": {
    "reserve": "SGVsbG8h",
    "includeRewards": false
  }
}
```

</tab>
</tabgroup>
## 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.

<tabgroup>
<tab label="React">

```tsx title="Loading State"
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>
  );
}
```

```tsx title="React Suspense"
import { type SupplyApyHistoryRequest, useSupplyApyHistory } from "@aave/react";

function SupplyApy({ request }: { request: SupplyApyHistoryRequest }) {
  const { data } = useSupplyApyHistory({
    ...request,
    suspense: true,
  });

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

</tab>
<tab label="GraphQL">

```graphql title="Query"
query ($request: SupplyApyHistoryRequest!) {
  supplyApyHistory(request: $request) {
    date
    avgRate {
      onChainValue
      decimals
      value
      normalized
    }
  }
}
```

</tab>
</tabgroup>
See below for examples of `SupplyApyHistoryRequest` objects.

<tabgroup>
<tab label="React">

```tsx title="By Reserve ID"
import { TimeWindow } from "@aave/react";

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

```tsx title="Custom Time Window"
import { TimeWindow } from "@aave/react";

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

```tsx title="Protocol Rates Only"
const request: SupplyApyHistoryRequest = {
  reserve: reserve.id,
  includeRewards: false, // exclude Merkl rewards from the rates
};
```

</tab>
<tab label="TypeScript">

```ts title="By Reserve ID"
import { supplyApyHistory } from "@aave/client/actions";
import { TimeWindow } from "@aave/client";
import { client } from "./client";

const result = await supplyApyHistory(client, {
  reserve: reserve.id,
  window: TimeWindow.LastDay,
});

if (result.isOk()) {
  console.log(result.value); // ApySample[]
} else {
  console.error(result.error);
}
```

```ts title="Custom Time Window"
import { supplyApyHistory } from "@aave/client/actions";
import { TimeWindow } from "@aave/client";
import { client } from "./client";

const result = await supplyApyHistory(client, {
  reserve: reserve.id,
  window: TimeWindow.LastWeek,
});
```

```ts title="Protocol Rates Only"
import { supplyApyHistory } from "@aave/client/actions";
import { client } from "./client";

const result = await supplyApyHistory(client, {
  reserve: reserve.id,
  includeRewards: false, // exclude Merkl rewards from the rates
});
```

</tab>
<tab label="GraphQL">

```json title="By Reserve ID"
{
  "request": {
    "reserve": "SGVsbG8h",
    "window": "LAST_DAY"
  }
}
```

```json title="Custom Time Window"
{
  "request": {
    "reserve": "SGVsbG8h",
    "window": "LAST_WEEK"
  }
}
```

```json title="Protocol Rates Only"
{
  "request": {
    "reserve": "SGVsbG8h",
    "includeRewards": false
  }
}
```

</tab>
</tabgroup>
## 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.

<tabgroup>
<tab label="React">

```tsx title="Loading State"
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}>
          {holder.address}
          <p>
            {holder.amount.amount.value.toFixed(4)} 
            {holder.amount.token.info.symbol}
          </p>
          {holder.weight.normalized.toFixed(4)}%
        </div>
      ))}
    </div>
  );
}
```

```tsx title="React Suspense"
import { ReserveHoldersFilter, useReserveHolders } from "@aave/react";

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

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

</tab>
<tab label="GraphQL">

```graphql title="Query"
query ($request: PaginatedReserveHoldersRequest!) {
  reserveHolders(request: $request) {
    items {
      address
      amount {
        ...Erc20Amount
      }
      weight {
        ...PercentNumber
      }
    }
    pageInfo {
      next
      prev
    }
  }
}
```

</tab>
</tabgroup>
Filter by `ReserveHoldersFilter.Supplied` (default) or `ReserveHoldersFilter.Borrowed`. In GraphQL, provide these as query variables.

<tabgroup>
<tab label="React">

```tsx title="Supplied Holders"
import { ReserveHoldersFilter, useReserveHolders } from "@aave/react";

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

```tsx title="Borrowed Holders"
import { ReserveHoldersFilter, useReserveHolders } from "@aave/react";

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

</tab>
<tab label="TypeScript">

```ts title="Supplied Holders"
import { ReserveHoldersFilter, reserveId } from "@aave/client";
import { reserveHolders } from "@aave/client/actions";
import { client } from "./client";

const result = await reserveHolders(client, {
  reserve: { reserveId: reserveId("SGVsbG8h") },
  filter: ReserveHoldersFilter.Supplied,
});

if (result.isOk()) {
  console.log(result.value.items); // ReserveHolder[]
} else {
  console.error(result.error);
}
```

```ts title="Borrowed Holders"
import { ReserveHoldersFilter, reserveId } from "@aave/client";
import { reserveHolders } from "@aave/client/actions";
import { client } from "./client";

const result = await reserveHolders(client, {
  reserve: { reserveId: reserveId("SGVsbG8h") },
  filter: ReserveHoldersFilter.Borrowed,
});
```

</tab>
<tab label="GraphQL">

```json title="Supplied Holders"
{
  "request": {
    "reserve": { "reserveId": "SGVsbG8h" },
    "filter": "SUPPLIED"
  }
}
```

```json title="Borrowed Holders"
{
  "request": {
    "reserve": { "reserveId": "SGVsbG8h" },
    "filter": "BORROWED"
  }
}
```

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

<tabgroup>
<tab label="React">

```tsx title="Pagination"
import { PageSize, useReserveHolders } from "@aave/react";

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

</tab>
<tab label="TypeScript">

```ts title="Pagination"
import { PageSize, reserveId } from "@aave/client";
import { reserveHolders } from "@aave/client/actions";
import { client } from "./client";

const result = await reserveHolders(client, {
  reserve: { reserveId: reserveId("SGVsbG8h") },
  pageSize: PageSize.Fifty,
  cursor: previousPage.pageInfo.next,
});
```

</tab>
<tab label="GraphQL">

```json title="Pagination"
{
  "request": {
    "reserve": { "reserveId": "SGVsbG8h" },
    "pageSize": "FIFTY",
    "cursor": "…"
  }
}
```

</tab>
</tabgroup>
