Repay Loans
Learn how to repay borrowed assets to Aave v4 reserves.
Repaying borrowed assets allows you to:
Reduce or eliminate your debt position
Improve your position's health factor and reduce liquidation risk
Free up collateral for withdrawal or additional borrowing
Close your borrow position entirely when repaying the full amount
Repaying borrowed assets improves the position's health factor and reduces liquidation risk. You can repay partial amounts or the full debt amount.
Repaying
Repaying a loan can be broken down into the following steps:
Identify the borrow position to repay
Preview the impact of the repay operation
Repay the borrowed assets
Identify the Borrow Position
Given a list of the user's borrow positions, identify the position (token) you want to reduce and choose the repayment amount (partial or full).
The borrowed position reserve should not be paused in order to repay.
For example, let’s say you have identified the following UserBorrowItem object.
Example UserBorrowItem
const borrowPosition: UserBorrowItem = { reserve: { id: "SGVsbG8h", onChainId: "42", chain: { chainId: 1, name: "Ethereum", }, spoke: { address: "0x123…", // … }, asset: { underlying: { address: "0xa0b86a33e6e2ad05ad6c9ac3b6e5e5f6e7b6c1b2", // USDC }, // … }, status: { paused: false, }, // … other reserve properties }, debt: { amount: { value: "512.023456", // ~512 USDC debt // … }, // … }, // …};Keep in mind that repaying:
Improves your health factor, reducing liquidation risk.
Frees up collateral, making it available for withdrawal or additional borrowing.
Can be partial (reducing debt but keeping the position open) or full (closing the borrow position entirely).
Preview Repay
Preview the impact of a repay operation before committing to it.
- React
- TypeScript
- GraphQL
- Solidity
Use the usePreview hook (or the imperative usePreviewAction variant) to preview the impact of the repay operation on the user's position.
Where the RepayRequest can be as follows:
You can also specify a different currency to return fiat amounts in.
The PreviewUserPosition shows the impact of the repay operation by comparing current and after states, with the table below outlining key fields and how to interpret them.
| Current → After | Impact | |
|---|---|---|
| healthFactor?.current → healthFactor?.after: BigDecimal | Higher is better | |
| riskPremium.current → riskPremium.after: PercentNumber | Lower is better | |
| netApy.current → netApy.after: PercentNumber | Higher is better | |
| netCollateral.current → netCollateral.after: FiatAmount | Higher is better | |
| netBalance.current → netBalance.after: FiatAmount | Updated balance |
Step-by-Step
Now that we know how to identify a borrow position to repay, and we know how to preview the impact of a repay operation, let's see how to repay assets for this position.
- React
- TypeScript
- GraphQL
- Solidity
To repay borrowed assets to an Aave reserve with AaveKit React, 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);Finally, handle the result.
Example
const execute = async () => { const result = await repay(/* … */);
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: ${result.error.cause.available.value} available.` ); break;
case "UnexpectedError": console.error(result.error.message); break; } return; }
console.log("Repay 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 = { repay: { sender: evmAddress("0x123…"), // User's address reserve: borrowPosition.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.fiatAmount.symbol} {fee.fiatAmount.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 repay the debt using the chain's native token with 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 Borrow Position
const borrowPosition: UserBorrowItem = { reserve: { id: "SGVsbG8h", onChainId: "42", 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
ERC-20 Permits
Repay operations support ERC-20 permit functionality using EIP-2612 signatures to authorize ERC-20 token transfers within the same transaction. The permit approach has a few benefits:
Single Transaction: Execute operations without separate approval transactions
Exact Amounts: Sign permissions for specific amounts instead of infinite approvals
Time Limited: Permits have deadlines for enhanced security
Use the reserve.asset.underlying.permitSupported flag to determine if the underlying token supports EIP-2612 permits.
USDC Borrow Position
const borrowPosition: UserBorrowItem = { reserve: { id: "SGVsbG8h", onChainId: "42", asset: { underlying: { address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", info: { name: "USD Coin", symbol: "USDC", decimals: 6, // … }, permitSupported: true, // … }, // … }, chain: { chainId: 1, name: "Ethereum", signatureGateway: "0xabc…", }, // … }, // …};If the underlying token supports EIP-2612 permits, you can use this alternate approach to repay ERC-20 tokens.
- React
- TypeScript
- GraphQL
The process outlined here assumes you have familiarity with the standard repay operation flow.
First, instantiate the useERC20Permit hook for the wallet library of your choice.
Viem
import { useWalletClient } from "wagmi";import { useERC20Permit } from "@aave/react/viem";
// …
const { data: wallet } = useWalletClient();const [signERC20Permit] = useERC20Permit(wallet);Then, generate the ERC-20 Permit signature for the desired repay operation.
Finally, execute the repay operation providing the permit signature as part of the ERC-20 amount input.
Handle the result object as described in the standard repay operation flow.
While the useRepay handler supports both TransactionRequest and ApprovalRequired cases, this particular repay operation will always execute only the TransactionRequest path.