Market Operations

Execute the fundamental lending and borrowing operations on Aave markets. This section covers supply, borrow, repay, and withdraw functionality.

Permit Overview

Some Aave operations support permit functionality using EIP-2612 signatures to authorize ERC-20 token transfers within the same transaction.

Benefits of Permit

  • 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

Permit is available for ERC-20 tokens that implement EIP-2612.

Supply Assets

By supplying assets to an Aave market, users earn interest on their deposits according to the reserve's supply APY rate.

When supplying assets to an Aave market, you can use the following methods:

MethodDescriptionTypical Scenario
Direct SupplySupply ERC-20 or native tokens directly from the sender’s wallet. aTokens are sent to the sender’s address.User deposits assets into their own wallet.
On Behalf of AnotherSupply from the sender’s wallet, but send aTokens to another address.User deposits assets from one wallet and borrow position is owned by another wallet.
With PermitUse a permit signature to skip ERC-20 approval and supply in a single transaction.User signs a permit and sends a single transaction. No ERC-20 allowance left behind.
With Permit
On Behalf of Another
Same as permit supply, but aTokens are sent to another address.No ERC-20 allowance needed and borrow position is owned by another wallet.

To supply assets to an Aave market, follow these steps.

1

Identify the Reserve

First, determine which reserve you want to supply assets to.

Let's say we choose the WETH supply reserve within one of the Ethereum markets.

