Withdraw Assets

Learn how to withdraw assets from your Aave v4 supply positions.


Withdraw supplied assets from your Aave v4 positions to access your funds and any earned interest.

Withdrawing assets while having an open borrow position may reduce the collateralization ratio and lower the position's health factor. In some cases, this may put the position at risk of being liquidated.

Withdrawing

Withdrawing can be broken down into the following steps:

  1. Identify the supply position to withdraw from

  2. Preview the impact of the withdraw operation

  3. Withdraw the assets

Identify the Supply Position

Given a list of user's supply positions, identify the supply position matching the token you want to withdraw and with a withdrawable amount that covers your needs.

The supplied position reserve should not be paused in order to withdraw from it.

For example, let’s say you have identified the following UserSupplyItem object.

Example UserSupplyItem
const supplyPosition: UserSupplyItem = {  reserve: {    id: "SGVsbG8h",    onChainId: "42",    chain: {      chainId: 1,      name: "Ethereum",    },    spoke: {      address: "0x123…",      // …    },    asset: {      underlying: {        address: "0xa0b86a33e6e2ad05ad6c9ac3b6e5e5f6e7b6c1b2", // USDC      },      // …    },    status: {      paused: false,    },    // … other reserve properties  },  isCollateral: true,  withdrawable: {    amount: {      value: "1000.000000", // 1,000 USDC supplied      // …    },    // …  },  // …};

Keep in mind that if the asset is used as collateral (isCollateral: true), withdrawing may:

  • Reduce your borrowing capacity and lower the position’s health factor, increasing the risk of liquidation.

  • If the collateral has a reserve.settings.collateralRisk greater than 0, lower the borrow APY on any open borrow positions in the same Spoke, effectively making those positions cheaper to maintain.

Preview Withdraw

Preview the impact of a withdraw operation before committing to it.

Use the usePreview hook (or the imperative usePreviewAction variant) to preview the impact of the withdraw operation on the user's position.

import { type WithdrawRequest, usePreview } from "@aave/react";
function WithdrawPreview({ request }: { request: WithdrawRequest }) {  const { data, error, loading } = usePreview({    action: {      withdraw: request,    },  });
  if (loading) return <div>Loading…</div>;  if (error) return <div>Error: {error.message}</div>;
  // data: PreviewUserPosition  return (    <div>      <h3>Health Factor:</h3>      <p>From: {data.healthFactor?.current ?? "N/A"}</p>      <p>To: {data.healthFactor?.after ?? "N/A"}</p>
      <h3>Risk Premium:</h3>      <p>From: {data.riskPremium.current.value}</p>      <p>To: {data.riskPremium.after.value}</p>
      <h3>Net APY:</h3>      <p>From: {data.netApy.current.value}</p>      <p>To: {data.netApy.after.value}</p>
      <h3>Net Collateral:</h3>      <p>From: {data.netCollateral.current.value}</p>      <p>To: {data.netCollateral.after.value}</p>    </div>  );}

Where the WithdrawRequest can be as follows:

const request: WithdrawRequest = {  sender: evmAddress("0x789…"), // User's address  reserve: supplyPosition.reserve.id,  amount: {    erc20: {      value: {        exact: bigDecimal(500), // 500 USDC      },    },  },};

You can also specify a different currency to return fiat amounts in.

import { Currency } from "@aave/react";
const { data, error, loading } = usePreview({  action: {    withdraw: request,  },  currency: Currency.Eur,});

The PreviewUserPosition shows the impact of the withdraw operation by comparing current and after states, with the table below outlining key fields and how to interpret them.

Current → AfterImpact
healthFactor?.current → healthFactor?.after: BigDecimalHigher is better
riskPremium.current → riskPremium.after: PercentNumberLower is better
netApy.current → netApy.after: PercentNumberHigher is better
netCollateral.current → netCollateral.after: FiatAmountHigher is better
netBalance.current → netBalance.after: FiatAmountUpdated balance

Step-by-Step

To withdraw assets from an Aave supply position 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 Withdraw Flow

Then, use the useWithdraw hook to prepare the withdraw operation.

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

3

Execute the Withdraw Operation

Then, execute the desired withdraw operation.

import { bigDecimal, evmAddress } from "@aave/react";
const execute = async () => {  const result = await withdraw({    sender: evmAddress(wallet.account.address), // User's address    reserve: supplyPosition.reserve.id,    amount: {      erc20: {        value: {          exact: bigDecimal(500), // Withdraw 500 USDC        },      },    },  });
  // …};

4

Handle the Result

Finally, handle the result.

Example
const execute = async () => {  const result = await withdraw(/* … */);
  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(`Invalid withdrawal amount: ${result.error.message}`);        break;
      case "UnexpectedError":        console.error(result.error.message);        break;    }    return;  }
  console.log("Withdraw 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 = {  withdraw: {    sender: evmAddress("0x123…"), // User's address    reserve: supplyPosition.reserve.id,    amount: {      erc20: {        value: {          exact: 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 withdraw 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 Supply Position
const supplyPosition: UserSupplyItem = {  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.

const execute = async () => {  const result = await withdraw({    sender: evmAddress(wallet.account.address), // User's address    reserve: supplyPosition.reserve.id,    amount: {      native: {        exact: bigDecimal(1), // Withdraw 1 ETH      },    },  });
  // …};