Position Swaps

Learn how to modify your Aave v4 positions using integrated swap operations.


Position swaps combine swap functionality with User Position operations, letting you:

This feature leverages CoW Protocol for swap execution. Position swaps are gasless—users sign an intent and solvers handle execution. This eliminates gas costs while providing MEV protection and optimal execution through batch auctions.

Review the Fees section to understand swap costs.

Swap Supply Asset

Swapping supply assets combines withdraw, swap, and re-supply into one gasless step.

Common scenarios:

ScenarioDescription
Liquidation Risk ReductionUser wants to swap volatile collateral to stable assets to reduce liquidation risk
Better RatesUser wants to switch supply position to a reserve with better rates (regardless of being used as collateral or not)
Replenish CollateralUser wants to use a non-collateral supply to replenish a collateral position to gain more borrowing power at the same risk level
Better Risk PremiumUser wants to consolidate collateral to a less risky asset (lower Collateral Risk) to reduce the risk premium on borrows

Swapping supply assets can be broken down into the following steps:

  1. Identify the supply position to swap from

  2. Choose the target reserve to swap onto

  3. Choose between market order and limit order

  4. Execute the swap operation

Supply Position

Identify the supply position among the user's supply positions where reserve.canSwapFrom: true.

UserSupplyItem
const supplyPosition: UserSupplyItem = {  id: "aGVsbG8",  reserve: {    id: "SGVsbG8h",    canSwapFrom: true,    chain: {      chainId: 1,      name: "Ethereum",    },    spoke: {      id: "aGVsbG8",      // …    },    // …  },  isCollateral: true,  withdrawable: {    amount: {      value: BigDecimal(0.03),      exchange: {        value: BigDecimal(100.0),        // …      },      // …    },    // …  },  // …};

The reserve.canSwapFrom flag confirms that the correponding reserve isn't paused and flash loans are enabled on it.

Target Reserve

Choose the target reserve where canSupply: true. The target reserve must be on the same spoke as the source supply position.

Like with typical supply operations, the canSupply flag confirms that the reserve is active: it isn't frozen, it isn't paused, and the supply cap has not been reached.

Target Reserve
const targetReserve: Reserve = {  id: "V29ybGQh",  canSupply: true,  canUseAsCollateral: true,  spoke: {    id: "aGVsbG8",    // …  },  asset: {    underlying: {      address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",      info: {        name: "USD Coin",        symbol: "USDC",        decimals: 6,        // …      },      // …    },    // …  },  summary: {    supplyApy: {      normalized: BigDecimal(4.5), // 4.5% APY      // …    },    // …  },  userState: {    suppliable: {      exchange: {        value: BigDecimal(1245.67),        name: "USD",        symbol: "$",        // …      },      // …    },  },  // …};

Consider the following factors when selecting a target reserve:

  • Token: Check asset.underlying for the token of the new supply position

  • Collateral: Verify canUseAsCollateral if collateral is needed

  • Capacity: Review userState.suppliable for sufficient supply capacity

  • Rate: Compare summary.supplyApy for favorable APY

Market or Limit Order

You decide whether to use a market order or a limit order.

Market orders execute at current rates.

const request: SupplySwapQuoteRequest = {  market: {    sellPosition: supplyPosition.id,    buyReserve: targetReserve.id,    enableCollateral:      supplyPosition.isCollateral && targetReserve.canUseAsCollateral,    amount: bigDecimal(0.03),    user: evmAddress("0x123…"),    // selectedSlippage: bigDecimal(1), // Optional: override suggested slippage  },};

The request takes the following parameters:

  • sellPosition — The current supply position to swap from

  • buyReserve — The target reserve to swap to

  • enableCollateral — Whether to enable the new position as collateral

  • amount — The amount of the current position to swap

  • user — The user's address

  • selectedSlippage — Optional slippage tolerance to use instead of the suggested slippage

The enableCollateral flag controls the destination supply’s collateral status: true enables it as collateral; false keeps the existing status (or non-collateral for a new position). The examples assume the target reserve allows collateral and mirror the source’s collateral state; adjust to fit your scenario.

Execute the Swap

To execute a supply swap with AaveKit React, follow these steps.

1

Get a Quote

First, use the useSupplySwapQuote hook (or the imperative useSupplySwapQuoteAction variant) to get pricing information for the swap.

import { type SupplySwapQuoteRequest, useSupplySwapQuote } from "@aave/react";
function SwapQuote({ request }: { request: SupplySwapQuoteRequest }) {  const { data, loading, error } = useSupplySwapQuote(request);
  if (loading) return <p>Loading…</p>;
  if (error) {    if (error.name === "ValidationError") {      switch (error.cause.__typename) {        case "InsufficientLiquidityError":          return <p>Not enough liquidity for this swap</p>;      }    }    return <p>{error.message}</p>;  }
  // data: SwapQuote  return (    <div>      <p>You will receive: {data.finalBuy.amount.value.toDisplayString()}</p>      <p>Partner fee: {data.costs.partnerFee.amount.value.toDisplayString()}</p>      <p>Slippage: {data.suggestedSlippage.normalized}%</p>    </div>  );}

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

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

The SwapQuote object provides detailed pricing information for swap operations.

interface SwapQuote {  __typename: "SwapQuote";  accuracy: QuoteAccuracy;  quoteId: SwapId;  suggestedSlippage: PercentNumber;  selectedSlippage: PercentNumber | null;  buy: TokenAmount;  sell: TokenAmount;  finalBuy: TokenAmount;  finalSell: TokenAmount;  costs: SwapQuoteCosts;}

Where:

  • accuracy — quote accuracy level (QuoteAccuracy.Fast or QuoteAccuracy.Accurate)

  • quoteId — a unique quote identifier required for executing the swap

  • buy and sell — current prices before fees

  • finalBuy and finalSell — amounts you'll receive/pay after fees and slippage

  • costs — a breakdown of all fees (partner fee, provider fee, flash loan fee, network costs)

  • suggestedSlippage — recommended slippage tolerance

  • selectedSlippage — the slippage tolerance selected when requesting a market quote (if provided)

2

Preview the Impact

Then, use the usePreview hook (or the imperative usePreviewAction variant) to preview the impact of the swap operation on the user's position.

import { type SwapQuote, usePreview } from "@aave/react";
function SwapPreview({ quote }: { quote: SwapQuote }) {  const { data, error, loading } = usePreview({    action: {      supplySwap: {        fromQuote: {          quoteId: quote.quoteId,        },      },    },  });
  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?.value.toFixed(2) ?? "N/A"}</p>      <p>To: {data.healthFactor.after?.value.toFixed(2) ?? "N/A"}</p>
      <h3>User Risk Premium:</h3>      <p>From: {data.riskPremium.current.normalized.toFixed(2)}%</p>      <p>To: {data.riskPremium.after.normalized.toFixed(2)}%</p>
      <h3>Net APY:</h3>      <p>From: {data.netApy.current.normalized.toFixed(2)}%</p>      <p>To: {data.netApy.after.normalized.toFixed(2)}%</p>
      <h3>Net Collateral:</h3>      <p>From: {data.netCollateral.current.value.toDisplayString(2)}</p>      <p>To: {data.netCollateral.after.value.toDisplayString(2)}</p>
      <h3>Borrowing Power:</h3>      <p>From: {data.borrowingPower.current.value.toDisplayString(2)}</p>      <p>To: {data.borrowingPower.after.value.toDisplayString(2)}</p>    </div>  );}

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

FieldImpact
healthFactor.[current → after]: BigDecimal|nullHigher is better
(null if not applicable)
riskPremium.[current → after]: PercentNumberLower is better
netApy.[current → after]: PercentNumberHigher is better
netCollateral.[current → after]: ExchangeAmountHigher is better
netBalance.[current → after]: ExchangeAmountUpdated balance
projectedEarning.[current → after]: ExchangeAmountProjected earnings
borrowingPower.[current → after]: ExchangeAmountBorrowing power
otherConditions: UserPositionConditionVariation[]Dynamic config changes

When swapping supply positions, Position Conditions update depending on the collateral status:

  • Swapping collateral: Swapping out of collateral updates the dynamic config for all reserves in the position and refreshes the user risk premium.

  • Swapping non-collateral into collateral: The reserve being swapped into uses the latest dynamic config, with no implicit risk premium changes.

The otherConditions field is an array of objects describing the resulting dynamic config changes.

  • CollateralFactorVariation – Collateral factor change

  • LiquidationFeeVariation – Liquidation fee change

  • MaxLiquidationBonusVariation – Maximum liquidation bonus change

3

Configure Wallet Integration

Then, instantiate the useSignTypedData hook for the wallet library of your choice.

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

4

Define the Swap Flow

Then, use the useSupplySwap hook to handle the operation.

import { useSupplySwap } from "@aave/react";
const [swapSupply, { loading, error }] = useSupplySwap((plan) => {  switch (plan.__typename) {    case "PositionSwapAdapterContractApproval":    case "PositionSwapPositionManagerApproval":      return signTypedData(plan.bySignature);
    case "SwapByIntent":      return signTypedData(plan.data);  }});

The operation involves up to 3 signatures:

  • Swap adapter contract approval: A one-time-use contract that encapsulates the swap logic. This signature ensures the contract is used only once for this specific swap operation.

  • Swap position manager approval: Authorizes a dedicated Position Manager to operate on the user's position.

  • Swap intent: The actual swap order containing swap parameters and the adapter contract and position manager approval signatures.

5

Execute the Operation

Then, execute the swap for the given quote.

Execute
const execute = async (quote: SwapQuote) => {  const result = await swapSupply({    fromQuote: {      quoteId: quote.quoteId,    },  });
  if (result.isErr()) {    console.error(result.error);    return;  }
  console.log("Swap order placed:", result.value);};

6

Handle the Result

Finally, handle the result.

Handle Result
if (result.isErr()) {  switch (result.error.name) {    case "CancelError":      return;
    case "SigningError":      console.error(`Failed to sign: ${result.error.message}`);      break;
    case "TimeoutError":      console.error(`Timed out: ${result.error.message}`);      break;
    case "TransactionError":      console.error(`Failed: ${result.error.message}`);      break;
    case "ValidationError":      switch (result.error.cause.__typename) {        case "InsufficientBalanceError":          console.error(            "Insufficient balance:",            `required: ${result.error.cause.required.value.toDisplayString(2)}`,            `available: ${result.error.cause.available.value.toDisplayString(2)}`,          );          break;        case "InsufficientLiquidityError":          console.error(`Insufficient liquidity: ${result.error.cause.reason}`);          break;      }      break;
    case "UnexpectedError":      console.error(result.error.message);      break;  }} else {  console.log("Swap order placed:", result.value);}

That's it—you placed your first supply swap order. Keep track of its status in the Monitor Swap Status section.

Swap Borrow Asset

Swapping borrow assets combines repay, swap, and re-borrow into one gasless step.

Common scenarios:

ScenarioDescription
Rate OptimizationUser wants to switch debt from a high-interest token to a lower-interest one (e.g., USDC → GHO)
Risk ManagementUser wants to match their debt currency to their income or collateral to reduce currency exposure
Liquidation AvoidanceUser wants to swap volatile debt (e.g., ETH-denominated) to stable debt (e.g., USDC) to avoid liquidation

Swapping borrow assets can be broken down into the following steps:

  1. Identify the borrow position to swap from

  2. Choose the target reserve to swap onto

  3. Choose between market order and limit order

  4. Execute the swap operation

Borrow Position

Identify the borrow position among the user's borrow positions where reserve.canSwapFrom: true.

UserBorrowItem
const borrowPosition: UserBorrowItem = {  id: "Ym9ycm93",  reserve: {    id: "SGVsbG8h",    canSwapFrom: true,    chain: {      chainId: 1,      name: "Ethereum",    },    spoke: {      id: "aGVsbG8",      // …    },    // …  },  debt: {    amount: {      value: BigDecimal(1000.0),      exchange: {        value: BigDecimal(1000.0),        // …      },      // …    },    // …  },  principal: {    amount: {      value: BigDecimal(950.0),      // …    },    // …  },  interest: {    amount: {      value: BigDecimal(50.0),      // …    },    // …  },  // …};

The reserve.canSwapFrom flag confirms that the corresponding reserve isn't paused and flash loans, required to perform the swap, are enabled.

Target Reserve

Choose the target reserve where canBorrow: true. The target reserve must be on the same spoke as the source borrow position.

Like with typical borrow operations, the canBorrow flag confirms that the reserve is active: it isn't frozen, it isn't paused, and the borrow cap has not been reached.

Target Reserve
const targetReserve: Reserve = {  id: "V29ybGQh",  canBorrow: true,  spoke: {    id: "aGVsbG8",    // …  },  asset: {    underlying: {      address: "0x40d16fc0246ad3160ccc09b8d0d3a2cd28ae6c2f",      info: {        name: "GHO",        symbol: "GHO",        decimals: 18,        // …      },      // …    },    // …  },  summary: {    borrowApy: {      normalized: BigDecimal(2.5), // 2.5% APY      // …    },    // …  },  userState: {    borrowable: {      exchange: {        value: BigDecimal(5000.0),        name: "USD",        symbol: "$",        // …      },      // …    },  },  // …};

Consider the following factors when selecting a target reserve:

  • Token: Check asset.underlying for the token of the new debt position

  • Capacity: Review userState.borrowable for sufficient borrow capacity

  • Rate: Compare summary.borrowApy for favorable borrowing rates

Market or Limit Order

You decide whether to use a market order or a limit order.

Market orders execute at current rates.

const request: BorrowSwapQuoteRequest = {  market: {    debtPosition: borrowPosition.id,    buyReserve: targetReserve.id,    amount: bigDecimal(1000),    user: evmAddress("0x123…"),    // selectedSlippage: bigDecimal(1), // Optional: override suggested slippage  },};

The request takes the following parameters:

  • debtPosition — The current borrow position to swap from

  • buyReserve — The target reserve to swap to

  • amount — The amount of the current debt to swap

  • user — The user's address

  • selectedSlippage — Optional slippage tolerance to use instead of the suggested slippage

Execute the Swap

To execute a borrow swap with AaveKit React, follow these steps.

1

Get a Quote

First, use the useBorrowSwapQuote hook (or the imperative useBorrowSwapQuoteAction variant) to get pricing information for the swap.

import { type BorrowSwapQuoteRequest, useBorrowSwapQuote } from "@aave/react";
function SwapQuote({ request }: { request: BorrowSwapQuoteRequest }) {  const { data, loading, error } = useBorrowSwapQuote(request);
  if (loading) return <p>Loading…</p>;
  if (error) {    if (error.name === "ValidationError") {      switch (error.cause.__typename) {        case "InsufficientLiquidityError":          return <p>Not enough liquidity for this swap</p>;      }    }    return <p>{error.message}</p>;  }
  // data: SwapQuote  return (    <div>      <p>New debt amount: {data.finalBuy.amount.value.toDisplayString()}</p>      <p>Partner fee: {data.costs.partnerFee.amount.value.toDisplayString()}</p>      <p>Slippage: {data.suggestedSlippage.normalized}%</p>    </div>  );}

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

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

The SwapQuote object provides detailed pricing information for swap operations.

interface SwapQuote {  __typename: "SwapQuote";  accuracy: QuoteAccuracy;  quoteId: SwapId;  suggestedSlippage: PercentNumber;  selectedSlippage: PercentNumber | null;  buy: TokenAmount;  sell: TokenAmount;  finalBuy: TokenAmount;  finalSell: TokenAmount;  costs: SwapQuoteCosts;}

Where:

  • accuracy — quote accuracy level (QuoteAccuracy.Fast or QuoteAccuracy.Accurate)

  • quoteId — a unique quote identifier required for executing the swap

  • buy and sell — current prices before fees

  • finalBuy and finalSell — amounts you'll receive/pay after fees and slippage

  • costs — a breakdown of all fees (partner fee, provider fee, flash loan fee, network costs)

  • suggestedSlippage — recommended slippage tolerance

  • selectedSlippage — the slippage tolerance selected when requesting a market quote (if provided)

2

Preview the Impact

Then, use the usePreview hook (or the imperative usePreviewAction variant) to preview the impact of the swap operation on the user's position.

import { type SwapQuote, usePreview } from "@aave/react";
function SwapPreview({ quote }: { quote: SwapQuote }) {  const { data, error, loading } = usePreview({    action: {      borrowSwap: {        fromQuote: {          quoteId: quote.quoteId,        },      },    },  });
  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?.value.toFixed(2) ?? "N/A"}</p>      <p>To: {data.healthFactor.after?.value.toFixed(2) ?? "N/A"}</p>
      <h3>User Risk Premium:</h3>      <p>From: {data.riskPremium.current.normalized.toFixed(2)}%</p>      <p>To: {data.riskPremium.after.normalized.toFixed(2)}%</p>
      <h3>Net APY:</h3>      <p>From: {data.netApy.current.normalized.toFixed(2)}%</p>      <p>To: {data.netApy.after.normalized.toFixed(2)}%</p>
      <h3>Net Collateral:</h3>      <p>From: {data.netCollateral.current.value.toDisplayString(2)}</p>      <p>To: {data.netCollateral.after.value.toDisplayString(2)}</p>
      <h3>Borrowing Power:</h3>      <p>From: {data.borrowingPower.current.value.toDisplayString(2)}</p>      <p>To: {data.borrowingPower.after.value.toDisplayString(2)}</p>    </div>  );}

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

FieldImpact
healthFactor.[current → after]: BigDecimal|nullHigher is better
(null if not applicable)
riskPremium.[current → after]: PercentNumberLower is better
netApy.[current → after]: PercentNumberHigher is better (less negative for net borrowers)
netCollateral.[current → after]: ExchangeAmountUpdated collateral value
netBalance.[current → after]: ExchangeAmountUpdated balance
projectedEarning.[current → after]: ExchangeAmountProjected earnings
borrowingPower.[current → after]: ExchangeAmountBorrowing power
otherConditions: UserPositionConditionVariation[]Dynamic config changes

Swap borrowing assets updates the Dynamic Config and User Risk Premium of the user position.

The otherConditions field is an array of objects describing the resulting dynamic config changes.

  • CollateralFactorVariation – Collateral factor change

  • LiquidationFeeVariation – Liquidation fee change

  • MaxLiquidationBonusVariation – Maximum liquidation bonus change

3

Configure Wallet Integration

Then, instantiate the useSignTypedData hook for the wallet library of your choice.

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

4

Define the Swap Flow

Then, use the useBorrowSwap hook to handle the operation.

import { useBorrowSwap } from "@aave/react";
const [swapBorrow, { loading, error }] = useBorrowSwap((plan) => {  switch (plan.__typename) {    case "PositionSwapAdapterContractApproval":    case "PositionSwapPositionManagerApproval":      return signTypedData(plan.bySignature);
    case "SwapByIntent":      return signTypedData(plan.data);  }});

The operation involves up to 3 signatures:

  • Swap adapter contract approval: A one-time-use contract that encapsulates the swap logic. This signature ensures the contract is used only once for this specific swap operation.

  • Swap position manager approval: Authorizes a dedicated Position Manager to operate on the user's position.

  • Swap intent: The actual swap order containing swap parameters and the adapter contract and position manager approval signatures.

5

Execute the Operation

Then, execute the swap for the given quote.

Execute
const execute = async (quote: SwapQuote) => {  const result = await swapBorrow({    fromQuote: {      quoteId: quote.quoteId,    },  });
  if (result.isErr()) {    console.error(result.error);    return;  }
  console.log("Swap order placed:", result.value);};

6

Handle the Result

Finally, handle the result.

Handle Result
if (result.isErr()) {  switch (result.error.name) {    case "CancelError":      return;
    case "SigningError":      console.error(`Failed to sign: ${result.error.message}`);      break;
    case "TimeoutError":      console.error(`Timed out: ${result.error.message}`);      break;
    case "TransactionError":      console.error(`Failed: ${result.error.message}`);      break;
    case "ValidationError":      switch (result.error.cause.__typename) {        case "InsufficientBalanceError":          console.error(            "Insufficient balance:",            `required: ${result.error.cause.required.value.toDisplayString(2)}`,            `available: ${result.error.cause.available.value.toDisplayString(2)}`,          );          break;        case "InsufficientLiquidityError":          console.error(`Insufficient liquidity: ${result.error.cause.reason}`);          break;      }      break;
    case "UnexpectedError":      console.error(result.error.message);      break;  }} else {  console.log("Swap order placed:", result.value);}

That's it—you placed your first borrow swap order. Keep track of its status in the Monitor Swap Status section.

Repay with Supply

Repay with supply combines withdraw, swap, and repay into one gasless step.

Common scenarios:

ScenarioDescription
Avoid LiquidationUser wants to improve Health Factor by repaying debt using their supply
Rebalance PositionsUser wants to consolidate stablecoin exposure by using idle supply to pay off debt in a different stablecoin
Reduce Debt ExposureUser wants to reduce debt load by converting non-collateral supply into debt repayment

Repaying with a supply position reduces your supplied balance. If the asset is used as collateral, ensure your remaining position maintains a healthy state.

Repay with supply can be broken down into the following steps:

  1. Identify the supply position to use for repayment

  2. Identify the borrow position to repay

  3. Choose between market order and limit order

  4. Execute the swap operation

Supply Position

Identify the supply position among the user's supply positions where reserve.canSwapFrom: true.

UserSupplyItem
const supplyPosition: UserSupplyItem = {  id: "c3VwcGx5",  reserve: {    id: "SGVsbG8h",    canSwapFrom: true,    chain: {      chainId: 1,      name: "Ethereum",    },    spoke: {      id: "aGVsbG8",      // …    },    // …  },  isCollateral: true,  balance: {    amount: {      value: BigDecimal(5000.0),      exchange: {        value: BigDecimal(5000.0),        // …      },      // …    },    // …  },  principal: {    amount: {      value: BigDecimal(4800.0),      // …    },    // …  },  interest: {    amount: {      value: BigDecimal(200.0),      // …    },    // …  },  // …};

The reserve.canSwapFrom flag confirms that the corresponding reserve isn't paused and flash loans, required to perform the swap, are enabled.

Borrow Position

Identify the borrow position among the user's borrow positions to repay.

UserBorrowItem
const borrowPosition: UserBorrowItem = {  id: "Ym9ycm93",  reserve: {    id: "V29ybGQh",    spoke: {      id: "aGVsbG8",      // …    },    // …  },  debt: {    amount: {      value: BigDecimal(1000.0),      exchange: {        value: BigDecimal(1000.0),        // …      },      // …    },    // …  },  principal: {    amount: {      value: BigDecimal(950.0),      // …    },    // …  },  interest: {    amount: {      value: BigDecimal(50.0),      // …    },    // …  },  // …};

The supply and borrow positions must be on the same spoke. The supply position's reserve is what gets swapped and used to repay the debt.

Market or Limit Order

You decide whether to use a market order or a limit order.

Market orders execute at current rates.

const request: RepayWithSupplyQuoteRequest = {  market: {    debtPosition: borrowPosition.id,    repayWithReserve: supplyPosition.reserve.id,    amount: bigDecimal(1000),    user: evmAddress("0x123…"),    // kind: RepayWithSupplyKind.Repay, // Optional: specify repay or supply priority    // selectedSlippage: bigDecimal(1), // Optional: override suggested slippage  },};

The request takes the following parameters:

  • debtPosition — The borrow position with debt to repay

  • repayWithReserve — The reserve of the supply position to use for repayment

  • amount — The swap amount, interpreted based on kind

  • user — The user's address

  • kind — Repay (default) or Supply, determines how amount is interpreted

  • selectedSlippage — Optional slippage tolerance to use instead of the suggested slippage

Since only one amount is provided, the kind parameter determines how it's interpreted:

KindUser inputs…System calculates…
Repay (default)The debt amount to repayThe supply amount needed
SupplyThe supply amount to useThe debt amount that will be repaid

Execute the Swap

To execute a repay with supply swap with AaveKit React, follow these steps.

1

Get a Quote

First, use the useRepayWithSupplyQuote hook (or the imperative useRepayWithSupplyQuoteAction variant) to get pricing information for the swap.

import {  type RepayWithSupplyQuoteRequest,  useRepayWithSupplyQuote,} from "@aave/react";
function SwapQuote({ request }: { request: RepayWithSupplyQuoteRequest }) {  const { data, loading, error } = useRepayWithSupplyQuote(request);
  if (loading) return <p>Loading…</p>;
  if (error) {    if (error.name === "ValidationError") {      switch (error.cause.__typename) {        case "InsufficientLiquidityError":          return <p>Not enough liquidity for this swap</p>;      }    }    return <p>{error.message}</p>;  }
  // data: SwapQuote  return (    <div>      <p>Repay amount: {data.finalBuy.amount.value.toDisplayString()}</p>      <p>Partner fee: {data.costs.partnerFee.amount.value.toDisplayString()}</p>      <p>Slippage: {data.suggestedSlippage.normalized}%</p>    </div>  );}

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

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

The SwapQuote object provides detailed pricing information for swap operations.

interface SwapQuote {  __typename: "SwapQuote";  accuracy: QuoteAccuracy;  quoteId: SwapId;  suggestedSlippage: PercentNumber;  selectedSlippage: PercentNumber | null;  buy: TokenAmount;  sell: TokenAmount;  finalBuy: TokenAmount;  finalSell: TokenAmount;  costs: SwapQuoteCosts;}

Where:

  • accuracy — quote accuracy level (QuoteAccuracy.Fast or QuoteAccuracy.Accurate)

  • quoteId — a unique quote identifier required for executing the swap

  • buy and sell — current prices before fees

  • finalBuy and finalSell — amounts you'll receive/pay after fees and slippage

  • costs — a breakdown of all fees (partner fee, provider fee, flash loan fee, network costs)

  • suggestedSlippage — recommended slippage tolerance

  • selectedSlippage — the slippage tolerance selected when requesting a market quote (if provided)

2

Preview the Impact

Then, use the usePreview hook (or the imperative usePreviewAction variant) to preview the impact of the swap operation on the user's position.

import { type SwapQuote, usePreview } from "@aave/react";
function SwapPreview({ quote }: { quote: SwapQuote }) {  const { data, error, loading } = usePreview({    action: {      repayWithSupply: {        fromQuote: {          quoteId: quote.quoteId,        },      },    },  });
  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?.value.toFixed(2) ?? "N/A"}</p>      <p>To: {data.healthFactor.after?.value.toFixed(2) ?? "N/A"}</p>
      <h3>User Risk Premium:</h3>      <p>From: {data.riskPremium.current.normalized.toFixed(2)}%</p>      <p>To: {data.riskPremium.after.normalized.toFixed(2)}%</p>
      <h3>Net APY:</h3>      <p>From: {data.netApy.current.normalized.toFixed(2)}%</p>      <p>To: {data.netApy.after.normalized.toFixed(2)}%</p>
      <h3>Net Collateral:</h3>      <p>From: {data.netCollateral.current.value.toDisplayString(2)}</p>      <p>To: {data.netCollateral.after.value.toDisplayString(2)}</p>
      <h3>Borrowing Power:</h3>      <p>From: {data.borrowingPower.current.value.toDisplayString(2)}</p>      <p>To: {data.borrowingPower.after.value.toDisplayString(2)}</p>    </div>  );}

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

FieldImpact
healthFactor.[current → after]: BigDecimal|nullHigher is better
(null if not applicable)
riskPremium.[current → after]: PercentNumberLower is better
netApy.[current → after]: PercentNumberHigher is better (less negative for net borrowers)
netCollateral.[current → after]: ExchangeAmountLower after (collateral used to repay)
netBalance.[current → after]: ExchangeAmountUpdated balance
projectedEarning.[current → after]: ExchangeAmountProjected earnings
borrowingPower.[current → after]: ExchangeAmountBorrowing power
otherConditions: UserPositionConditionVariation[]Dynamic config changes

If the supply used for repayment was enabled as collateral, the Dynamic Config and User Risk Premium of the user position will be updated.

The otherConditions field is an array of objects describing the resulting dynamic config changes.

  • CollateralFactorVariation – Collateral factor change

  • LiquidationFeeVariation – Liquidation fee change

  • MaxLiquidationBonusVariation – Maximum liquidation bonus change

3

Configure Wallet Integration

Then, instantiate the useSignTypedData hook for the wallet library of your choice.

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

4

Define the Swap Flow

Then, use the useRepayWithSupply hook to handle the operation.

import { useRepayWithSupply } from "@aave/react";
const [repayWithSupply, { loading, error }] = useRepayWithSupply((plan) => {  switch (plan.__typename) {    case "PositionSwapAdapterContractApproval":    case "PositionSwapPositionManagerApproval":      return signTypedData(plan.bySignature);
    case "SwapByIntent":      return signTypedData(plan.data);  }});

The operation involves up to 3 signatures:

  • Swap adapter contract approval: A one-time-use contract that encapsulates the swap logic. This signature ensures the contract is used only once for this specific swap operation.

  • Swap position manager approval: Authorizes a dedicated Position Manager to operate on the user's position.

  • Swap intent: The actual swap order containing swap parameters and the adapter contract and position manager approval signatures.

5

Execute the Operation

Then, execute the swap for the given quote.

Execute
const execute = async (quote: SwapQuote) => {  const result = await repayWithSupply({    fromQuote: {      quoteId: quote.quoteId,    },  });
  if (result.isErr()) {    console.error(result.error);    return;  }
  console.log("Swap order placed:", result.value);};

6

Handle the Result

Finally, handle the result.

Handle Result
if (result.isErr()) {  switch (result.error.name) {    case "CancelError":      return;
    case "SigningError":      console.error(`Failed to sign: ${result.error.message}`);      break;
    case "TimeoutError":      console.error(`Timed out: ${result.error.message}`);      break;
    case "TransactionError":      console.error(`Failed: ${result.error.message}`);      break;
    case "ValidationError":      switch (result.error.cause.__typename) {        case "InsufficientBalanceError":          console.error(            "Insufficient balance:",            `required: ${result.error.cause.required.value.toDisplayString(2)}`,            `available: ${result.error.cause.available.value.toDisplayString(2)}`,          );          break;        case "InsufficientLiquidityError":          console.error(`Insufficient liquidity: ${result.error.cause.reason}`);          break;      }      break;
    case "UnexpectedError":      console.error(result.error.message);      break;  }} else {  console.log("Swap order placed:", result.value);}

That's it—you placed your first repay with supply order. Keep track of its status in the Monitor Swap Status section.

Withdraw and Swap

Withdraw assets from your supply position and receive them as a different token in one operation.

Common scenarios:

ScenarioExample
Take ProfitsWithdraw WETH supply and receive USDC directly

This feature is coming soon. Documentation will be available upon release.