# Repay Loans on Aave V3

Repay borrowed assets to Aave V3 markets.

## 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:

| Method                                    | Description                                                                       | Typical Scenario                                                                     |
| ----------------------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| **Direct Repay**                          | Repay ERC-20 or native tokens directly from the sender’s wallet.                  | User repays borrowed assets from their own wallet balance.                           |
| **On Behalf of Another**                  | Repay debt for another address.                                                   | User borrowed with one wallet and wants to repay from a different wallet.            |
| **With Permit**                           | Use 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 Borrow Position

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

Given this `MarketUserReserveBorrowPosition` object:

```ts title="MarketUserReserveBorrowPosition"
const position: MarketUserReserveBorrowPosition = {
  __typename: "MarketUserReserveBorrowPosition",
  market: {
    __typename: "MarketInfo",
    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
    chain: { 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.

```ts title="Reserve"
const reserve: Reserve = {
  __typename: "Reserve",
  market: {
    __typename: "MarketInfo",
    address: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
    chain: { 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 Repay Execution Plan

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

Use the `useRepay` hook in React, the `repay` action in TypeScript, or the `repay` query in GraphQL to create the execution plan for repaying debt from a market reserve, optionally on behalf of another address.

<tabgroup>
<tab label="React">

```tsx title="Repay ERC-20"
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.chain.chainId,
  });

  // …
};
```

```tsx title="Repay Native"
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: {
      native: bigDecimal(1), // 1 ETH
    },
    sender: evmAddress(walletClient!.account.address),
    chainId: position.market.chain.chainId,
  });

  // …
};
```

```tsx title="Repay Max ERC-20"
import { useWalletClient } from "wagmi";
import { useRepay, 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: {
          max: true,
        },
      },
    },
    sender: evmAddress(walletClient!.account.address),
    chainId: position.market.chain.chainId,
  });

  // …
};
```

```tsx title="Repay On Behalf of Another"
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.chain.chainId,
    onBehalfOf: evmAddress("0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"),
  });

  // …
};
```

</tab>
<tab label="TypeScript">

```ts title="Repay ERC-20"
import { repay } from "@aave/client/actions";
import { bigDecimal, evmAddress } from "@aave/client";

import { client } from "./client";
import { wallet } from "./wallet";

const result = await repay(client, {
  market: position.market.address,
  amount: {
    erc20: {
      currency: position.currency.address,
      value: {
        exact: bigDecimal(1), // 1 WETH
      },
    },
  },
  sender: evmAddress(wallet.account.address),
  chainId: position.market.chain.chainId,
});

// …
```

```ts title="Repay Native"
import { repay } from "@aave/client/actions";
import { bigDecimal, evmAddress } from "@aave/client";

import { client } from "./client";
import { wallet } from "./wallet";

const result = await repay(client, {
  market: position.market.address,
  amount: {
    native: bigDecimal(1), // 1 ETH
  },
  sender: evmAddress(wallet.account.address),
  chainId: position.market.chain.chainId,
});

// …
```

```ts title="Repay Max ERC-20"
import { repay } from "@aave/client/actions";
import { evmAddress } from "@aave/client";

import { client } from "./client";
import { wallet } from "./wallet";

const result = await repay(client, {
  market: position.market.address,
  amount: {
    erc20: {
      currency: position.currency.address,
      value: {
        max: true,
      },
    },
  },
  sender: evmAddress(wallet.account.address),
  chainId: position.market.chain.chainId,
});

// …
```

```ts title="Repay On Behalf of Another"
import { repay } from "@aave/client/actions";
import { bigDecimal, evmAddress } from "@aave/client";

import { client } from "./client";
import { wallet } from "./wallet";

const result = await repay(client, {
  market: position.market.address,
  amount: {
    erc20: {
      currency: position.currency.address,
      value: {
        exact: bigDecimal(1), // 1 WETH
      },
    },
  },
  sender: evmAddress(wallet.account.address),
  chainId: position.market.chain.chainId,
  onBehalfOf: evmAddress("0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"),
});

// …
```

```ts title="client.ts"
import { AaveClient } from "@aave/client";

export const client = AaveClient.create();
```

```ts title="wallet.ts"
import { createWalletClient, http, type Hex } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { mainnet } from "viem/chains";

export const wallet = createWalletClient({
  account: privateKeyToAccount(process.env.PRIVATE_KEY as Hex),
  chain: mainnet,
  transport: http(),
});
```

</tab>
<tab label="GraphQL">

```graphql title="Query"
query {
  repay(
    request: {
      market: "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2"
      amount: {
        erc20: {
          currency: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"
          value: {
            exact: "1"
            # OR
            # max: true
          }
        }
        # OR if the reserve accepts native currency
        # native: "1"
      }
      sender: "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"
      chainId: 1
      # optional
      # onBehalfOf: "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"
    }
  ) {
    __typename
    ... on TransactionRequest {
      to
      from
      data
      value
      chainId
      operation
    }
    ... on ApprovalRequired {
      reason
      requiredAmount {
        value
        decimals
      }
      currentAllowance {
        value
        decimals
      }
      approval {
        to
        from
        data
        value
        chainId
        operation
      }
      originalTransaction {
        to
        from
        data
        value
        chainId
        operation
      }
    }
    ... on InsufficientBalanceError {
      required {
        value
        decimals
      }
      available {
        value
        decimals
      }
    }
  }
}
```

</tab>
</tabgroup>
If `Reserve.permitSupported` is `true` and your borrow position is an ERC-20 token, you can sign [permits](./supply#permit-overview) and prepare repay transactions.

- **React**: Use the `useRepay` and `useERC20Permit` hooks, with the `useERC20Permit` implementation for the [wallet library of choice](../getting-started/react#sign-erc-20-permits).
- **TypeScript**: Use the `repay` and `permitTypedData` actions together with the `signERC20PermitWith` helper, with the `signERC20PermitWith` implementation for the [wallet library of choice](../getting-started/typescript#sign-erc-20-permits).

<tabgroup>
<tab label="React">

```tsx title="Repay ERC-20 with Permit"
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(1); // 1 WETH

  const permit = await signPermit({
    amount,
    chainId: position.market.chain.chainId,
    currency: position.currency.address,
    owner: evmAddress(walletClient!.account.address),
    spender: position.market.address,
  }).andThen((signature) =>
    repay({
      market: position.market.address,
      amount: {
        erc20: {
          currency: position.currency.address,
          value: {
            exact: amount, // 1 WETH
          },
          permitSig: signature,
        },
      },
      sender: evmAddress(walletClient!.account.address),
      chainId: position.market.chain.chainId,
    })
  );

  // …
};
```

```tsx title="Repay ERC-20 with Permit On Behalf of Another"
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(1); // 1 WETH

  const permit = await signPermit({
    amount,
    chainId: position.market.chain.chainId,
    currency: position.currency.address,
    owner: evmAddress(walletClient!.account.address),
    spender: position.market.address,
  }).andThen((signature) =>
    repay({
      market: position.market.address,
      amount: {
        erc20: {
          currency: position.currency.address,
          value: {
            exact: amount, // 1 WETH
          },
          permitSig: signature,
        },
      },
      sender: evmAddress(walletClient!.account.address),
      chainId: position.market.chain.chainId,
      onBehalfOf: evmAddress("0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"),
    })
  );

  // …
};
```

</tab>
<tab label="TypeScript">

```tsx title="Repay ERC-20 with Permit"
import { repay, permitTypedData } from "@aave/client/actions";
import { signERC20PermitWith } from "@aave/client/viem";
import { bigDecimal, evmAddress } from "@aave/client";

import { client } from "./client";
import { wallet } from "./wallet";

const amount = bigDecimal(1); // 1 WETH

const result = await permitTypedData(client, {
  amount,
  chainId: position.market.chain.chainId,
  currency: position.currency.address,
  owner: evmAddress(wallet.account.address),
  spender: position.market.address,
})
  .andThen(signERC20PermitWith(wallet))
  .andThen((signature) =>
    repay(client, {
      market: position.market.address,
      amount: {
        erc20: {
          currency: position.currency.address,
          value: {
            exact: amount,
          },
          permitSig: signature,
        },
      },
      sender: evmAddress(wallet.account.address),
      chainId: position.market.chain.chainId,
    })
  );

// …
```

```tsx title="Repay ERC-20 with Permit On Behalf of Another"
import { repay, permitTypedData } from "@aave/client/actions";
import { signERC20PermitWith } from "@aave/client/viem";
import { bigDecimal, evmAddress } from "@aave/client";

import { client } from "./client";
import { wallet } from "./wallet";

const amount = bigDecimal(1); // 1 WETH

const result = await permitTypedData(client, {
  amount,
  chainId: position.market.chain.chainId,
  currency: position.currency.address,
  owner: evmAddress(wallet.account.address),
  spender: position.market.address,
})
  .andThen(signERC20PermitWith(wallet))
  .andThen((signature) =>
    repay(client, {
      market: position.market.address,
      amount: {
        erc20: {
          currency: position.currency.address,
          value: {
            exact: amount,
          },
          permitSig: signature,
        },
      },
      sender: evmAddress(wallet.account.address),
      chainId: position.market.chain.chainId,
      onBehalfOf: evmAddress("0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234"),
    })
  );

// …
```

</tab>
</tabgroup>
### 3. Process the Repay Execution Plan

Finally, handle the execution plan.

- **React**: Use the `useSendTransaction` hook for the [wallet library of your choice](../getting-started/react#send-aave-transactions) to send the transactions in the execution plan.
- **TypeScript**: Use `sendWith` for your [chosen wallet library](../getting-started/typescript#send-aave-transactions) 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.

<tabgroup>
<tab label="React">

```tsx title="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 states
const 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);
  }
};
```

</tab>
<tab label="TypeScript">

```ts title="Viem"
import { repay } from "@aave/client/actions";
import { sendWith } from "@aave/client/viem";

import { client } from "./client";
import { wallet } from "./wallet";

const result = await repay(client, {
  // …
})
  .andThen(sendWith(wallet))
  .andThen(client.waitForTransaction);

if (result.isErr()) {
  console.error("Repay failed:", result.error);
} else {
  console.log("Repay successful:", result.value);
}
```

</tab>
<tab label="GraphQL">

```json title="TransactionRequest"
{
  "data": {
    "repay": {
      "__typename": "TransactionRequest",
      "to": "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
      "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
      "data": "0x573ade81000000000000000000000000c02…",
      "value": "0",
      "chainId": 1,
      "operation": "REPAY"
    }
  }
}
```

</tab>
</tabgroup>
In GraphQL, if the response is an `ApprovalRequired`, you must first send the `approval` transaction. Once it succeeds, you can then send the `originalTransaction`.

```json title="ApprovalRequired"
{
  "data": {
    "repay": {
      "__typename": "ApprovalRequired",
      "reason": "Insufficient allowance for ERC-20 token transfer",
      "requiredAmount": {
        "value": "1.0",
        "decimals": 18
      },
      "currentAllowance": {
        "value": "0.0",
        "decimals": 18
      },
      "approval": {
        "to": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
        "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
        "data": "0x095ea7b3000000000000000000000000878…",
        "value": "0",
        "chainId": 1,
        "operation": null
      },
      "originalTransaction": {
        "to": "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2",
        "from": "0x742d35cc6e5c4ce3b69a2a8c7c8e5f7e9a0b1234",
        "data": "0x573ade81000000000000000000000000c02…",
        "value": "0",
        "chainId": 1,
        "operation": "REPAY"
      }
    }
  }
}
```

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

```json title="InsufficientBalanceError"
{
  "data": {
    "repay": {
      "__typename": "InsufficientBalanceError",
      "required": {
        "value": "1.0",
        "decimals": 18
      },
      "available": {
        "value": "0.5",
        "decimals": 18
      }
    }
  }
}
```
