Aave V4 Liquidity Hubs
Liquidity Hubs hold the shared liquidity of Aave V4 and grant each Spoke a credit line for borrowing and a debit line for supplying.
Hub Data Structure
Hub data provides an aggregate view of a Liquidity Hub, including:
- Identification: id, name, chain, address
- Aggregated details: totalSupplied, totalBorrowed
- System caps: totalSupplyCap, totalBorrowCap
In Solidity, Hubs are represented by deployed contracts implementing the IHub interface, managed by governance. Unlike the SDK, there is no single onchain struct containing Hub metadata (name, address) nor aggregate summary information (e.g., total liquidity) as these are maintained offchain.
Hubs manage two key relationships: Assets and Spokes. For more information about Hub Assets, see the Hub Assets section below. For details on Spoke-Hub relationships and Spoke data structures, see the Spoke Data Structure section.
The following TypeScript interfaces and GraphQL fragments illustrate the core Hub type.
interface Hub {
__typename: "Hub";
id: HubId;
address: EvmAddress;
chain: Chain;
name: string;
summary: HubSummary;
}
interface HubSummary {
__typename: "HubSummary";
totalBorrowed: ExchangeAmountWithChange;
totalBorrowCap: ExchangeAmount;
totalSupplied: ExchangeAmountWithChange;
totalSupplyCap: ExchangeAmount;
utilizationRate: PercentNumber;
}
interface ExchangeAmount {
__typename: "ExchangeAmount";
value: BigDecimal;
name: string;
symbol: string;
icon: string;
decimals: number;
}
interface ExchangeAmountWithChange {
__typename: "ExchangeAmountWithChange";
current: ExchangeAmount;
change: PercentNumber;
}
interface PercentNumber {
__typename: "PercentNumber";
onChainValue: bigint;
decimals: number;
value: BigDecimal;
normalized: BigDecimal;
}
interface Chain {
__typename: "Chain";
chainId: ChainId;
name: string;
icon: string;
rpcUrl: string;
explorerUrl: string;
isTestnet: boolean;
nativeWrappedToken: EvmAddress;
nativeInfo: TokenInfo;
nativeGateway: EvmAddress;
signatureGateway: EvmAddress;
}
interface TokenInfo {
__typename: "TokenInfo";
id: TokenInfoId;
name: string;
symbol: string;
canonicalSymbol: string;
icon: string;
decimals: number;
categories: TokenCategory[];
}
fragment Hub on Hub {
__typename
id
address
chain {
...Chain
}
name
summary {
...HubSummary
}
}
fragment HubSummary on HubSummary {
__typename
totalBorrowed {
...ExchangeAmountWithChange
}
totalBorrowCap {
...ExchangeAmount
}
totalSupplied {
...ExchangeAmountWithChange
}
totalSupplyCap {
...ExchangeAmount
}
utilizationRate {
...PercentNumber
}
}
fragment ExchangeAmount on ExchangeAmount {
__typename
value
name
symbol
icon
decimals
}
fragment ExchangeAmountWithChange on ExchangeAmountWithChange {
__typename
current {
...ExchangeAmount
}
change {
...PercentNumber
}
}
fragment PercentNumber on PercentNumber {
__typename
onChainValue
decimals
value
normalized
}
fragment Chain on Chain {
__typename
chainId
name
icon
rpcUrl
explorerUrl
isTestnet
nativeWrappedToken
nativeInfo {
...TokenInfo
}
nativeGateway
signatureGateway
}
fragment TokenInfo on TokenInfo {
__typename
id
name
symbol
icon
decimals
categories
}
interface IHub {
function getAssetCount() external view returns (uint256);
function getAsset(uint256 assetId) external view returns (Asset memory);
function getAssetConfig(uint256 assetId) external view returns (AssetConfig memory);
function getSpokeCount(uint256 assetId) external view returns (uint256);
function getSpokeAddress(uint256 assetId, uint256 index) external view returns (address);
function getSpoke(uint256 assetId, address spoke) external view returns (SpokeData memory);
function getSpokeConfig(uint256 assetId, address spoke) external view returns (SpokeConfig memory);
function isSpokeListed(uint256 assetId, address spoke) external view returns (bool);
}
Listing Available Hubs
Discover all available Aave Liquidity Hubs across supported networks.
Use the use hook in React, the hubs action in TypeScript, or the hubs query in GraphQL to fetch a list of Liquidity Hubs.
import { type HubsRequest, useHubs } from "@aave/react";
function HubsList({ request }: { request: HubsRequest }) {
const { data, loading, error } = useHubs(request);
if (loading) return <div>Loading…</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
{data.map((hub) => (
<div key={hub.id}>
<h3>{hub.name}</h3>
<p>Chain: {hub.chain.name}</p>
</div>
))}
</div>
);
}
import { type HubsRequest, useHubs } from "@aave/react";
function HubsList({ request }: { request: HubsRequest }) {
const { data } = useHubs({
...request,
suspense: true,
});
return (
<div>
{data.map((hub) => (
<div key={hub.id}>
<h3>{hub.name}</h3>
<p>Chain: {hub.chain.name}</p>
</div>
))}
</div>
);
}
import { type HubsRequest, useHubsAction } from "@aave/react";
// …
const [fetch, { called, data, error, loading }] = useHubsAction();
const handler = async (request: HubsRequest) => {
const result = await fetch(request);
if (result.isOk()) {
console.log(result.value); // Hub[]
} else {
console.error(result.error);
}
};
import { chainId } from "@aave/client";
import { hubs } from "@aave/client/actions";
import { client } from "./client";
const result = await hubs(client, {
query: {
chainIds: [chainId(1)],
},
});
if (result.isErr()) {
console.error(result.error);
} else {
// result.value: Hub[]
console.log(result.value);
}
import { chainId, evmAddress } from "@aave/client";
import { hubs } from "@aave/client/actions";
import { client } from "./client";
const result = await hubs(client, {
query: {
tokens: [
{
address: evmAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC
chainId: chainId(1),
},
{
address: evmAddress("0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f"), // GHO
chainId: chainId(1),
},
],
},
});
import { assetId } from "@aave/client";
import { hubs } from "@aave/client/actions";
import { client } from "./client";
const result = await hubs(client, {
query: {
assetIds: [assetId("SGVsbG8h"), assetId("V29ybGQh")],
},
});
import { chainId, Currency } from "@aave/client";
import { hubs } from "@aave/client/actions";
import { client } from "./client";
const result = await hubs(
client,
{
query: {
chainIds: [chainId(1)],
},
},
{ currency: Currency.Eur },
);
import { AaveClient } from "@aave/client";
export const client = AaveClient.create();
query ($request: HubsRequest!) {
hubs(request: $request) {
id
address
chain {
...Chain
}
name
summary {
...HubSummary
}
}
}
use doesn’t watch for updates. Use it for on-demand fresh data,
such as in an event handler.
In React and GraphQL, see below for examples of Hubs objects.
import { chainId } from "@aave/react";
const request: HubsRequest = {
query: {
chainIds: [chainId(1)],
},
};
import { evmAddress, chainId } from "@aave/react";
const request: HubsRequest = {
query: {
tokens: [
{
address: evmAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"), // USDC
chainId: chainId(1),
},
{
address: evmAddress("0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f"), // GHO
chainId: chainId(1),
},
],
},
};
import { assetId } from "@aave/react";
const request: HubsRequest = {
query: {
assetIds: [assetId("SGVsbG8h"), assetId("V29ybGQh")],
},
};
{
"request": {
"query": {
"chainIds": [1]
}
}
}
{
"request": {
"query": {
"tokens": [
{
"address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"chainId": 1
},
{
"address": "0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f",
"chainId": 1
}
]
}
}
}
{
"request": {
"query": {
"assetIds": ["SGVsbG8h", "V29ybGQh"]
}
}
}
query ($request: HubsRequest!) {
hubs(request: $request) {
id
address
chain {
...Chain
}
name
summary(currency: EUR) {
...HubSummary
}
}
}
In React, you can also specify a different currency for the data.
import { Currency } from "@aave/react";
const { data, error, loading } = useHubs({
query: {
// your query criteria
},
currency: Currency.Eur,
});
Deployed Hubs
In Solidity, hubs are deployed and managed by governance. The following hubs are deployed on Ethereum Mainnet:
| Name | Address |
|---|---|
| Core Hub | 0x |
| Plus Hub | 0x06002e9c4412 |
| Prime Hub | 0x943827 |
Once a hub address is known, access its assets and spokes using the methods documented in the Hub Data Structure section above.
Fetching a Single Hub
Get detailed information about a specific Liquidity Hub.
Use the use hook in React, the hub action in TypeScript, or the hub query in GraphQL to fetch a specific hub by ID or by address and chain.
import { type HubRequest, useHub } from "@aave/react";
function HubDetails({ request }: { request: HubRequest }) {
const { data, loading, error } = useHub(request);
if (loading) return <div>Loading…</div>;
if (error) return <div>Error: {error.message}</div>;
if (!data) return <div>Hub not found</div>;
return (
<div>
<h2>{data.name}</h2>
<p>Address: {data.address}</p>
<p>Chain: {data.chain.name}</p>
</div>
);
}
import { type HubRequest, useHub } from "@aave/react";
function HubDetails({ request }: { request: HubRequest }) {
const { data } = useHub({
...request,
suspense: true,
});
if (!data) return <div>Hub not found</div>;
return (
<div>
<h2>{data.name}</h2>
<p>Address: {data.address}</p>
<p>Chain: {data.chain.name}</p>
</div>
);
}
import { hubId } from "@aave/client";
import { hub } from "@aave/client/actions";
import { client } from "./client";
const id = hubId("SGVsbG8h");
const result = await hub(client, {
query: {
hubId: id,
},
});
if (result.isOk()) {
console.log(result.value); // Hub | null - null if not found
} else {
console.error(result.error);
}
import { chainId, evmAddress } from "@aave/client";
import { hub } from "@aave/client/actions";
import { client } from "./client";
const result = await hub(client, {
query: {
hubInput: {
address: evmAddress("0x123…"),
chainId: chainId(1),
},
},
});
import { Currency } from "@aave/client";
import { hub } from "@aave/client/actions";
import { client } from "./client";
const result = await hub(
client,
{
query: {
/* your query criteria */
},
},
{ currency: Currency.Eur },
);
import { AaveClient } from "@aave/client";
export const client = AaveClient.create();
query {
hub(request: { query: { hubId: "SGVsbG8h" } }) {
id
address
chain {
...Chain
}
name
summary {
...HubSummary
}
}
}
query {
hub(request: { query: { hubInput: { address: "0x123…", chainId: 1 } } }) {
id
address
chain {
...Chain
}
name
summary {
...HubSummary
}
}
}
query {
hub(request: { query: { hubId: "SGVsbG8h" } }) {
id
address
chain {
...Chain
}
name
summary(currency: EUR) {
...HubSummary
}
}
}
In React, see below for examples of Hub objects.
import { hubId } from "@aave/react";
const request: HubRequest = {
query: {
hubId: hubId(params.id), // HubId - typically from URL params
},
};
import { chainId, evmAddress } from "@aave/react";
const request: HubRequest = {
query: {
hubInput: {
address: evmAddress("0x123…"),
chainId: chainId(1),
},
},
};
In React, pass time or currency with the request; in TypeScript, pass them in the third options argument of hub.
import { TimeWindow } from "@aave/react";
const { data, loading, error } = useHub({
query: {
// your query criteria
},
timeWindow: TimeWindow.LastWeek,
});
import { Currency } from "@aave/react";
const { data, loading, error } = useHub({
query: {
// your query criteria
},
currency: Currency.Eur,
});
Hub Summary History
Fetch historical summary data for a specific hub over a specified time window.
Use the use hook in React, the hub action in TypeScript, or the hub query in GraphQL to fetch historical summary data for a hub.
import {
type HubSummaryHistoryRequest,
useHubSummaryHistory,
} from "@aave/react";
function HubHistory({ request }: { request: HubSummaryHistoryRequest }) {
const { data, loading, error } = useHubSummaryHistory(request);
if (loading) return <div>Loading…</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
<h2>Hub History</h2>
{data.map((item) => (
<div key={item.date.toString()}>
<p>Date: {item.date.toLocaleDateString()}</p>
<p>
Deposits: {item.deposits.symbol}
{item.deposits.value.toDisplayString(2)}
</p>
<p>
Borrows: {item.borrows.symbol}
{item.borrows.value.toDisplayString(2)}
</p>
<p>Utilization: {item.utilizationRate.normalized.toFixed(2)}%</p>
</div>
))}
</div>
);
}
import {
type HubSummaryHistoryRequest,
useHubSummaryHistory,
} from "@aave/react";
function HubHistory({ request }: { request: HubSummaryHistoryRequest }) {
const { data } = useHubSummaryHistory({
...request,
suspense: true,
});
return (
<div>
<h2>Hub History</h2>
{data.map((item) => (
<div key={item.date.toString()}>
<p>Date: {item.date.toLocaleDateString()}</p>
<p>
Deposits: {item.deposits.symbol}
{item.deposits.value.toDisplayString(2)}
</p>
<p>
Borrows: {item.borrows.symbol}
{item.borrows.value.toDisplayString(2)}
</p>
</div>
))}
</div>
);
}
import { hubSummaryHistory } from "@aave/client/actions";
import { hubId, TimeWindow } from "@aave/client";
import { client } from "./client";
const result = await hubSummaryHistory(client, {
query: { hubId: hubId(id) },
window: TimeWindow.LastWeek,
});
if (result.isOk()) {
console.log(result.value); // HubSummarySample[]
} else {
console.error(result.error);
}
import { hubSummaryHistory } from "@aave/client/actions";
import { chainId, evmAddress, TimeWindow } from "@aave/client";
import { client } from "./client";
const result = await hubSummaryHistory(client, {
query: {
hubInput: {
address: evmAddress("0x123…"),
chainId: chainId(1),
},
},
window: TimeWindow.LastWeek,
});
query ($request: HubSummaryHistoryRequest!) {
hubSummaryHistory(request: $request) {
date
deposits {
...ExchangeAmount
}
borrows {
...ExchangeAmount
}
availableLiquidity {
...ExchangeAmount
}
utilizationRate {
...PercentNumber
}
}
}
- React: See below for examples of
Hubobjects.Summary History Request - GraphQL: Use the
queryandwindowfields to specify the hub and time period.
import { hubId, TimeWindow } from "@aave/react";
const request: HubSummaryHistoryRequest = {
query: { hubId: hubId(params.id) },
window: TimeWindow.LastWeek,
};
import { chainId, evmAddress, TimeWindow } from "@aave/react";
const request: HubSummaryHistoryRequest = {
query: {
hubInput: {
address: evmAddress("0x123…"),
chainId: chainId(1),
},
},
window: TimeWindow.LastWeek,
};
{
"request": {
"query": { "hubId": "SGVsbG8h" },
"window": "LAST_WEEK"
}
}
{
"request": {
"query": {
"hubInput": { "address": "0x123…", "chainId": 1 }
},
"window": "LAST_WEEK"
}
}
Specify the time window for the historical data. window accepts Time (default), Last, Last, Last, Last or All (GraphQL: LAST_, LAST_, LAST_, LAST_, LAST_, ALL).
import { hubId, TimeWindow } from "@aave/react";
const request: HubSummaryHistoryRequest = {
query: { hubId: hubId(params.id) },
window: TimeWindow.LastWeek,
};
import { hubSummaryHistory } from "@aave/client/actions";
import { hubId, TimeWindow } from "@aave/client";
import { client } from "./client";
const result = await hubSummaryHistory(client, {
query: { hubId: hubId(id) },
window: TimeWindow.LastWeek,
});
{
"request": {
"query": { "hubId": "SGVsbG8h" },
"window": "LAST_WEEK"
}
}
You can also specify a different currency for the data.
import { Currency, hubId, TimeWindow } from "@aave/react";
const { data, error, loading } = useHubSummaryHistory({
query: { hubId: hubId(params.id) },
window: TimeWindow.LastWeek,
currency: Currency.Eur,
});
import { hubSummaryHistory } from "@aave/client/actions";
import { hubId, TimeWindow, Currency } from "@aave/client";
import { client } from "./client";
const result = await hubSummaryHistory(client, {
query: { hubId: hubId(id) },
window: TimeWindow.LastWeek,
currency: Currency.Eur,
});
{
"request": {
"query": { "hubId": "SGVsbG8h" },
"window": "LAST_WEEK",
"currency": "EUR"
}
}
Hub Spoke Configs
Fetch per-asset configuration for a specific (hub, spoke) pair, including supply caps, borrow caps, operational status, and the risk premium threshold.
The Hub type describes each config.
interface HubSpokeConfig {
__typename: "HubSpokeConfig";
hub: Hub;
spoke: Spoke;
asset: HubAsset;
supplyCap: Erc20Amount;
borrowCap: Erc20Amount;
active: boolean;
halted: boolean;
riskPremiumThreshold: PercentNumber;
}
fragment HubSpokeConfig on HubSpokeConfig {
__typename
hub {
...Hub
}
spoke {
...Spoke
}
asset {
...HubAsset
}
supplyCap {
...Erc20Amount
}
borrowCap {
...Erc20Amount
}
active
halted
riskPremiumThreshold {
...PercentNumber
}
}
Use the use hook in React, the hub action in TypeScript, or the hub query in GraphQL to fetch all asset configs shared by a hub and spoke.
import { type HubId, type SpokeId, useHubSpokeConfigs } from "@aave/react";
function HubSpokeConfigs({ hubId, spokeId }: { hubId: HubId; spokeId: SpokeId }) {
const { data, loading, error } = useHubSpokeConfigs({ hubId, spokeId });
if (loading) return <div>Loading…</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{data.map((config) => (
<li key={config.asset.id}>
{config.asset.underlying.info.symbol}: {config.active ? "Active" : "Inactive"}
</li>
))}
</ul>
);
}
import { type HubId, type SpokeId, useHubSpokeConfigs } from "@aave/react";
function HubSpokeConfigs({ hubId, spokeId }: { hubId: HubId; spokeId: SpokeId }) {
const { data } = useHubSpokeConfigs({
suspense: true,
hubId,
spokeId,
});
return (
<ul>
{data.map((config) => (
<li key={config.asset.id}>
{config.asset.underlying.info.symbol}: {config.active ? "Active" : "Inactive"}
</li>
))}
</ul>
);
}
import { hubId, spokeId } from "@aave/client";
import { hubSpokeConfigs } from "@aave/client/actions";
import { client } from "./client";
const result = await hubSpokeConfigs(client, {
hubId: hubId("SGVsbG8h"),
spokeId: spokeId("SGVsbG8h"),
});
if (result.isOk()) {
console.log(result.value); // HubSpokeConfig[]
} else {
console.error(result.error);
}
import { AaveClient } from "@aave/client";
export const client = AaveClient.create();
query {
hubSpokeConfigs(request: { hubId: "SGVsbG8h", spokeId: "SGVsbG8h" }) {
hub {
name
}
spoke {
name
}
asset {
underlying {
info {
symbol
}
}
}
supplyCap {
amount {
value
}
}
borrowCap {
amount {
value
}
}
active
halted
riskPremiumThreshold {
value
}
}
}
Hub Assets
Hub Assets are the ERC-20 tokens held by a given Hub.
Hub Asset Data Structure
Hub Asset data provides detailed information about each asset available on a Liquidity Hub, including:
- Identification: id, onchainAssetId, underlying token details
- Hub reference: the hub where this asset is available
- Summary metrics: supplied/borrowed amounts, APY rates, utilization
- Reserve coverage: total connected reserves and active reserves
- Settings: fee receiver, liquidity fees, strategies
- User state: user’s balance (when user is specified in request)
interface HubAsset {
__typename: "HubAsset";
id: HubAssetId;
onchainAssetId: OnChainHubAssetId;
hub: Hub;
underlying: Erc20Token;
summary: HubAssetSummary;
settings: HubAssetSettings;
userState: HubAssetUserState | null;
}
interface HubAssetSummary {
__typename: "HubAssetSummary";
supplied: Erc20Amount;
borrowed: Erc20Amount;
availableLiquidity: Erc20Amount;
supplyApy: PercentNumber;
borrowApy: PercentNumber;
netApy: PercentNumber;
utilizationRate: PercentNumber;
reservesCount: number;
activeReservesCount: number;
}
interface HubAssetSettings {
__typename: "HubAssetSettings";
feeReceiver: EvmAddress;
liquidityFee: PercentNumber;
irStrategy: EvmAddress;
reinvestmentController: EvmAddress | null;
optimalUtilizationRate: PercentNumber;
baseBorrowRate: PercentNumber;
slopeBelowOptimal: PercentNumber;
slopeAboveOptimal: PercentNumber;
}
interface HubAssetUserState {
__typename: "HubAssetUserState";
balance: Erc20Amount;
}
fragment HubAsset on HubAsset {
__typename
id
onchainAssetId
hub {
...Hub
}
underlying {
...Erc20Token
}
summary {
...HubAssetSummary
}
settings {
...HubAssetSettings
}
userState {
...HubAssetUserState
}
}
fragment HubAssetSummary on HubAssetSummary {
__typename
supplied {
...Erc20Amount
}
borrowed {
...Erc20Amount
}
availableLiquidity {
...Erc20Amount
}
supplyApy {
...PercentNumber
}
borrowApy {
...PercentNumber
}
netApy {
...PercentNumber
}
utilizationRate {
...PercentNumber
}
reservesCount
activeReservesCount
}
fragment HubAssetSettings on HubAssetSettings {
__typename
feeReceiver
liquidityFee {
...PercentNumber
}
irStrategy
reinvestmentController
optimalUtilizationRate {
...PercentNumber
}
baseBorrowRate {
...PercentNumber
}
slopeBelowOptimal {
...PercentNumber
}
slopeAboveOptimal {
...PercentNumber
}
}
fragment HubAssetUserState on HubAssetUserState {
__typename
balance {
...Erc20Amount
}
}
struct Asset {
uint120 liquidity;
uint120 realizedFees;
uint8 decimals;
uint120 addedShares;
uint120 swept;
int200 premiumOffsetRay;
uint120 drawnShares;
uint120 premiumShares;
uint16 liquidityFee;
uint120 drawnIndex;
uint96 drawnRate;
uint40 lastUpdateTimestamp;
address underlying;
address irStrategy;
address reinvestmentController;
address feeReceiver;
uint200 deficitRay;
}
struct AssetConfig {
address feeReceiver;
uint16 liquidityFee;
address irStrategy;
address reinvestmentController;
}
Listing Hub Assets
Discover all available assets on a Hub, including their liquidity metrics, APY rates, and user-specific data.
Use the use hook in React, the hub action in TypeScript, or the hub query in GraphQL to fetch assets for a specific hub. In Solidity, assets within the hub are assigned sequential asset values starting from 0. For reference, here’s a complete function to retrieve all Hub Assets.
import { type HubAssetsRequest, useHubAssets } from "@aave/react";
function HubAssetsList({ request }: { request: HubAssetsRequest }) {
const { data, loading, error } = useHubAssets(request);
if (loading) return <div>Loading…</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<div>
{data.map((asset) => (
<div key={asset.id}>
<h3>{asset.underlying.info.name}</h3>
<p>Hub: {asset.hub.name}</p>
</div>
))}
</div>
);
}
import { type HubAssetsRequest, useHubAssets } from "@aave/react";
function HubAssetsList({ request }: { request: HubAssetsRequest }) {
const { data } = useHubAssets({
...request,
suspense: true,
});
return (
<div>
{data.map((asset) => (
<div key={asset.id}>
<h3>{asset.underlying.info.name}</h3>
<p>Hub: {asset.hub.name}</p>
</div>
))}
</div>
);
}
import { hubId } from "@aave/client";
import { hubAssets } from "@aave/client/actions";
import { client } from "./client";
const id = hubId("SGVsbG8h");
const result = await hubAssets(client, {
query: {
hubId: id,
},
});
if (result.isOk()) {
console.log(result.value); // HubAsset[]
} else {
console.error(result.error);
}
import { chainId, evmAddress } from "@aave/client";
import { hubAssets } from "@aave/client/actions";
import { client } from "./client";
const result = await hubAssets(client, {
query: {
hubInput: {
address: evmAddress("0x123…"),
chainId: chainId(1),
},
},
});
import { Currency } from "@aave/client";
import { hubAssets } from "@aave/client/actions";
import { client } from "./client";
const result = await hubAssets(
client,
{
query: {
// your query criteria
},
},
{
currency: Currency.Eur,
},
);
import { AaveClient } from "@aave/client";
export const client = AaveClient.create();
query {
hubAssets(request: { query: { hubId: "SGVsbG8h" } }) {
id
onchainAssetId
hub {
...Hub
}
underlying {
...Erc20Token
}
summary {
...HubAssetSummary
}
settings {
...HubAssetSettings
}
userState {
...HubAssetUserState
}
}
}
query {
hubAssets(
request: { query: { hubInput: { address: "0x123…", chainId: 1 } } }
) {
id
onchainAssetId
hub {
...Hub
}
underlying {
...Erc20Token
}
summary {
...HubAssetSummary
}
settings {
...HubAssetSettings
}
userState {
...HubAssetUserState
}
}
}
query {
hubAssets(request: { query: { hubId: "SGVsbG8h" } }) {
id
onchainAssetId
hub {
...Hub
}
underlying {
...Erc20Token
}
summary(currency: EUR) {
...HubAssetSummary
}
}
}
query {
hubAssets(request: { query: { hubId: "SGVsbG8h" }, user: "0x456…" }) {
id
onchainAssetId
hub {
...Hub
}
underlying {
...Erc20Token
}
summary {
...HubAssetSummary
}
userState {
...HubAssetUserState
}
}
}
import { IHub } from "aave-v4/src/hub/interfaces/IHub.sol";
contract HubReader {
function getHubAssets(
address hubAddress
) external view returns (IHub.Asset[] memory) {
IHub hub = IHub(hubAddress);
uint256 assetCount = hub.getAssetCount();
IHub.Asset[] memory assets = new IHub.Asset[](assetCount);
for (uint256 assetId = 0; assetId < assetCount; assetId++) {
assets[assetId] = hub.getAsset(assetId);
}
return assets;
}
}
In React, see below for examples of Hub objects.
const request: HubAssetsRequest = {
query: {
hubId: hub.id, // hub.id: HubId from component props or previous query
},
};
import { chainId, evmAddress } from "@aave/react";
const request: HubAssetsRequest = {
query: {
hubInput: {
address: evmAddress("0x123…"),
chainId: chainId(1),
},
},
};
In React and TypeScript, you can add a user address to return Hub for each asset.
import { evmAddress } from "@aave/react";
const request: HubAssetsRequest = {
query: {
// your query criteria
},
user: evmAddress("0x456…"),
};
import { evmAddress } from "@aave/client";
import { hubAssets } from "@aave/client/actions";
import { client } from "./client";
const result = await hubAssets(client, {
query: {
// your query criteria
},
user: evmAddress("0x456…"),
});
In React, you can also specify a different currency for the data.
import { Currency } from "@aave/react";
// …
const { data, loading, error } = useHubAssets({
query: {
// your query criteria
},
currency: Currency.Eur,
});
Interest Rate Model
The interest rate model describes how supply and borrow rates change across the utilization range for a specific Hub Asset. Each data point includes the utilization rate, the corresponding borrow and supply rates, and the liquidity distance from the current state.
interface HubAssetInterestRateModelPoint {
__typename: "HubAssetInterestRateModelPoint";
utilizationRate: PercentNumber;
borrowRate: PercentNumber;
supplyRate: PercentNumber;
liquidityDistance: Erc20Amount;
}
fragment HubAssetInterestRateModelPoint on HubAssetInterestRateModelPoint {
__typename
utilizationRate {
...PercentNumber
}
borrowRate {
...PercentNumber
}
supplyRate {
...PercentNumber
}
liquidityDistance {
...Erc20Amount
}
}
Fetch the full interest rate curve for a specific Hub Asset.
Use the use hook to fetch the interest rate curve for a Hub Asset.
import { useHubAssetInterestRateModel } from "@aave/react";
function InterestRateModel({ hubAssetId }: { hubAssetId: HubAssetId }) {
const { data, loading, error } = useHubAssetInterestRateModel({
query: { hubAssetId },
});
if (loading) return <p>Loading…</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div>
{data?.map((point, i) => (
<div key={i}>
<span>Utilization: {point.utilizationRate.normalized.toFixed(2)}%</span>
<span>Borrow Rate: {point.borrowRate.normalized.toFixed(2)}%</span>
<span>Supply Rate: {point.supplyRate.normalized.toFixed(2)}%</span>
</div>
))}
</div>
);
}
import { useHubAssetInterestRateModel } from "@aave/react";
function InterestRateModel({ hubAssetId }: { hubAssetId: HubAssetId }) {
const { data } = useHubAssetInterestRateModel({
suspense: true,
query: { hubAssetId },
});
return (
<div>
{data.map((point, i) => (
<div key={i}>
<span>Utilization: {point.utilizationRate.normalized.toFixed(2)}%</span>
<span>Borrow Rate: {point.borrowRate.normalized.toFixed(2)}%</span>
<span>Supply Rate: {point.supplyRate.normalized.toFixed(2)}%</span>
</div>
))}
</div>
);
}
Use the hub action to fetch the interest rate curve.
import { type HubAssetId } from "@aave/client";
import { hubAssetInterestRateModel } from "@aave/client/actions";
import { client } from "./client";
// const hubAssetId: HubAssetId = "…"; // from a previous query
const result = await hubAssetInterestRateModel(client, {
query: { hubAssetId },
});
if (result.isOk()) {
for (const point of result.value) {
console.log(
point.utilizationRate.value,
point.borrowRate.value,
point.supplyRate.value,
);
}
} else {
console.error(result.error);
}
import { AaveClient } from "@aave/client";
export const client = AaveClient.create();
Use the hub query to fetch the interest rate curve.
query {
hubAssetInterestRateModel(request: { query: { hubAssetId: "…" } }) {
points {
utilizationRate {
...PercentNumber
}
borrowRate {
...PercentNumber
}
supplyRate {
...PercentNumber
}
liquidityDistance {
...Erc20Amount
}
}
}
}