Supply Assets
Learn how to earn interest on Aave v4 and use assets as collateral for borrowing.
Supplying assets to Aave v4 allows you to:
Receive reserve shares representing your deposit
Earn variable supply APY on your reserve shares
Use reserve shares as collateral for borrowing
Withdraw assets and earnings anytime
Supplying assets as collateral while having an open borrow position may increase the position's health factor.
Supplying
Supplying assets to Aave can be broken down into the following steps:
Identify the Reserve
Preview the impact of the supply operation (optional)
Supply the assets
Identify the Reserve
The first step is to filter the supply reserves to those marked with canSupply: true.
Reserves List
const reserves: Reserve[] = [ { id: "SGVsbG8h", onChainId: "42", canSupply: true, supplyCap: BigDecimal(2000000000.0), // 2B USDC // … }, { id: "V29ybGQh", onChainId: "43", canSupply: false, // cannot supply to this reserve supplyCap: BigDecimal(1000000000.0), // 1B USDC // … }, // …];The canSupply flag confirms that the reserve is active: it isn’t frozen, it isn’t paused, and the supply cap has not been reached.
From the remaining reserves, choose one that meets these criteria:
Collateral Enabled: The reserve can be used as collateral (canUseAsCollateral) if you plan to borrow against it.
Suppliable Amount: The userState.suppliable value is sufficient for the amount you want to supply.
Example Reserve Data
const reserve: Reserve = { id: "SGVsbG8h", onChainId: "42", supplyCap: BigDecimal(2000000000.0), // 2B USDC canSupply: true, canUseAsCollateral: true, chain: { chainId: 1, name: "Ethereum", }, spoke: { address: "0x123…", // … }, status: { frozen: false, paused: false, }, userState: { suppliable: { amount: { onChainValue: "1000000000", decimals: 6, value: BigDecimal(1000.0), // Can supply up to 1,000 USDC }, // … }, // … }, // …};Make sure you include a user address when fetching reserve data—otherwise userState will be null.
Preview Supply
Preview the impact of a supply operation before committing to it.
- React
- TypeScript
- GraphQL
- Solidity
Use the usePreview hook (or the imperative usePreviewAction variant) to preview the impact of the supply operation on the user's position.
See below for examples of SupplyRequest objects.
The PreviewUserPosition shows the impact of the supply operation by comparing current and after states, with the table below outlining key fields and how to interpret them.
| Field | Impact | |
|---|---|---|
| healthFactor.[current → after]: BigDecimal|null | Higher is better (null if not applicable) | |
| netApy.[current → after]: PercentNumber | Higher is better | |
| netCollateral.[current → after]: ExchangeAmount | Higher is better | |
| netBalance.[current → after]: ExchangeAmount | Updated balance | |
| projectedEarning.[current → after]: ExchangeAmount | Projected earnings | |
| borrowingPower.[current → after]: ExchangeAmount | Borrowing power |
Supplying assets as collateral updates the Dynamic Config just for the reserve being supplied as collateral.
The otherConditions field is an array of objects describing the resulting dynamic config changes.
CollateralFactorVariation – Collateral factor change
LiquidationFeeVariation – Liquidation fee change
MaxLiquidationBonusVariation – Maximum liquidation bonus change
You can also specify a different currency to return fiat amounts in.
Step-by-Step
Now that you know how to identify a reserve and preview the impact of a supply operation, let's supply assets to a reserve.
Supplying ERC-20 tokens requires token approval. You can choose between two approaches:
Transaction-based approval — Sends a separate ERC-20 approve() transaction before the supply transaction (2 transactions total).
Permit-based approval — Signs an EIP-2612 permit to approve and supply in a single transaction. More gas-efficient, but requires the token to support permits.
- React
- TypeScript
- GraphQL
- Solidity
To supply assets to an Aave reserve with AaveKit React, follow these steps.
First, instantiate the hooks for the wallet library of your choice:
useSendTransaction — used to send ERC-20 approval and supply transactions
useSignTypedData — used to sign ERC-20 permits when available
Viem
import { useWalletClient } from "wagmi";import { useSendTransaction, useSignTypedData } from "@aave/react/viem";
// …
const { data: wallet } = useWalletClient();const [sendTransaction] = useSendTransaction(wallet);const [signTypedData] = useSignTypedData(wallet);Then, use the useSupply hook to prepare the supply operation.
In the Erc20Approval case, the bySignature field is only available if the token supports EIP-2612 permits.
For tokens like USDT on Ethereum Mainnet that require an allowance reset, the hook calls your callback twice: once to reset the allowance to 0, then again to set the new value. bySignature will be null for these approvals.
Finally, handle the result.
Example
const execute = async () => { const result = await supply(/* … */);
if (result.isErr()) { switch (result.error.name) { case "CancelError": // The user cancelled the operation return;
case "SigningError": console.error( `Failed to sign the transaction: ${result.error.message}`, ); break;
case "TimeoutError": console.error(`Transaction timed out: ${result.error.message}`); break;
case "TransactionError": console.error(`Transaction failed: ${result.error.message}`); break;
case "ValidationError": console.error( "Insufficient balance:", `required: ${result.error.cause.required.value.toDisplayString(2)}`, `available: ${result.error.cause.available.value.toDisplayString(2)}`, ); break;
case "UnexpectedError": console.error(result.error.message); break; } return; }
console.log("Supply successful with hash:", result.value);};Collateral Management
Manage how user supplies are used as collateral for borrowing. The process can be broken down into three steps:
Identify the supply position
Preview the impact of changing collateral status
Toggle the collateral status
Identify the Supply Position
First, identify the supply position you want to modify from the user's supply positions.
UserSupplyItem
const supplyPosition: UserSupplyItem = { reserve: { id: "SGVsbG8h", onChainId: "42", chain: { chainId: 1, name: "Ethereum", }, spoke: { address: "0x123…", // … }, canUseAsCollateral: true, // … }, isCollateral: false, principal: { amount: { value: BigDecimal(42.0), }, // … }, interest: { amount: { value: BigDecimal(4.2), }, // … },};The corresponding reserve needs to have canUseAsCollateral: true to be possible to use as collateral.
Preview Changes
Preview the impact of changing collateral status before executing the transaction.
Disabling a supplied asset as collateral may reduce the position's health factor. In some cases, this may put the position at risk of being liquidated.
- React
- TypeScript
- GraphQL
- Solidity
Use the usePreview hook (or the imperative usePreviewAction variant) to preview the impact of collateral status changes on the user's position.
Where the SetUserSuppliesAsCollateralRequest can be as follows:
The PreviewUserPosition shows the impact of the collateral status change by comparing current and after states, with the table below outlining key fields and how to interpret them.
| Field | Impact | |
|---|---|---|
| healthFactor.[current → after]: BigDecimal|null | Higher is better (null if not applicable) | |
| riskPremium.[current → after]: PercentNumber | Lower is better | |
| netApy.[current → after]: PercentNumber | Higher is better | |
| netCollateral.[current → after]: ExchangeAmount | Higher is better | |
| borrowingPower.[current → after]: ExchangeAmount | Borrowing power | |
| otherConditions: UserPositionConditionVariation[] | Dynamic config changes |
Enabling collateral updates the Dynamic Config just for the reserve being enabled, while disabling collateral updates the Dynamic Config for all reserves in which the user has supplies or borrows within the same user position.
The otherConditions field is an array of objects describing the resulting dynamic config changes.
CollateralFactorVariation – Collateral factor change
LiquidationFeeVariation – Liquidation fee change
MaxLiquidationBonusVariation – Maximum liquidation bonus change
You can also specify a different currency to return fiat amounts in.
Step-by-Step
Toggle the collateral status of any supplied asset using the following steps.
Enabling collateral updates the Dynamic Config—Collateral Factor, Liquidation Fee, and Max Liquidation Bonus—for the supplied asset. Disabling collateral is a risk-increasing action that updates the Dynamic Config and, consequently, the User Risk Premium for the entire user position. See User Position Conditions for more details.
- React
- TypeScript
- GraphQL
- Solidity
To enable or disable a supplied asset as collateral, follow these steps.
First, instantiate the useSendTransaction hook for the wallet library of your choice.
Viem
import { useWalletClient } from "wagmi";import { useSendTransaction } from "@aave/react/viem";
// …
const { data: wallet } = useWalletClient();const [sendTransaction] = useSendTransaction(wallet);Use the useSetUserSuppliesAsCollateral hook to prepare the transaction request.
Then, update the collateral status.
Set Collateral
import { evmAddress } from "@aave/react";
const execute = async () => { const result = await setAsCollateral({ sender: evmAddress(wallet.account.address), // User's address changes: [ { reserve: supplyPosition.reserve.id, enableCollateral: true, }, ], });};
// …Finally, handle the result.
Example
const execute = async () => { const result = await setAsCollateral(/* … */);
if (result.isErr()) { switch (result.error.name) { case "CancelError": // The user cancelled the operation return;
case "SigningError": console.error( `Failed to sign the transaction: ${result.error.message}`, ); break;
case "TimeoutError": console.error(`Transaction timed out: ${result.error.message}`); break;
case "TransactionError": console.error(`Transaction failed: ${result.error.message}`); break;
case "UnexpectedError": console.error(result.error.message); break; } return; }
console.log("Collateral set successful with hash:", result.value);};Advanced Usage
Network Fee
This experimental AaveKit React hook currently works only with Viem or Wagmi integrations. Support for additional wallet libraries may be added later.
Estimate the network cost of any action using the same PreviewAction you pass to the usePreview hook.
Let's consider the following example:
PreviewAction
import { type PreviewAction } from "@aave/react";
const action: PreviewAction = { supply: { sender: evmAddress("0x123…"), // User's address reserve: supplyPosition.reserve.id, amount: { erc20: { value: bigDecimal(42), // USDC }, }, },};Use the useNetworkFee hook to estimate both the network fee for the provided action and its fiat equivalent.
Viem
import { type PreviewAction, Currency } from "@aave/react";import { useNetworkFee } from "@aave/react/viem";
function NetworkFee({ action }: { action: PreviewAction }) { const { data: fee, loading, error, } = useNetworkFee({ query: { estimate: action }, currency: Currency.Eur, });
if (loading) return <p>Loading fee…</p>; if (error) return <p>Error: {error.message}</p>;
return ( <p> Network Fee: {fee.amount.value.toDisplayString(2)} {fee.token.info.symbol} <span> ≈{fee.exchange.symbol} {fee.exchange.value.toDisplayString(2)} </span> </p> );}Native Tokens
When the Reserve's underlying token is the wrapped version of the chain's native token (e.g., WETH on Ethereum), you can supply the asset as the chain's native token using the Native Token Gateway.
Use the reserve.asset.underlying.isWrappedNativeToken flag to determine if the underlying token is a wrapped native token. The Native Gateway address is available from the chain details.
WETH Reserve
const reserve: Reserve = { id: "SGVsbG8h", onChainId: "42", supplyCap: BigDecimal(2000000000.0), // 2B WETH canSupply: true, canUseAsCollateral: true, asset: { underlying: { address: "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", info: { name: "Wrapped Ether", symbol: "WETH", decimals: 18, // … }, isWrappedNativeToken: true, // … }, // … }, spoke: { address: "0x123…", // … }, chain: { chainId: 1, name: "Ethereum", nativeGateway: "0xabc…", }, // …};Specify the amount in the amount field as a native value.
- React
- TypeScript
- GraphQL
- Solidity
Supply Native
const execute = async () => { const result = await supply({ sender: evmAddress(wallet.account.address), // User's address reserve: reserve.id, amount: { native: bigDecimal(42), // 42 ETH }, });
// …};