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;
}
interface ReserveSummary {
__typename: "ReserveSummary";
supplied: Erc20Amount;
borrowed: Erc20Amount;
supplyApy: PercentNumber;
borrowApy: PercentNumber;
rewards: Reward[];
}
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;
}
interface ReserveStatus {
__typename: "ReserveStatus";
frozen: boolean;
paused: boolean;
active: boolean;
}
interface ReserveUserState {
__typename: "ReserveUserState";
balance: Erc20Amount;
suppliable: Erc20Amount;
borrowable: Erc20Amount;
borrowApy: PercentNumber;
collateralFactor: PercentNumber;
maxLiquidationBonus: PercentNumber;
liquidationFee: PercentNumber;
dynamicConfigKey: DynamicConfigKey;
}
The following GraphQL fragments illustrate the core Reserve type:
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
}
}
fragment ReserveSummary on ReserveSummary {
__typename
supplied {
...Erc20Amount
}
borrowed {
...Erc20Amount
}
supplyApy {
...PercentNumber
}
borrowApy {
...PercentNumber
}
rewards {
...Reward
}
}
fragment ReserveSettings on ReserveSettings {
__typename
collateralFactor {
...PercentNumber
}
maxLiquidationBonus {
...PercentNumber
}
liquidationFee {
...PercentNumber
}
collateralRisk {
...PercentNumber
}
borrowable
collateral
suppliable
receiveSharesEnabled
latestDynamicConfigKey
borrowCap {
...Erc20Amount
}
supplyCap {
...Erc20Amount
}
}
fragment ReserveStatus on ReserveStatus {
__typename
frozen
paused
active
}
fragment ReserveUserState on ReserveUserState {
__typename
balance {
...Erc20Amount
}
suppliable {
...Erc20Amount
}
borrowable {
...Erc20Amount
}
borrowApy {
...PercentNumber
}
collateralFactor {
...PercentNumber
}
maxLiquidationBonus {
...PercentNumber
}
liquidationFee {
...PercentNumber
}
dynamicConfigKey
}
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.
struct Reserve {
address underlying;
IHubBase hub;
uint16 assetId;
uint8 decimals;
uint24 collateralRisk;
ReserveFlags flags;
uint32 dynamicConfigKey;
}
struct ReserveConfig {
uint24 collateralRisk;
bool paused;
bool frozen;
bool borrowable;
bool receiveSharesEnabled;
}
struct DynamicReserveConfig {
uint16 collateralFactor;
uint32 maxLiquidationBonus;
uint16 liquidationFee;
}
Listing Available Reserves
Discover all available reserves given some criteria.
Use the use hook (or the imperative use 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 reserve values. To retrieve all reserves within a spoke, first obtain the total reserve count and then loop through each reserve.
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>
);
}
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>
<p>Spoke: {reserve.spoke.name}</p>
</div>
))}
</div>
);
}
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);
}
};
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);
}
import { AaveClient } from "@aave/client";
export const client = AaveClient.create();
query ($request: ReservesRequest!) {
value: reserves(request: $request) {
...Reserve
}
}
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;
}
}
use 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)],
},
};
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),
},
],
},
};
import { evmAddress } from "@aave/react";
const request: ReservesRequest = {
query: {
spokeToken: {
spoke: spoke.id, // spoke: Spoke
token: evmAddress("0x123…"),
},
},
};
import { evmAddress, chainId } from "@aave/react";
const request: ReservesRequest = {
query: {
hubToken: {
chainId: chainId(1),
hub: evmAddress("0x456…"),
token: evmAddress("0x123…"),
},
},
};
const request: ReservesRequest = {
query: {
hubId: hub.id, // hub: Hub
},
};
import { evmAddress, chainId } from "@aave/react";
const request: ReservesRequest = {
query: {
hub: {
chainId: chainId(1),
address: evmAddress("0x456…"),
},
},
};
const request: ReservesRequest = {
query: {
spokeId: spoke.id, // spoke: Spoke
},
};
import { evmAddress, chainId } from "@aave/react";
const request: ReservesRequest = {
query: {
spoke: {
address: evmAddress("0x123…"),
chainId: chainId(1),
},
},
};
const request: ReservesRequest = {
query: {
userPositionId: position.id, // position: UserPosition
},
};
import { TokenCategory, chainId } from "@aave/react";
const request: ReservesRequest = {
query: {
chainTokenCategories: [
{
chainId: chainId(1),
categories: [TokenCategory.Stablecoin, TokenCategory.EthCorrelated],
},
],
},
};
const request: ReservesRequest = {
query: {
tokenInfo: tokenInfo.id, // tokenInfo: TokenInfo
},
};
import { chainId } from "@aave/react";
const request: ReservesRequest = {
query: {
symbolChainIds: {
symbol: "USDC",
chainIds: [chainId(1), chainId(43114)], // optional; omit to match all 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);
}
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),
},
],
},
});
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…"),
},
},
});
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…"),
},
},
});
import { reserves } from "@aave/client/actions";
import { client } from "./client";
const result = await reserves(client, {
query: {
hubId: hub.id, // hub: Hub
},
});
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…"),
},
},
});
import { reserves } from "@aave/client/actions";
import { client } from "./client";
const result = await reserves(client, {
query: {
spokeId: spoke.id, // spoke: Spoke
},
});
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),
},
},
});
import { reserves } from "@aave/client/actions";
import { client } from "./client";
const result = await reserves(client, {
query: {
userPositionId: position.id, // position: UserPosition
},
});
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],
},
],
},
});
import { reserves } from "@aave/client/actions";
import { client } from "./client";
const result = await reserves(client, {
query: {
tokenInfo: tokenInfo.id, // tokenInfo: TokenInfo
},
});
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
},
},
});
import { AaveClient } from "@aave/client";
export const client = AaveClient.create();
{
"request": {
"query": {
"chainIds": [1]
}
}
}
{
"request": {
"query": {
"tokens": [
{
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"chainId": 1
},
{
"address": "0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f",
"chainId": 1
}
]
}
}
}
{
"request": {
"query": {
"spokeToken": {
"spoke": "SGVsbG8h",
"token": "0x123…"
}
}
}
}
{
"request": {
"query": {
"hubToken": {
"chainId": 1,
"hub": "0x456…",
"token": "0x123…"
}
}
}
}
{
"request": {
"query": {
"hubId": "SGVsbG8h"
}
}
}
{
"request": {
"query": {
"hub": {
"chainId": 1,
"address": "0x456…"
}
}
}
}
{
"request": {
"query": {
"spokeId": "SGVsbG8h"
}
}
}
{
"request": {
"query": {
"spoke": {
"address": "0x123…",
"chainId": 1
}
}
}
}
{
"request": {
"query": {
"userPositionId": "SGVsbG8h"
}
}
}
{
"request": {
"query": {
"chainTokenCategories": [
{
"chainId": 1,
"categories": ["STABLECOIN", "ETH_CORRELATED"]
}
]
}
}
}
{
"request": {
"query": {
"tokenInfo": "SGVsbG8h"
}
}
}
{
"request": {
"query": {
"symbolChainIds": {
"symbol": "USDC",
"chainIds": [1, 43114]
}
}
}
}
Filter reserves by supply, borrow, or collateral.
import { ReservesRequestFilter } from "@aave/react";
// …
const request: ReservesRequest = {
query: {
// your query criteria
},
filter: ReservesRequestFilter.Supply,
};
import { ReservesRequestFilter } from "@aave/react";
// …
const request: ReservesRequest = {
query: {
// your query criteria
},
filter: ReservesRequestFilter.Collateral,
};
import { ReservesRequestFilter } from "@aave/react";
// …
const request: ReservesRequest = {
query: {
// your query criteria
},
filter: ReservesRequestFilter.Borrow,
};
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,
});
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,
});
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,
});
{
"request": {
"query": {
"spoke": {
"address": "0x123…",
"chainId": 1
}
},
"filter": "SUPPLY"
}
}
{
"request": {
"query": {
"spoke": {
"address": "0x123…",
"chainId": 1
}
},
"filter": "COLLATERAL"
}
}
{
"request": {
"query": {
"spoke": {
"address": "0x123…",
"chainId": 1
}
},
"filter": "BORROW"
}
}
Add a user address to return Reserve for each reserve.
import { evmAddress } from "@aave/react";
// …
const request: ReservesRequest = {
query: {
// your query criteria
},
user: evmAddress("0x456…"),
};
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…"),
});
{
"request": {
"query": {
"spoke": {
"address": "0x123…",
"chainId": 1
}
},
"user": "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 },
};
import { evmAddress, OrderDirection } from "@aave/react";
// …
const request: ReservesRequest = {
query: {
// your query criteria
},
orderBy: { userBalance: OrderDirection.Asc },
user: evmAddress("0x456…"),
};
import { OrderDirection, ReservesRequestFilter } from "@aave/react";
// …
const request: ReservesRequest = {
query: {
// your query criteria
},
filter: ReservesRequestFilter.Supply,
orderBy: { supplyApy: OrderDirection.Desc },
};
import { OrderDirection, ReservesRequestFilter } from "@aave/react";
// …
const request: ReservesRequest = {
query: {
// your query criteria
},
filter: ReservesRequestFilter.Borrow,
orderBy: { borrowApy: OrderDirection.Asc },
};
import { OrderDirection } from "@aave/react";
// …
const request: ReservesRequest = {
query: {
// your query criteria
},
orderBy: { collateralFactor: OrderDirection.Desc },
};
import { OrderDirection, ReservesRequestFilter } from "@aave/react";
// …
const request: ReservesRequest = {
query: {
// your query criteria
},
filter: ReservesRequestFilter.Supply,
orderBy: { supplyAvailable: OrderDirection.Desc },
};
import { OrderDirection, ReservesRequestFilter } from "@aave/react";
// …
const request: ReservesRequest = {
query: {
// your query criteria
},
filter: ReservesRequestFilter.Borrow,
orderBy: { borrowAvailable: OrderDirection.Desc },
};
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 },
});
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…"),
});
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 },
});
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 },
});
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 },
});
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 },
});
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 },
});
{
"request": {
"query": {
"spoke": {
"address": "0x123…",
"chainId": 1
}
},
"orderBy": { "assetName": "ASC" }
}
}
{
"request": {
"query": {
"spoke": {
"address": "0x123…",
"chainId": 1
}
},
"user": "0x456…",
"orderBy": { "userBalance": "ASC" }
}
}
{
"request": {
"query": {
"spoke": {
"address": "0x123…",
"chainId": 1
}
},
"filter": "SUPPLY",
"orderBy": { "supplyApy": "DESC" }
}
}
{
"request": {
"query": {
"spoke": {
"address": "0x123…",
"chainId": 1
}
},
"filter": "BORROW",
"orderBy": { "borrowApy": "ASC" }
}
}
{
"request": {
"query": {
"spoke": {
"address": "0x123…",
"chainId": 1
}
},
"orderBy": { "collateralFactor": "DESC" }
}
}
{
"request": {
"query": {
"spoke": {
"address": "0x123…",
"chainId": 1
}
},
"filter": "SUPPLY",
"orderBy": { "supplyAvailable": "DESC" }
}
}
{
"request": {
"query": {
"spoke": {
"address": "0x123…",
"chainId": 1
}
},
"filter": "BORROW",
"orderBy": { "borrowAvailable": "DESC" }
}
}
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,
});
import { Currency } from "@aave/react";
const [fetch, { called, data, error, loading }] = useReservesAction({
currency: Currency.Eur,
});
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,
},
);
Fetching a Single Reserve
Get detailed information about a specific reserve.
Use the use 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>
);
}
import { type ReserveRequest, useReserve } from "@aave/react";
function ReserveDetails({ request }: { request: ReserveRequest }) {
const { data } = useReserve({
...request,
suspense: true,
});
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>
);
}
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);
}
import { AaveClient } from "@aave/client";
export const client = AaveClient.create();
query ($request: ReserveRequest!) {
value: reserve(request: $request) {
...Reserve
}
}
See below for examples of Reserve objects.
import { chainId, evmAddress, type OnChainReserveId } from "@aave/react";
const request: ReserveRequest = {
query: {
reserveInput: {
chainId: chainId(1),
spoke: evmAddress("0x123…"),
onChainId: "1" as OnChainReserveId,
},
},
};
import { ReserveId } from "@aave/react";
const request: ReserveRequest = {
query: {
reserveId: "SGVsbG8h" as ReserveId,
},
};
import { evmAddress } from "@aave/react";
const request: ReserveRequest = {
query: {
// your query criteria
},
user: evmAddress("0x456…"),
};
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);
}
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 },
});
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…"),
});
{
"request": {
"query": {
"reserveInput": {
"chainId": 1,
"spoke": "0x123…",
"onChainId": "1"
}
}
}
}
{
"request": {
"query": {
"reserveId": "SGVsbG8h"
}
}
}
{
"request": {
"query": {
"reserveId": "SGVsbG8h"
},
"user": "0x456…"
}
}
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,
});
import { Currency } from "@aave/react";
const { data, loading, error } = useReserve({
query: {
// your query criteria
},
currency: Currency.Eur,
});
Borrow APY History
Fetch historical borrow APY data for a specific reserve. By default, Merkl rewards are included in the returned rates; pass include for protocol base rates only.
Use the use hook in React, the borrow action in TypeScript, or the borrow 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>
);
}
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>
);
}
query ($request: BorrowApyHistoryRequest!) {
borrowApyHistory(request: $request) {
date
avgRate {
onChainValue
decimals
value
normalized
}
}
}
See below for examples of Borrow objects.
import { TimeWindow } from "@aave/react";
const request: BorrowApyHistoryRequest = {
reserve: reserve.id,
window: TimeWindow.LastDay,
};
import { TimeWindow } from "@aave/react";
const request: BorrowApyHistoryRequest = {
reserve: reserve.id,
window: TimeWindow.LastWeek,
};
const request: BorrowApyHistoryRequest = {
reserve: reserve.id,
includeRewards: false, // exclude Merkl rewards from the rates
};
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);
}
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,
});
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
});
{
"request": {
"reserve": "SGVsbG8h",
"window": "LAST_DAY"
}
}
{
"request": {
"reserve": "SGVsbG8h",
"window": "LAST_WEEK"
}
}
{
"request": {
"reserve": "SGVsbG8h",
"includeRewards": false
}
}
Supply APY History
Fetch historical supply APY data for a specific reserve. By default, Merkl rewards are included in the returned rates; pass include for protocol base rates only.
Use the use hook in React, the supply action in TypeScript, or the supply 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>
);
}
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>
);
}
query ($request: SupplyApyHistoryRequest!) {
supplyApyHistory(request: $request) {
date
avgRate {
onChainValue
decimals
value
normalized
}
}
}
See below for examples of Supply objects.
import { TimeWindow } from "@aave/react";
const request: SupplyApyHistoryRequest = {
reserve: reserve.id,
window: TimeWindow.LastDay,
};
import { TimeWindow } from "@aave/react";
const request: SupplyApyHistoryRequest = {
reserve: reserve.id,
window: TimeWindow.LastWeek,
};
const request: SupplyApyHistoryRequest = {
reserve: reserve.id,
includeRewards: false, // exclude Merkl rewards from the rates
};
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);
}
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,
});
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
});
{
"request": {
"reserve": "SGVsbG8h",
"window": "LAST_DAY"
}
}
{
"request": {
"reserve": "SGVsbG8h",
"window": "LAST_WEEK"
}
}
{
"request": {
"reserve": "SGVsbG8h",
"includeRewards": false
}
}
Reserve Holders
Fetch a paginated list of the top holders for a specific reserve, filtered by suppliers or borrowers.
Use the use hook in React, the reserve action in TypeScript, or the reserve 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>
);
}
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}>
<p>{holder.address}</p>
<p>
{holder.amount.amount.value.toFixed(4)}{" "}
{holder.amount.token.info.symbol}
</p>
</div>
))}
</div>
);
}
query ($request: PaginatedReserveHoldersRequest!) {
reserveHolders(request: $request) {
items {
address
amount {
...Erc20Amount
}
weight {
...PercentNumber
}
}
pageInfo {
next
prev
}
}
}
Filter by Reserve (default) or Reserve. In GraphQL, provide these as query variables.
import { ReserveHoldersFilter, useReserveHolders } from "@aave/react";
const { data } = useReserveHolders({
reserve: { reserveId: reserve.id },
filter: ReserveHoldersFilter.Supplied,
});
import { ReserveHoldersFilter, useReserveHolders } from "@aave/react";
const { data } = useReserveHolders({
reserve: { reserveId: reserve.id },
filter: ReserveHoldersFilter.Borrowed,
});
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);
}
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,
});
{
"request": {
"reserve": { "reserveId": "SGVsbG8h" },
"filter": "SUPPLIED"
}
}
{
"request": {
"reserve": { "reserveId": "SGVsbG8h" },
"filter": "BORROWED"
}
}
Results are paginated. Use page (Page by default, or Page) and pass page as cursor to fetch the next page.
import { PageSize, useReserveHolders } from "@aave/react";
const { data } = useReserveHolders({
reserve: { reserveId: reserve.id },
pageSize: PageSize.Fifty,
cursor: previousPage.pageInfo.next,
});
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,
});
{
"request": {
"reserve": { "reserveId": "SGVsbG8h" },
"pageSize": "FIFTY",
"cursor": "…"
}
}