React
The Aave React SDK is a collection of React hooks for building decentralized applications on top of the Aave Protocol. It provides a simple and type-safe way to interact with Aave markets, manage user positions, and execute transactions.
Getting Started
To get started, follow the steps below.
Then, create an AaveClient instance that will be used to interact with the protocol.
client.ts
import { AaveClient } from "@aave/react";
export const client = AaveClient.create();
You don't need to install the @aave/client package as it's already included and re-exported by the @aave/react package.
Next, wrap your app with the <AaveProvider> component and pass the client instance.
App.tsx
import { AaveProvider } from "@aave/react";
import { client } from "./client";
export function App() { return ( <AaveProvider client={client}> {/* Your application components */} </AaveProvider> );}
That's it—you can now start using the Aave React SDK.
Example
import { useAaveChains } from "@aave/react";
export function SupportedChains() { const { data: chains } = useAaveChains();
return ( <div> <h2>Supported Chains</h2> {chains?.map((chain) => ( <div key={chain.id}> <h3>{chain.name}</h3> <p>Chain ID: {chain.id}</p> </div> ))} </div> );}
Integrations
The Aave React SDK includes first-class support for viem, ethers v6, Privy, Dynamic and thirdweb.
- Viem
- Ethers
- Privy
- Dynamic
- thirdweb
Ensure you have viem package installed in your project.
Send Aave Transactions
To send transactions through the connected wallet, use the useSendTransaction action hook.
const [sendTransaction, { loading, error }] = useSendTransaction(/* args */);
This hook abstracts the wallet interaction and provides a simple interface for submitting transactions.
- Viem
- Ethers
- Privy
- Dynamic
- thirdweb
Import the useSendTransaction hook from the @aave/react/viem entry point and wire it up with the viem's WalletClient.
Viem
import { useSendTransaction } from "@aave/react/viem";import { useWalletClient } from "wagmi";
function MyComponent() { const { data: walletClient } = useWalletClient(); const [sendTransaction, sending] = useSendTransaction(walletClient);
// Use with transaction hooks…}
The example uses wagmi to get the WalletClient from the connected wallet.
Then, use it as describe in the specific page.
Sign ERC-20 Permits
Aave makes use of EIP-2612 to allow users to avoid ERC-20 approval before sending transactions.
Use the useERC20Permit hook to sign ERC-20 permits.
- Viem
- Ethers
- Privy
- Dynamic
- thirdweb
Import the useERC20Permit hook from the @aave/react/viem entry point and wire it up with the viem's WalletClient.
Viem
import { useERC20Permit } from "@aave/react/viem";import { useWalletClient } from "wagmi";
function MyComponent() { const { data: walletClient } = useWalletClient(); const [sendTransaction, sending] = useERC20Permit(walletClient);
// Use with transaction hooks…}
The example uses wagmi to get the WalletClient from the connected wallet.
Then, use it as describe in the specific page.
Read Hooks
All read hooks (market data, user positions, etc.) support two ways of operating: loading state and React Suspense.
Loading State
Handle loading state manually in your component:
Loading States
function ChainsList() { const { data, loading, error } = useAaveChains();
if (loading) return <div>Loading…</div>;
if (error) return <div>Error: {error.message}</div>;
return ( <div> {data.map((chain) => ( <div key={chain.id}>{chain.name}</div> ))} </div> );}
React Suspense
Let React handle loading states automatically through a Suspense boundary.
With Suspense
// Component - no loading states neededfunction ChainsList() { const { data: chains } = useAaveChains({ suspense: true, // Enable suspense mode });
return ( <div> {chains.map((chain) => ( <div key={chain.id}>{chain.name}</div> ))} </div> );}
// Parent - wrap with Suspense boundaryfunction ChainsPage() { return ( <Suspense fallback={<div>Loading …</div>}> <ChainsList /> </Suspense> );}
Action Hooks
The Aave React SDK provides action hooks that are designed to be triggered manually when you need to perform an operation. Action hooks return an execute function and a state object.
const [execute, state] = useActionHook();
Execute Function
The execute function returns a ResultAsync<T, E>, a thenable object that represents one of two states:
Ok<T>: A successful result containing a value of type T
Err<E>: A failure containing an error of type E
Awaiting a ResultAsync<T, E> resolves to a Result<T, E>.
With a Result<T, E>, you can use the convenient isOk() and isErr() methods to check the outcome and narrow the type.
If you have a ResultAsync<T, E>, you must first await it to access those methods.
const result = await execute();
if (result.isOk()) { console.log("Result:", result.value);} else { console.error("Error:", result.error);}
This approach avoids reliance on try/catch blocks and promotes predictable, type-safe code by ensuring errors are handled explicitly.
See the NeverThrow documentation for more information. The NeverThrow library is re-exported for convenience.
State Object
The state object returned by action hooks provides information about the current operation status:
const { called, data, error, loading } = state;
Where:
called: true when the operation has been executed at least once, false otherwise
data: Contains the last successful result of type T, undefined otherwise
error: Contains the error of type E if the operation failed, undefined otherwise
loading: true when the operation is in progress, false otherwise
Transaction Hooks
Transaction hooks are a specific type of action hook that handle protocol interactions like supply, borrow, withdraw, repay, and more.
There are two types of transaction hooks:
Simple transactions - single transactions that can be sent directly to the wallet
Complex transactions - transactions that could require approval beforehand
Simple Transactions
To handle a simple transaction hook, follow the steps below.
First, instantiate the transaction hook and the useSendTransaction hook according to the wallet provider you are using.
Instantiate Hooks
const [prepare, preparing] = useSimpleTransaction();const [sendTransaction, sending] = useSendTransaction(/* … */);
Next, execute the transaction in your app by chaining the prepare and send operations.
const result = await prepare(/* args */).andThen(sendTransaction);
Optionally, combine the state objects to drive your UI components.
const loading = preparing.loading && sending.loading;const error = preparing.error || sending.error;
Complex Transactions
To handle a complex transaction hook, follow the steps below.
First, instantiate the transaction hook and the useSendTransaction hook according to the wallet provider you are using.
Instantiate Hooks
const [prepare, preparing] = useComplexTransaction();const [sendTransaction, sending] = useSendTransaction(/* … */);
Optionally, combine the state objects to drive your UI components.
const loading = preparing.loading && sending.loading;const error = preparing.error || sending.error;
Next, handle the execution plan in your transaction flow. Some operations may require token approval before executing the main transaction.
import { errAsync } from "@aave/react";
const result = await prepare(/* args */).andThen((plan) => { switch (plan.__typename) { case "TransactionRequest": return sendTransaction(plan);
case "ApprovalRequired": return sendTransaction(plan.approval).andThen(() => sendTransaction(plan.originalTransaction) );
case "InsufficientBalanceError": return errAsync( new Error(`Insufficient balance: ${plan.required.value} required.`) ); }});
// …
If you wish to ask the user for confirmation before sending the transaction, you can do so by integrating your app's confirmation UI at this point.
Next Steps
Aave Markets - Learn how to interact with Aave markets.
Aave Vaults - Learn how to interact with Aave vaults.