Advanced Features

Implement advanced Aave v4 features for sophisticated DeFi applications.


Update Risk Premium

As protocol configurations evolve through governance votes, a user position’s risk premium may improve, allowing them to lower the interest on their borrow positions.

Due to protocol technical constraints, users must update their risk premium when eligible. You can identify the user's positions that qualify for an update by checking the betterRiskPremium field (normally null).

Eligible User Position
const position: UserPosition = {  __typename: "UserPosition",  id: "abc…",  user: "0x456…",  riskPremium: {    normalized: "50", // 50%    // …  },  betterRiskPremium: {    normalized: "25", // 25% - lower is better    // …  },  spoke: {    id: "SGVsbG8h",    address: "0x123…",    chain: {      chainId: 1,      name: "Ethereum",      // …    },    // …  },  // …};

To update the risk premium with AaveKit React, follow these steps.

1

Configure Wallet Integration

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);

2

Define the Risk Premium Update Flow

Then, use the useUpdateUserRiskPremium hook to prepare the transaction request.

import { useUpdateUserRiskPremium } from "@aave/react";
const [updateRiskPremium, { loading, error }] = useUpdateUserRiskPremium(  (request) => sendTransaction(request));

3

Execute the Transaction

Then, execute the transaction.

Update Risk Premium
import { evmAddress, type UserPosition } from "@aave/react";
const execute = async (position: UserPosition) => {  const result = await updateRiskPremium({    sender: evmAddress(wallet.account.address), // User's address    spoke: position.spoke.id,  });};

4

Handle the Result

Finally, handle the result.

Example
const execute = async () => {  const result = await updateRiskPremium(/* … */);
  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("Risk premium updated successful with hash:", result.value);};

Liquidations

Liquidate unhealthy positions to earn liquidation bonuses and help maintain protocol stability.

Identify Target Position

First, identify a position with a health factor below 1.0 that is eligible for liquidation.

User Position
const position: UserPosition = {  __typename: "UserPosition",  id: "abc…",  user: "0x456…",  healthFactor: {    value: "0.85", // Below 1.0 - eligible for liquidation    // …  },  spoke: {    address: "0x123…",    chain: {      chainId: 1,      name: "Ethereum",    },    // …  },  // …};

It's not in the scope of this guide to explain how to find positions with a health factor below 1.0 and identify unhealthy positions. See Health Factor for more details.

Select Liquidation Targets

To liquidate a position, we need to choose two things: which debt to repay and which collateral to receive as liquidation bonus.

When choosing positions to liquidate, ensure liquidation bonuses exceed gas costs.

1

Choose the Debt Position

First, identify which debt position to target by looking at the user's borrow positions. Consider targeting debts with larger amounts.

Fetch borrow positions from User Borrows, then pick the specific position you want to liquidate:

Borrow Position
const debtPosition: UserBorrowItem = {  reserve: {    id: "SGVsbG8h",    onChainId: "42",    asset: {      underlying: { symbol: "WETH", name: "Wrapped Ether" },    },    // …  },  debt: {    amount: {      value: "0.5",    },    fiatAmount: {      value: "2000",      // …    },    // …  },  // …};

If the remaining debt in the target reserve after liquidation is less than $1,000 USD, you must liquidate the entire debt in that reserve.

2

Choose the Collateral Position

Next, identify which collateral position to target by examining the user's supply positions that are enabled as collateral. Only supplies with isCollateral: true can be targeted for liquidation.

Choose collateral in the token you prefer to receive as your liquidation bonus by fetching the supply positions from User Supplies:

Supply Position
const collateralPosition: UserSupplyItem = {  reserve: {    id: "V29ybGQ=",    onChainId: "43",    asset: {      underlying: { symbol: "USDC", name: "USD Coin" },    },    // …  },  isCollateral: true, // Can be liquidated  withdrawable: {    amount: {      value: "2000",      // …    },    // …  },  // …};

In Aave v4, liquidation bonuses follow a Dutch auction where lower health factors result in higher liquidation bonuses.

Liquidate the Position

After selecting the debt and collateral reserves, choose the repayment amount. You can send an exact value or let the protocol determine the needed amount by using max, restoring the position to a healthy state (HF ≥ 1.0).

To liquidate an unhealthy position with AaveKit React, follow these steps:

1

Configure Wallet Integration

First, instantiate the useSendTransaction hook for the wallet library of your choice. This wallet will pay the debt tokens and receive the seized collateral.

Viem
import { useWalletClient } from "wagmi";import { useSendTransaction } from "@aave/react/viem";
// …
const { data: wallet } = useWalletClient();const [sendTransaction] = useSendTransaction(wallet);

2

Implement the Liquidation Operation

Then, use the useLiquidatePosition hook to prepare the liquidation operation.

import { useLiquidatePosition } from "@aave/react";
const [liquidatePosition, { loading, error }] = useLiquidatePosition(  (plan, { cancel }) => {    switch (plan.__typename) {      case "TransactionRequest":        return sendTransaction(plan);      case "Erc20ApprovalRequired":        return sendTransaction(plan.transaction);    }  });

3

Execute the Liquidation

Then, execute the liquidation operation. Specify an exact debt amount to cover, or use amount: { max: true } to bring the position back to a healthy state.

import {  bigDecimal,  evmAddress,  type UserBorrowItem,  type UserPosition,  type UserSupplyItem,} from "@aave/react";
const execute = async (  position: UserPosition,  debt: UserBorrowItem,  collateral: UserSupplyItem) => {  const result = await liquidatePosition({    collateral: collateral.reserve.id,    debt: debt.reserve.id,    amount: {      exact: bigDecimal("1000"), // 1000 USDC    },    liquidator: evmAddress(wallet.account.address), // User's address    user: position.user,  });
  // …};

4

Handle the Result

Finally, handle the result.

Example
const execute = async (/* … */) => {  const result = await liquidatePosition(/* … */);
  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.required.value} required.`        );        break;
      case "UnexpectedError":        console.error(result.error.message);        break;    }    return;  }
  console.log("Liquidation successful with hash:", result.value);};