Reserve
const reserve: Reserve = {  __typename: "Reserve",  market: {    __typename: "Market",    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",    chainId: 1,    // …  },  underlyingToken: {    __typename: "Currency",    symbol: "WETH",    name: "Wrapped Ether",    address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",    // …  },  acceptsNative: {    __typename: "NativeCurrency",    symbol: "ETH",    name: "Ethereum",    // …  },  isFrozen: false,  isPaused: false,  permitSupported: true,  userState: {    __typename: "ReserveUserState",    suppliable: {      __typename: "TokenAmount",      amount: {        __typename: "DecimalValue",        value: "1245.67",        raw: "1245670000000000000000",        decimals: 18,        // …      },      // …    },  },  // …};

To supply to the reserve, you need to verify these conditions:

  • Reserve.isFrozen is false - the reserve is not frozen

  • Reserve.isPaused is false - the reserve is not paused

  • Reserve.userState.suppliable.amount.value is greater than 0 - the amount the user can supply to the reserve given their unique circumstances

Make sure you include a user address when fetching market and reserve data—otherwise Reserve.userState will be empty.

The Reserve.permitSupported flag indicates whether the underlying token supports EIP-2612 permits.

Additionally, if Reserve.acceptsNative is not null, users can choose to supply the asset as the chain's native token and it will be automatically wrapped before being sent to the reserve. This is typical for reserves of the wrapped version of the chain's native token (e.g., WETH on Ethereum).

2

Prepare the Execution Plan

Next, if all of these conditions are met, we can proceed with creating the execution plan for the supply operation.

Use the useSupply hook to prepare supply transactions, optionally on behalf of another address.

import { useWalletClient } from "wagmi";import { useSupply, bigDecimal, evmAddress } from "@aave/react";
// …
const { data: walletClient } = useWalletClient();
const [supply, supplying] = useSupply();
const execute = async () => {  const result = await supply({    market: reserve.market.address,    amount: {      erc20: {        currency: reserve.underlyingToken.address,        value: bigDecimal(42), // 42 WETH      },    },    sender: evmAddress(walletClient!.account.address),    chainId: reserve.market.chain.chainId,  });
  // …};

If Reserve.permitSupported is true and you supply ERC-20 tokens, you can use the useSupply and useERC20Permit hooks to sign permits and prepare supply transactions. Use the useERC20Permit implementation for the wallet library of choice.

import { useSupply, bigDecimal, evmAddress } from "@aave/react";import { useERC20Permit } from "@aave/react/viem";import { useWalletClient } from "wagmi";
// …
const { data: walletClient } = useWalletClient();
const [signPermit, signing] = useERC20Permit(walletClient);const [supply, supplying] = useSupply();
const execute = async () => {  const amount = bigDecimal(42); // 42 WETH
  const permit = await signPermit({    amount,    chainId: reserve.market.chain.chainId,    currency: reserve.underlyingToken.address,    owner: evmAddress(walletClient!.account.address),    spender: reserve.market.address,  }).andThen((signature) =>    supply({      market: reserve.market.address,      amount: {        erc20: {          currency: reserve.underlyingToken.address,          value: amount, // 42 WETH          permitSig: signature,        },      },      sender: evmAddress(walletClient!.account.address),      chainId: reserve.market.chain.chainId,    })  );
  // …};

3

Process the Execution Plan

Finally, you need to handle the execution plan, and the process is the same whether or not you used a permit in the previous step.

If you provided a permit signature, the execution plan will run as a single transaction.

Use the useSendTransaction hook for the wallet library of your choice to send the transactions in the execution plan.

Viem
import { useWalletClient } from "wagmi";import { errAsync, useSupply } from "@aave/react";import { useSendTransaction } from "@aave/react/viem";
// …
const { data: walletClient } = useWalletClient();
const [supply, supplying] = useSupply();const [sendTransaction, sending] = useSendTransaction(walletClient);
// …
// Optional: combine loading statesconst loading = supplying.loading || sending.loading;const error = supplying.error || sending.error;
// …
const execute = async () => {  const result = await supply({    // …  }).andThen((plan) => {    switch (plan.__typename) {      case "TransactionRequest":        // Single transaction execution        return sendTransaction(plan);
      case "ApprovalRequired":        // Approval + transaction sequence        return sendTransaction(plan.approval).andThen(() =>          sendTransaction(plan.originalTransaction)        );
      case "InsufficientBalanceError":        return errAsync(          new Error(`Insufficient balance: ${plan.required.value} required.`)        );    }  });
  if (result.isErr()) {    console.error("Supply failed:", result.error);  } else {    console.log("Supply successful with hash:", result.value);  }};

Collateral Management

To manage which supplied assets are used as collateral for borrowing, follow these steps.

1

Identify the User Position

First, determine which user supply position you want to enable or disable as collateral.

Let's say we identified this MarketUserReserveSupplyPosition object.

MarketUserReserveSupplyPosition
const position: MarketUserReserveSupplyPosition = {  __typename: "MarketUserReserveSupplyPosition",  market: {    __typename: "Market",    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",    chainId: 1,    // …  },  currency: {    __typename: "Currency",    symbol: "WETH",    name: "Wrapped Ether",    address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",    // …  },  balance: {    __typename: "TokenAmount",    amount: {      __typename: "DecimalValue",      value: "5.0",      raw: "5000000000000000000",      decimals: 18,      // …    },    // …  },  isCollateral: false, // Currently not used as collateral  canBeCollateral: true, // Can be enabled as collateral  // …};

To enable a position as collateral, you need to verify these conditions:

  • position.canBeCollateral is true - the asset can be used as collateral

  • position.isCollateral is false - the asset is not currently used as collateral

To disable a position as collateral, you only need to check if position.isCollateral is true.

A reserve may be disabled from being used as collateral, pending an Aave DAO vote. This prevents new collateral usage of the asset but does not impact existing user positions already using it as collateral.

2

Prepare the Transaction Request

Next, we can proceed with creating the transaction request for the collateral toggle operation.

Use the useCollateralToggle hook to create the transaction request for enabling or disabling collateral.

Toggle Collateral
import { useWalletClient } from "wagmi";import { useCollateralToggle, evmAddress } from "@aave/react";
// …
const { data: walletClient } = useWalletClient();
const [toggleCollateral, toggling] = useCollateralToggle();
const execute = async () => {  const result = await toggleCollateral({    market: position.market.address,    underlyingToken: position.currency.address,    user: evmAddress(walletClient!.account.address),    chainId: position.market.chainId,  });
  // …};

3

Send the Transaction

Finally, send the transaction.

Use the useSendTransaction hook for the wallet library of your choice to send the transaction.

Viem
import { useWalletClient } from "wagmi";import { useCollateralToggle } from "@aave/react";import { useSendTransaction } from "@aave/react/viem";
// …
const { data: walletClient } = useWalletClient();
const [toggleCollateral, toggling] = useCollateralToggle();const [sendTransaction, sending] = useSendTransaction(walletClient);
// …
// Optional: combine loading statesconst loading = toggling.loading || sending.loading;const error = toggling.error || sending.error;
// …
const execute = async () => {  const result = await toggleCollateral({    // …  }).andThen(sendTransaction);
  if (result.isErr()) {    console.error("Collateral toggle failed:", result.error);  } else {    console.log("Collateral toggle successful with hash:", result.value);  }};

Borrow Assets

Users can borrow assets from Aave markets at the reserve’s borrow APY using supply positions as collateral.

When borrowing assets from an Aave market, you can use the following methods:

MethodDescriptionTypical Scenario
Direct BorrowBorrow assets from a reserve using supplied collateralUser borrows from a reserve against their own supplied collateral.
Credit DelegationBorrow assets from a reserve using delegated borrow creditsUser borrows from a reserve using credits from collateral supplied by a credit delegator.

To borrow assets from an Aave market, follow these steps.

1

Identify the Reserve

First, determine which reserve you want to borrow assets from.

Let's say we choose the WETH borrow reserve within one of the Ethereum markets.

Reserve
const reserve: Reserve = {  __typename: "Reserve",  market: {    __typename: "Market",    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",    chainId: 1,    // …  },  underlyingToken: {    __typename: "Currency",    symbol: "WETH",    name: "Wrapped Ether",    address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",    // …  },  acceptsNative: {    __typename: "NativeCurrency",    symbol: "ETH",    name: "Ethereum",    // …  },  isFrozen: false,  isPaused: false,  userState: {    __typename: "ReserveUserState",    borrowable: {      __typename: "TokenAmount",      amount: {        __typename: "DecimalValue",        value: "15.75",        raw: "15750000000000000000",        decimals: 18,        // …      },      // …    },  },  // …};

To borrow from the reserve, you need to verify these conditions:

  • Reserve.isFrozen is false - the reserve is not frozen

  • Reserve.isPaused is false - the reserve is not paused

  • Reserve.userState.borrowable.amount.value is greater than 0 - the amount the user can borrow from the reserve given their unique circumstances

Make sure you include a user address when fetching market and reserve data—otherwise Reserve.userState will be empty.

Additionally, if Reserve.acceptsNative is not null, users can choose to receive any borrowed assets as the chain's native token and it will be automatically unwrapped before being sent to the user's wallet. This is typical for reserves of the wrapped version of the chain's native token (e.g., WETH on Ethereum).

2

Prepare the Execution Plan

Next, if all of these conditions are met, we can proceed with creating the execution plan for the borrow operation.

Use the useBorrow hook to create the execution plan for a direct borrow operation.

import { useWalletClient } from "wagmi";import { useBorrow, bigDecimal, evmAddress } from "@aave/react";
// …
const { data: walletClient } = useWalletClient();
const [borrow, borrowing] = useBorrow();
const execute = async () => {  const result = await borrow({    market: reserve.market.address,    amount: {      erc20: {        currency: reserve.underlyingToken.address,        value: bigDecimal(2), // 2 WETH      },    },    sender: evmAddress(walletClient!.account.address),    chainId: reserve.market.chain.chainId,  });
  // …};

If you intend to leverage credit delegation, you can first check the credit delegation allowance.

Check Credit Delegation Allowance
import { useCreditDelegateeAllowance, evmAddress } from "@aave/react";
// …
const { data: allowance, loading } = useCreditDelegateeAllowance({  market: reserve.market.address,  underlyingToken: reserve.underlyingToken.address,  user: evmAddress("0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"), // Delegator  delegatee: evmAddress(walletClient!.account.address), // Your address  chainId: reserve.market.chainId,});
if (allowance && BigInt(allowance.amount.raw) > 0n) {  console.log("Available delegation allowance:", allowance.amount.value);} else {  console.log("No credit delegation allowance available");}

And then, you can proceed with preparing the execution plan for the borrow operation.

Borrow with Credit Delegation
import { useWalletClient } from "wagmi";import { useBorrow, bigDecimal, evmAddress } from "@aave/react";
// …
const { data: walletClient } = useWalletClient();
const [borrow, borrowing] = useBorrow();
const execute = async () => {  const result = await borrow({    market: reserve.market.address,    amount: {      erc20: {        currency: reserve.underlyingToken.address,        value: bigDecimal(2), // 2 WETH      },    },    sender: evmAddress(walletClient!.account.address),    chainId: reserve.market.chain.chainId,    onBehalfOf: evmAddress("0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"), // Delegator  });
  // …};

3

Process the Execution Plan

Finally, handle the execution plan.

Use the useSendTransaction hook for the wallet library of your choice to send the transactions in the execution plan.

Viem
import { useWalletClient } from "wagmi";import { errAsync, useBorrow } from "@aave/react";import { useSendTransaction } from "@aave/react/viem";
// …
const { data: walletClient } = useWalletClient();
const [borrow, borrowing] = useBorrow();const [sendTransaction, sending] = useSendTransaction(walletClient);
// …
// Optional: combine loading statesconst loading = borrowing.loading || sending.loading;const error = borrowing.error || sending.error;
// …
const execute = async () => {  const result = await borrow({    // …  }).andThen((plan) => {    switch (plan.__typename) {      case "TransactionRequest":        // Single transaction execution        return sendTransaction(plan);
      case "ApprovalRequired":        // Approval + transaction sequence        return sendTransaction(plan.approval).andThen(() =>          sendTransaction(plan.originalTransaction)        );
      case "InsufficientBalanceError":        return errAsync(          new Error(`Insufficient balance: ${plan.required.value} required.`)        );    }  });
  if (result.isErr()) {    console.error("Borrow failed:", result.error);  } else {    console.log("Borrow successful with hash:", result.value);  }};

Credit Delegation

Credit delegation allows a user to approve another user (delegatee) to borrow assets against their own supply position. The supply position must be enabled as collateral.

To delegate credit to another address, follow these steps.

1

Identify the User Position

First, determine which user supply position you want to delegate credit from.

Let's say we identified this MarketUserReserveSupplyPosition object.

MarketUserReserveSupplyPosition
const position: MarketUserReserveSupplyPosition = {  __typename: "MarketUserReserveSupplyPosition",  market: {    __typename: "Market",    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",    chainId: 1,    // …  },  currency: {    __typename: "Currency",    symbol: "WETH",    name: "Wrapped Ether",    address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",    // …  },  balance: {    __typename: "TokenAmount",    amount: {      __typename: "DecimalValue",      value: "5.0",      raw: "5000000000000000000",      decimals: 18,      // …    },    // …  },  isCollateral: true,  canBeCollateral: true,  // …};

Ensure MarketUserReserveSupplyPosition.isCollateral is true, if not enable it as collateral first.

2

Prepare the Transaction Request

Next, we can proceed with creating the transaction request for the credit delegation operation.

Use the useApproveBorrowCreditDelegation hook to create the transaction request for approving credit delegation.

Approve Credit Delegation
import { useWalletClient } from "wagmi";import { useApproveBorrowCreditDelegation, evmAddress } from "@aave/react";
// …
const { data: walletClient } = useWalletClient();
const [approveDelegation, approving] = useApproveBorrowCreditDelegation();
const execute = async () => {  const result = await approveDelegation({    market: position.market.address,    underlyingToken: position.currency.address,    amount: "1000",    user: evmAddress(walletClient!.account.address),    delegatee: evmAddress("0x5678..."),    chainId: position.market.chainId,  });
  // …};

3

Send the Transaction

Finally, send the transaction.

Use the useSendTransaction hook for the wallet library of your choice to send the transaction.

Viem
import { useWalletClient } from "wagmi";import { useApproveBorrowCreditDelegation } from "@aave/react";import { useSendTransaction } from "@aave/react/viem";
// …
const { data: walletClient } = useWalletClient();
const [approveDelegation, approving] = useApproveBorrowCreditDelegation();const [sendTransaction, sending] = useSendTransaction(walletClient);
// …
// Optional: combine loading statesconst loading = approving.loading || sending.loading;const error = approving.error || sending.error;
// …
const execute = async () => {  const result = await approveDelegation({    // …  }).andThen(sendTransaction);
  if (result.isErr()) {    console.error("Credit delegation failed:", result.error);  } else {    console.log("Credit delegation successful with hash:", result.value);  }};

That's it—the delegatee can now borrow against the user's supply position.

Repay Loans

By repaying borrowed assets to an Aave market, users reduce or clear their debt position.

When repaying borrowed assets to an Aave market, you can use the following methods:

MethodDescriptionTypical Scenario
Direct RepayRepay ERC-20 or native tokens directly from the sender's wallet.User repays borrowed assets from their own wallet balance.
On Behalf of AnotherRepay debt for another address.User borrowed with one wallet and wants to repay from a different wallet.
With PermitUse a permit signature to skip ERC-20 approval and repay in a single transaction.User signs a permit and sends a single transaction. No ERC-20 allowance left behind.
With Permit
On Behalf of Another
Same as permit repay, but the debt position is owned by another wallet.No ERC-20 allowance needed when repaying debt for another wallet.

To repay borrowed assets from an Aave market, follow these steps.

1

Identify the User Position

First, determine which user borrow position you want to repay debt for.

Let's say we identified this MarketUserReserveBorrowPosition object.

MarketUserReserveBorrowPosition
const position: MarketUserReserveBorrowPosition = {  __typename: "MarketUserReserveBorrowPosition",  market: {    __typename: "Market",    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",    chainId: 1,    // …  },  currency: {    __typename: "Currency",    symbol: "WETH",    name: "Wrapped Ether",    address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",    // …  },  debt: {    __typename: "TokenAmount",    amount: {      __typename: "DecimalValue",      value: "1.5",      raw: "1500000000000000000",      decimals: 18,      // …    },    // …  },  // …};

That is tied to the following Reserve object.

Reserve
const reserve: Reserve = {  __typename: "Reserve",  market: {    __typename: "Market",    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",    chainId: 1,    // …  },  underlyingToken: {    __typename: "Currency",    symbol: "WETH",    name: "Wrapped Ether",    address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",    // …  },  permitSupported: true,  acceptsNative: {    __typename: "NativeCurrency",    // …  },};

The Reserve.permitSupported flag indicates whether the underlying token supports EIP-2612 permits.

Additionally, if Reserve.acceptsNative is not null, users can choose to repay the borrow position as the chain's native token and it will be automatically wrapped before being sent to the reserve. This is typical for reserves of the wrapped version of the chain's native token (e.g., WETH on Ethereum).

2

Prepare the Execution Plan

Next, we can proceed with creating the execution plan for the repay operation.

Use the useRepay hook to create the execution plan for repaying debt from a market reserve, optionally on behalf of another address.

import { useWalletClient } from "wagmi";import { useRepay, bigDecimal, evmAddress } from "@aave/react";
// …
const { data: walletClient } = useWalletClient();
const [repay, repaying] = useRepay();
const execute = async () => {  const result = await repay({    market: position.market.address,    amount: {      erc20: {        currency: position.currency.address,        value: {          exact: bigDecimal(1), // 1 WETH        },      },    },    sender: evmAddress(walletClient!.account.address),    chainId: position.market.chainId,  });
  // …};

If Reserve.permitSupported is true and your borrow position is an ERC-20 token, you can use the useRepay and useERC20Permit hooks to sign permits and prepare repay transactions. Use the useERC20Permit implementation for the wallet library of choice.

import { useRepay, bigDecimal, evmAddress } from "@aave/react";import { useERC20Permit } from "@aave/react/viem";import { useWalletClient } from "wagmi";
// …
const { data: walletClient } = useWalletClient();
const [signPermit, signing] = useERC20Permit(walletClient);const [repay, repaying] = useRepay();
const execute = async () => {  const amount = bigDecimal(42); // 42 WETH
  const permit = await signPermit({    amount,    chainId: reserve.market.chain.chainId,    currency: reserve.underlyingToken.address,    owner: evmAddress(walletClient!.account.address),    spender: reserve.market.address,  }).andThen((signature) =>    repay({      market: position.market.address,      amount: {        erc20: {          currency: position.currency.address,          value: {            exact: amount, // 42 WETH          },          permitSig: signature,        },      },      sender: evmAddress(walletClient!.account.address),      chainId: position.market.chainId,    })  );
  // …};

3

Process the Execution Plan

Finally, handle the execution plan.

Use the useSendTransaction hook for the wallet library of your choice to send the transactions in the execution plan.

Viem
import { useWalletClient } from "wagmi";import { errAsync, useRepay } from "@aave/react";import { useSendTransaction } from "@aave/react/viem";
// …
const { data: walletClient } = useWalletClient();
const [repay, repaying] = useRepay();const [sendTransaction, sending] = useSendTransaction(walletClient);
// …
// Optional: combine loading statesconst loading = repaying.loading || sending.loading;const error = repaying.error || sending.error;
// …
const execute = async () => {  const result = await repay({    // …  }).andThen((plan) => {    switch (plan.__typename) {      case "TransactionRequest":        // Single transaction execution        return sendTransaction(plan);
      case "ApprovalRequired":        // Approval + transaction sequence        return sendTransaction(plan.approval).andThen(() =>          sendTransaction(plan.originalTransaction)        );
      case "InsufficientBalanceError":        return errAsync(          new Error(`Insufficient balance: ${plan.required.value} required.`)        );    }  });
  if (result.isErr()) {    console.error("Repay failed:", result.error);  } else {    console.log("Repay successful with hash:", result.value);  }};

Withdraw Assets

Users can withdraw assets from Aave markets using their previously supplied reserves.

When withdrawing assets from an Aave market, you can use the following methods:

MethodDescriptionTypical Scenario
Direct WithdrawWithdraw ERC-20 or native tokens directly to supplier wallet.User withdraws supplied assets from their own wallet balance.
Another RecipientWithdraw supplied assets to another address.User supplied with one wallet and wants to withdraw to a different wallet.

To withdraw supplied assets from an Aave market, follow these steps.

1

Identify the User Position

First, determine which user supply position you want to withdraw assets from.

Let's say we identified this MarketUserReserveSupplyPosition object.

MarketUserReserveSupplyPosition
const position: MarketUserReserveSupplyPosition = {  __typename: "MarketUserReserveSupplyPosition",  market: {    __typename: "Market",    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",    chainId: 1,    // …  },  currency: {    __typename: "Currency",    symbol: "WETH",    name: "Wrapped Ether",    address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",    // …  },  balance: {    __typename: "TokenAmount",    amount: {      __typename: "DecimalValue",      value: "5.0",      raw: "5000000000000000000",      decimals: 18,      // …    },    // …  },  // …};

That is tied to the following Reserve object.

Reserve
const reserve: Reserve = {  __typename: "Reserve",  market: {    __typename: "Market",    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",    chainId: 1,    // …  },  underlyingToken: {    __typename: "Currency",    symbol: "WETH",    name: "Wrapped Ether",    address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",    // …  },  acceptsNative: {    __typename: "NativeCurrency",    // …  },};

2

Prepare the Execution Plan

Next, we can proceed with creating the execution plan for the withdraw operation.

Use the useWithdraw hook to create the execution plan for withdrawing assets from a market reserve.

import { useWalletClient } from "wagmi";import { useWithdraw, bigDecimal, evmAddress } from "@aave/react";
// …
const { data: walletClient } = useWalletClient();
const [withdraw, withdrawing] = useWithdraw();
const execute = async () => {  const result = await withdraw({    market: position.market.address,    amount: {      erc20: {        currency: position.currency.address,        value: {          exact: bigDecimal(2), // 2 WETH        },      },    },    sender: evmAddress(walletClient!.account.address),    chainId: position.market.chainId,  });
  // …};

If Reserve.acceptsNative is not null, you can choose to withdraw the assets using the chain's native token.

import { useWalletClient } from "wagmi";import { useWithdraw, bigDecimal, evmAddress } from "@aave/react";
// …
const { data: walletClient } = useWalletClient();
const [withdraw, withdrawing] = useWithdraw();
const execute = async () => {  const result = await withdraw({    market: position.market.address,    amount: {      native: {        value: { exact: bigDecimal(2) }, // 2 ETH      },    },    sender: evmAddress(walletClient!.account.address),    chainId: position.market.chainId,  });
  // …};

3

Process the Execution Plan

Finally, handle the execution plan.

Use the useSendTransaction hook for the wallet library of your choice to send the transactions in the execution plan.

Viem
import { useWalletClient } from "wagmi";import { errAsync, useWithdraw } from "@aave/react";import { useSendTransaction } from "@aave/react/viem";
// …
const { data: walletClient } = useWalletClient();
const [withdraw, withdrawing] = useWithdraw();const [sendTransaction, sending] = useSendTransaction(walletClient);
// …
// Optional: combine loading statesconst loading = withdrawing.loading || sending.loading;const error = withdrawing.error || sending.error;
// …
const execute = async () => {  const result = await withdraw({    // …  }).andThen((plan) => {    switch (plan.__typename) {      case "TransactionRequest":        // Single transaction execution        return sendTransaction(plan);
      case "ApprovalRequired":        // Approval + transaction sequence        return sendTransaction(plan.approval).andThen(() =>          sendTransaction(plan.originalTransaction)        );
      case "InsufficientBalanceError":        return errAsync(          new Error(`Insufficient balance: ${plan.required.value} required.`)        );    }  });
  if (result.isErr()) {    console.error("Withdraw failed:", result.error);  } else {    console.log("Withdraw successful with hash:", result.value);  }};

Advanced Operations

Health Factor Preview

The health factor is calculated only when a user has at least one active borrow position. If the user has no positions or only supply positions, the health factor will be null.

To preview how a user's health factor will change before executing a market operation (supply, borrow, repay, withdraw).

Use the useHealthFactorPreview hook to preview the health factor after the operation.

import { useWalletClient } from "wagmi";import { useHealthFactorPreview, bigDecimal, evmAddress } from "@aave/react";
// …
const { data: walletClient } = useWalletClient();const [preview, { loading, error }] = useHealthFactorPreview();
const result = await preview({  action: {    borrow: {      market: reserve.market.address,      amount: {        erc20: {          currency: reserve.underlyingToken.address,          value: bigDecimal(42), // 42 WETH        },      },      borrower: evmAddress(walletClient!.account.address),      chainId: reserve.market.chain.chainId,    },  },});
if (result.isErr()) {  console.error(result.error);} else {  console.log(result.value.after); // 1.5 or null}