Skip to Content
docs

Borrow Assets on Aave V3

Borrow assets from Aave V3 markets against your collateral, or delegate your borrowing power.

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 Borrow Reserve

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

Given this Reserve object for WETH on an Ethereum market:

Reserve
const reserve: Reserve = {
  __typename: "Reserve",
  market: {
    __typename: "MarketInfo",
    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
    chain: { 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

Include a user address when fetching market and reserve data, or 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 Borrow 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 in React, the borrow action in TypeScript, or the borrow query in GraphQL 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.chain.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 Borrow Execution Plan

Finally, handle the execution plan.

  • React: Use the useSendTransaction hook for the wallet library of your choice to send the transactions in the execution plan.
  • TypeScript: Use sendWith for your chosen wallet library to send the transactions in the execution plan, and await indexing with client.waitForTransaction.
  • GraphQL: If the response is a TransactionRequest, you can send it directly using the wallet associated with the from address.
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 states
const 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);
  }
};

In GraphQL, if the response is an ApprovalRequired, you must first send the approval transaction. Once it succeeds, you can then send the originalTransaction. This happens only for native borrows, which need credit delegation to the WrappedTokenGateway.

ApprovalRequired
{
  "data": {
    "borrow": {
      "__typename": "ApprovalRequired",
      "reason": "Insufficient credit delegation to the WrappedTokenGateway",
      "requiredAmount": {
        "value": "2.0",
        "decimals": 18
      },
      "currentAllowance": {
        "value": "0.0",
        "decimals": 18
      },
      "approval": {
        "to": "0xeA51d7853EEFb32b6ee06b1C12E6dcCA88Be0fFE",
        "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
        "data": "0xc04a8a10000000000000000000000000d01…",
        "value": "0",
        "chainId": 1,
        "operation": null
      },
      "originalTransaction": {
        "to": "0xd01607c3C5eCABa394D8be377a08590149325722",
        "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
        "data": "0xe74f7b85000000000000000000000000878…",
        "value": "0",
        "chainId": 1,
        "operation": "BORROW"
      }
    }
  }
}

In GraphQL, if the response is an InsufficientBalanceError, inform the user that they don’t have enough balance to borrow the requested amount.

InsufficientBalanceError
{
  "data": {
    "borrow": {
      "__typename": "InsufficientBalanceError",
      "required": {
        "value": "2.0",
        "decimals": 18
      },
      "available": {
        "value": "1.0",
        "decimals": 18
      }
    }
  }
}

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 Delegated Position

First, choose the asset the delegatee may borrow and make sure your collateral is enabled.

Given this MarketUserReserveSupplyPosition object:

MarketUserReserveSupplyPosition
const position: MarketUserReserveSupplyPosition = {
  __typename: "MarketUserReserveSupplyPosition",
  market: {
    __typename: "MarketInfo",
    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
    chain: { 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 Delegation Transaction Request

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

Use the useApproveBorrowCreditDelegation hook in React, the approveBorrowCreditDelegation action in TypeScript, or the approveBorrowCreditDelegation query in GraphQL to create the transaction request for approving credit delegation. underlyingToken is the asset the delegatee will borrow; the example uses WETH.

Approve Credit Delegation
import { useWalletClient } from "wagmi";
import {
  useApproveBorrowCreditDelegation,
  evmAddress,
  bigDecimal,
} 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: bigDecimal(1000),
    user: evmAddress(walletClient!.account.address),
    delegatee: evmAddress("0x8ba1f109551bd432803012645ac136ddd64dba72"),
    chainId: position.market.chain.chainId,
  });

  // …
};

3. Send the Delegation Transaction

Finally, send the transaction.

  • React: Use the useSendTransaction hook for the wallet library of your choice to send the transaction.
  • TypeScript: Use sendWith for your chosen wallet library to initiate the transaction, and await indexing with client.waitForTransaction.
  • GraphQL: The response is a TransactionRequest that can be sent directly using the wallet associated with the from address.
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 states
const 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);
  }
};

The delegatee can now borrow against the user’s supply position.