Swap Supply Asset
Swapping supply assets combines withdraw, swap, and re-supply into one step.
Position swaps now run on the Order API. Update your code:
prepare→Position Swap prepareOrder swap→submitOrder - React:
use→Supply Swap useSupply Swap Order - React:
use→Borrow Swap useBorrow Swap Order - React:
use→Repay With Supply useRepay With Supply Order
This feature leverages CoW Protocol for swap execution. Users sign an intent and solvers execute it through batch auctions with MEV protection. Most flows need no transaction; if an approval or the submit result returns a transaction request, the user sends it and pays gas.
See Fees for swap costs.
Common scenarios:
| Scenario | Description |
|---|---|
| Liquidation Risk Reduction | User wants to swap volatile collateral to stable assets to reduce liquidation risk |
| Better Rates | User wants to switch supply position to a reserve with better rates (regardless of being used as collateral or not) |
| Replenish Collateral | User wants to use a non-collateral supply to replenish a collateral position to gain more borrowing power at the same risk level |
| Better Risk Premium | User 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:
- Identify the supply position to swap from
- Choose the target reserve to swap onto
- Choose between market order and limit order
- Execute the swap operation
Identify the Supply Position
Identify the supply position among the user’s supply positions where reserve..
const supplyPosition: UserSupplyItem = {
id: "aGVsbG8",
reserve: {
id: "SGVsbG8h",
canSwapFrom: true,
chain: {
chainId: 1,
name: "Ethereum",
},
spoke: {
id: "aGVsbG8",
// …
},
// …
},
isCollateral: true,
balance: {
amount: {
value: BigDecimal(1.5),
exchange: {
value: BigDecimal(5000.0),
// …
},
// …
},
// …
},
withdrawable: {
amount: {
value: BigDecimal(0.03),
exchange: {
value: BigDecimal(100.0),
// …
},
// …
},
// …
},
// …
};
reserve. means the reserve isn’t paused and has flash loans
enabled, which the swap needs.
Identify the Target Reserve
Choose the target reserve where can. The target reserve must be on the same spoke as the source supply position.
As in a regular supply, can means the reserve isn’t frozen, isn’t
paused and is below its supply cap.
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.for the token of the new supply positionunderlying - Collateral: Verify
canif collateral is neededUse As Collateral - Capacity: Review
userfor sufficient supply capacityState. suppliable - Rate: Compare
summary.for favorable APYsupply Apy
Market or Limit Order
You decide whether to use a market order or a limit order.
Market Orders
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
},
};
{
"request": {
"market": {
"sellPosition": "aGVsbG8",
"buyReserve": "V29ybGQh",
"enableCollateral": true,
"amount": "0.03",
"user": "0x123…"
}
}
}
The request takes the following parameters:
sell: The current supply position to swap fromPosition buy: The target reserve to swap toReserve enable: Whether to enable the new position as collateralCollateral amount: The amount of the current position to swapuser: The user’s addressselected: Optional slippage tolerance to use instead of the suggested slippageSlippage
Limit Orders
Limit orders execute when your price condition is met.
const request: SupplySwapQuoteRequest = {
limit: {
currentPosition: supplyPosition.id,
currentAmount: bigDecimal(0.03),
newReserve: targetReserve.id,
newAmount: bigDecimal(105), // Desired amount to receive
enableCollateral:
supplyPosition.isCollateral && targetReserve.canUseAsCollateral,
user: evmAddress("0x123…"),
kind: SupplySwapKind.Current,
// deadline: new Date(Date.now() + 24 * 60 * 60 * 1000), // Optional: custom expiry
},
};
{
"request": {
"limit": {
"currentPosition": "aGVsbG8",
"currentAmount": "0.03",
"newReserve": "V29ybGQh",
"newAmount": "105",
"enableCollateral": true,
"user": "0x123…",
"kind": "CURRENT"
}
}
}
The request takes the following parameters:
current: The current supply position to swap fromPosition current: The amount of the current position to swapAmount new: The target reserve to swap toReserve new: The desired amount to receive in the new positionAmount enable: Whether to enable the new position as collateralCollateral user: The user’s addresskind: Current (default) or New, determines which amount is honoreddeadline: Optional deadline as DateTime; if not provided, uses default expiry
With both amounts specified, the kind parameter determines which amount takes priority:
| Kind | User specifies… | What happens with the order |
|---|---|---|
| Current | The exact current amount and a minimum new amount | Order fulfilled when new position price allows desired exchange within current limit |
| New | The exact new amount and a maximum current usage | Order fulfilled when current position price allows achieving the desired new amount |
The enable 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.
Step-by-Step with AaveKit
To execute a supply swap with AaveKit, follow these steps.
1. Get a Quote
First, use the use hook (or the imperative use variant) in React, the supply action in TypeScript, or the supply query in GraphQL 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>
);
}
import { type SupplySwapQuoteRequest, useSupplySwapQuote } from "@aave/react";
function SwapQuote({ request }: { request: SupplySwapQuoteRequest }) {
const { data } = useSupplySwapQuote({
...request,
suspense: true,
});
// 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>
);
}
import {
type SupplySwapQuoteRequest,
useSupplySwapQuoteAction,
} from "@aave/react";
const [getQuote, { called, data, error, loading }] = useSupplySwapQuoteAction();
const handler = async (request: SupplySwapQuoteRequest) => {
const result = await getQuote(request);
if (result.isOk()) {
// result.value: SwapQuote
console.log(result.value);
} else {
console.error(result.error);
}
};
import { supplySwapQuote } from "@aave/client/actions";
import { client } from "./client";
// …
const result = await supplySwapQuote(client, request);
if (result.isErr()) {
console.error(result.error);
return;
}
// result.value.quote: SwapQuote
import { AaveClient } from "@aave/client";
export const client = AaveClient.create();
query ($request: SupplySwapQuoteRequest!, $currency: Currency!) {
supplySwapQuote(request: $request) {
__typename
... on PositionSwapByIntentApprovalsRequired {
quote {
...SwapQuote
}
approvals {
...PositionSwapApproval
}
}
... on InsufficientLiquidityError {
reason
}
}
}
fragment PositionSwapApproval on PositionSwapApproval {
__typename
... on PositionSwapAdapterContractApproval {
bySignature {
...SwapTypedData
}
}
... on PositionSwapPositionManagerApproval {
byTransaction {
...TransactionRequest
}
bySignature {
...SwapTypedData
}
}
... on PositionSwapSetCollateralApproval {
bySignature {
...SwapTypedData
}
}
}
In React and TypeScript, 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,
});
import { Currency } from "@aave/react";
const [getQuote, { called, data, error, loading }] = useSupplySwapQuoteAction({
currency: Currency.Eur,
});
import { Currency } from "@aave/client";
// …
const result = await supplySwapQuote(client, request, {
currency: Currency.Eur,
});
In React and TypeScript, the quote is returned as a Swap.
The Swap 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;
orderQuoteId: OrderQuoteId;
costs: SwapQuoteCosts;
}
interface SwapQuoteCosts {
__typename: "SwapQuoteCosts";
networkCosts: TokenAmount;
partnerFee: TokenAmount;
flashloanFee: TokenAmount | null;
providerFee: TokenAmount;
}
type TokenAmount = Erc20Amount | NativeAmount;
interface Erc20Amount {
__typename: "Erc20Amount";
token: Erc20Token;
amount: DecimalNumber;
exchange: ExchangeAmount;
exchangeRate: DecimalNumber;
}
interface NativeAmount {
__typename: "NativeAmount";
token: NativeToken;
amount: DecimalNumber;
exchange: ExchangeAmount;
exchangeRate: DecimalNumber;
}
Where:
accuracy: quote accuracy level (QuoteorAccuracy. Fast Quote)Accuracy. Accurate quote: a unique quote identifier required for executing the swapId buyandsell: token amounts before fees and slippagefinalandBuy final: amounts you’ll receive/pay after fees and slippageSell order: same value asQuote Id quote, typed for order operationsId costs: a breakdown of all fees (partner fee, provider fee, flash loan fee, network costs)suggested: recommended slippage tolerance based on asset volatility and order sizeSlippage selected: the slippage tolerance selected when requesting a market quote (if provided)Slippage
In GraphQL, the response can be either:
Position: The quote was successful, but the user needs to sign approvals before executing the swap.Swap By Intent Approvals Required Insufficient: There’s not enough liquidity for the requested swap amount.Liquidity Error
The Position contains the Swap with pricing details and the Position list of required approvals to sign before executing the swap.
The Swap object provides detailed pricing information for swap operations.
fragment SwapQuote on SwapQuote {
__typename
accuracy
quoteId
suggestedSlippage {
...PercentNumber
}
selectedSlippage {
...PercentNumber
}
buy {
...TokenAmount
}
sell {
...TokenAmount
}
finalBuy {
...TokenAmount
}
finalSell {
...TokenAmount
}
orderQuoteId
costs {
...SwapQuoteCosts
}
}
fragment SwapQuoteCosts on SwapQuoteCosts {
__typename
networkCosts {
...TokenAmount
}
partnerFee {
...TokenAmount
}
flashloanFee {
...TokenAmount
}
providerFee {
...TokenAmount
}
}
fragment TokenAmount on TokenAmount {
__typename
... on Erc20Amount {
token {
...Erc20Token
}
amount {
...DecimalNumber
}
exchange(currency: $currency) {
...ExchangeAmount
}
exchangeRate(currency: $currency) {
...DecimalNumber
}
}
... on NativeAmount {
token {
...NativeToken
}
amount {
...DecimalNumber
}
exchange(currency: $currency) {
...ExchangeAmount
}
exchangeRate(currency: $currency) {
...DecimalNumber
}
}
}
Where:
accuracy: quote accuracy level (FASTorACCURATE)quote: a unique quote identifier required for executing the swapId buyandsell: token amounts before fees and slippagefinalandBuy final: amounts you’ll receive/pay after fees and slippageSell order: same value asQuote Id quote, typed for order operationsId costs: a breakdown of all fees (partner fee, provider fee, flash loan fee, network costs)suggested: recommended slippage tolerance based on asset volatility and order sizeSlippage selected: the slippage tolerance selected when requesting a market quote (if provided)Slippage
2. Preview the Impact
Then, use the use hook (or the imperative use variant) in React, the preview action in TypeScript, or the preview query with the quote from the previous step in GraphQL to preview the impact of the swap operation on the user’s position. In TypeScript and GraphQL, this step is optional.
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?.toFixed(2) ?? "N/A"}</p>
<p>To: {data.healthFactor.after?.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>Max Borrowing Power:</h3>
<p>From: {data.maxBorrowingPower.current.value.toDisplayString(2)}</p>
<p>To: {data.maxBorrowingPower.after.value.toDisplayString(2)}</p>
</div>
);
}
import { type SwapQuote, usePreview } from "@aave/react";
function SwapPreview({ quote }: { quote: SwapQuote }) {
const { data, error, loading } = usePreview({
action: {
supplySwap: {
fromQuote: {
quoteId: quote.quoteId,
},
},
},
suspense: true,
});
// data: PreviewUserPosition
return (
<div>
<h3>Health Factor:</h3>
<p>From: {data.healthFactor.current?.toFixed(2) ?? "N/A"}</p>
<p>To: {data.healthFactor.after?.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>Max Borrowing Power:</h3>
<p>From: {data.maxBorrowingPower.current.value.toDisplayString(2)}</p>
<p>To: {data.maxBorrowingPower.after.value.toDisplayString(2)}</p>
</div>
);
}
import { type SwapQuote, usePreviewAction } from "@aave/react";
// …
const [preview, { called, data, error, loading }] = usePreviewAction();
const handler = async (quote: SwapQuote) => {
const result = await preview({
action: {
supplySwap: {
fromQuote: {
quoteId: quote.quoteId,
},
},
},
});
if (result.isOk()) {
console.log(result.value); // PreviewUserPosition
} else {
console.error(result.error);
}
};
import { preview } from "@aave/client/actions";
import { client } from "./client";
// …
const result = await supplySwapQuote(client, request).andThen(
({ approvals, quote }) =>
preview(client, {
action: {
supplySwap: {
fromQuote: {
quoteId: quote.quoteId,
},
},
},
}),
);
if (result.isErr()) {
console.error(result.error);
return;
}
// result.value: PreviewUserPosition
query ($request: PreviewRequest!, $currency: Currency = USD) {
preview(request: $request) {
__typename
id
healthFactor {
...HealthFactorResult
}
netApy {
...PercentNumberVariation
}
riskPremium {
...PercentNumberVariation
}
netCollateral(currency: $currency) {
...ExchangeAmountVariation
}
netBalance(currency: $currency) {
...ExchangeAmountVariation
}
projectedEarnings {
...ExchangeAmountVariation
}
maxBorrowingPower {
...ExchangeAmountVariation
}
remainingBorrowingPower {
...ExchangeAmountVariation
}
otherConditions {
...UserPositionConditionVariation
}
}
}
In GraphQL, pass the quote in the supply field:
{
"request": {
"action": {
"supplySwap": {
"fromQuote": {
"quoteId": "<quote-id-from-step-1>"
}
}
}
},
"currency": "USD"
}
The Preview 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.
| Field | Impact |
|---|---|
health | Higher is better ( null if not applicable) |
risk | Lower is better |
net | Higher is better |
net | Higher is better |
net | Updated balance |
projected | Projected earnings |
max | Maximum borrowing power |
remaining | Remaining borrowing power |
other | 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 other field is an array of objects describing the resulting dynamic config changes.
Collateral– Collateral factor changeFactor Variation Liquidation– Liquidation fee changeFee Variation Max– Maximum liquidation bonus changeLiquidation Bonus Variation
3. Configure Wallet Integration
Then, in React, instantiate the hooks for the wallet library of your choice:
use: used to sign the approvals and the order typed dataSign Typed Data use: used to send the order transaction when the Order API returns oneSend Transaction
import { useWalletClient } from "wagmi";
import { useSendTransaction, useSignTypedData } from "@aave/react/viem";
// …
const { data: wallet } = useWalletClient();
const [sendTransaction] = useSendTransaction(wallet);
const [signTypedData] = useSignTypedData(wallet);
4. Define the Swap Flow
Then, in React, use the use hook to handle the operation. It fetches the quote, collects the approval signatures, and prepares, signs, and submits the order.
import { useSupplySwapOrder } from "@aave/react";
const [swapSupply, { loading, error }] = useSupplySwapOrder((plan) => {
switch (plan.__typename) {
case "PositionSwapAdapterContractApproval":
case "PositionSwapPositionManagerApproval":
case "PositionSwapSetCollateralApproval":
return signTypedData(plan.bySignature);
case "OrderTypedData":
return signTypedData(plan);
case "OrderTransactionRequest":
return sendTransaction(plan.transaction);
}
});
import { useState } from "react";
import { useSupplySwapOrder } from "@aave/react";
const [status, setStatus] = useState("");
const [swapSupply, { loading, error }] = useSupplySwapOrder((plan) => {
switch (plan.__typename) {
case "PositionSwapAdapterContractApproval":
setStatus("Sign the swap adapter approval in your wallet");
return signTypedData(plan.bySignature);
case "PositionSwapPositionManagerApproval":
setStatus("Sign the swap position manager approval in your wallet");
return signTypedData(plan.bySignature);
case "PositionSwapSetCollateralApproval":
setStatus("Sign the set collateral approval in your wallet");
return signTypedData(plan.bySignature);
case "OrderTypedData":
setStatus("Sign the swap order in your wallet");
return signTypedData(plan);
case "OrderTransactionRequest":
setStatus("Send the swap transaction in your wallet");
return sendTransaction(plan.transaction);
}
});
import { useSupplySwapOrder } from "@aave/react";
const [swapSupply, { loading, error }] = useSupplySwapOrder((plan, { cancel }) => {
if (window.confirm("Are you sure you want to continue?") === false) {
return cancel("User cancelled the operation");
}
switch (plan.__typename) {
case "PositionSwapAdapterContractApproval":
case "PositionSwapPositionManagerApproval":
case "PositionSwapSetCollateralApproval":
return signTypedData(plan.bySignature);
case "OrderTypedData":
return signTypedData(plan);
case "OrderTransactionRequest":
return sendTransaction(plan.transaction);
}
});
The operation involves up to 4 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.
- Set collateral approval: Enables the destination asset as collateral, needed only when it is not yet enabled as collateral.
- Swap order: The order typed data returned by
prepare, signed after the approvals.Order
5. Sign Approvals
In TypeScript, use sign for the wallet library of your choice to sign the swap approvals.
import {
type PositionSwapByIntentApprovalsRequired,
type PrepareOrderRequest,
type ResultAsync,
type SignTypedDataError,
okAsync,
} from "@aave/client";
import { signTypedDataWith } from "@aave/client/viem";
import { wallet } from "./wallet";
export function signApprovals({
approvals,
quote,
}: PositionSwapByIntentApprovalsRequired): ResultAsync<
PrepareOrderRequest,
SignTypedDataError
> {
return approvals.reduce(
(acc, approval) =>
acc.andThen((request) =>
signTypedDataWith(wallet, approval.bySignature).map((signature) => {
switch (approval.__typename) {
case "PositionSwapAdapterContractApproval":
return { ...request, adapterContractSignature: signature };
case "PositionSwapPositionManagerApproval":
return { ...request, positionManagerSignature: signature };
case "PositionSwapSetCollateralApproval":
return { ...request, setCollateralSignature: signature };
}
}),
),
okAsync<PrepareOrderRequest, SignTypedDataError>({
quoteId: quote.orderQuoteId,
adapterContractSignature: null,
positionManagerSignature: null,
setCollateralSignature: null,
}),
);
}
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(),
});
In GraphQL, handle the required approvals from the quote response before proceeding:
Position: Sign theSwap Adapter Contract Approval bytyped data to authorize the swap adapter contract.Signature Position: Either send theSwap Position Manager Approval byrequest or sign theTransaction bytyped data to authorize the position manager.Signature Position: Sign theSwap Set Collateral Approval bytyped data to enable the destination asset as collateral. Pass it asSignature setwhen preparing the order.Collateral Signature
6. Prepare the Order
- TypeScript: Use the
prepareaction to prepare the order.Order - GraphQL: Use the
preparequery with the quote’sOrder orderand the signed approvals.Quote Id
import { prepareOrder } from "@aave/client/actions";
import { signApprovals } from "./signApprovals";
// …
const result = await supplySwapQuote(client, request)
.andThen(signApprovals)
.andThen((request) => prepareOrder(client, request));
if (result.isErr()) {
console.error(result.error);
return;
}
// result.value: PreparedOrder
query ($request: PrepareOrderRequest!) {
prepareOrder(request: $request) {
__typename
... on PreparedOrder {
...PreparedOrder
}
... on InsufficientBalanceError {
...InsufficientBalanceError
}
}
}
fragment PreparedOrder on PreparedOrder {
__typename
newQuoteId
data {
...OrderTypedData
}
}
fragment OrderTypedData on OrderTypedData {
__typename
types
primaryType
domain {
...DomainData
}
message
}
With the order from the last quote response and the signed approvals, construct the request as follows:
{
"request": {
"quoteId": "<quote.orderQuoteId>",
"adapterContractSignature": "0x…",
"positionManagerSignature": "0x…",
"setCollateralSignature": "0x…"
}
}
{
"request": {
"quoteId": "<quote.orderQuoteId>",
"adapterContractSignature": "0x…"
}
}
{
"request": {
"quoteId": "<quote.orderQuoteId>"
}
}
If the response is a Prepared, sign the data typed data and submit the order. If it’s an Insufficient, inform the user about the insufficient balance.
7. Execute the Swap
Then, execute the swap for the given quote.
- TypeScript: Sign the order typed data and submit it with the
submitaction. If the response is anOrder Order, send the transaction withTransaction Request send.With - GraphQL: Use the
submitmutation with the new quote ID and the signed order from the previous step.Order
const execute = async (quote: SwapQuote) => {
const result = await swapSupply({
fromQuote: {
quoteId: quote.quoteId,
},
});
if (result.isErr()) {
console.error(result.error);
return;
}
// result.value: OrderReceipt
console.log("Swap order placed:", result.value.orderId);
};
import { okAsync } from "@aave/client";
import { prepareOrder, submitOrder, supplySwapQuote } from "@aave/client/actions";
import { sendWith, signTypedDataWith } from "@aave/client/viem";
import { client } from "./client";
import { signApprovals } from "./signApprovals";
import { wallet } from "./wallet";
const result = await supplySwapQuote(client, request)
.andThen(signApprovals)
.andThen((request) => prepareOrder(client, request))
.andThen(({ newQuoteId, data }) =>
signTypedDataWith(wallet, data).andThen((signature) =>
submitOrder(client, { bySignature: { quoteId: newQuoteId, signature } }),
),
)
.andThen((plan) => {
switch (plan.__typename) {
case "OrderTransactionRequest":
return sendWith(wallet, plan.transaction).map(() => plan.orderReceipt);
case "OrderReceipt":
return okAsync(plan);
}
});
// …
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(),
});
mutation ($request: SubmitOrderRequest!) {
submitOrder(request: $request) {
__typename
... on OrderTransactionRequest {
...OrderTransactionRequest
}
... on OrderReceipt {
...OrderReceipt
}
... on InsufficientBalanceError {
...InsufficientBalanceError
}
}
}
fragment OrderTransactionRequest on OrderTransactionRequest {
__typename
transaction {
...TransactionRequest
}
orderReceipt {
...OrderReceipt
}
}
fragment OrderReceipt on OrderReceipt {
__typename
orderId
}
In GraphQL, pass the new from the prepare response and the signed order as variables:
{
"request": {
"bySignature": {
"quoteId": "<prepareOrder.newQuoteId>",
"signature": "0x…"
}
}
}
8. Handle the Result
Finally, in React and TypeScript, handle the 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;
}
return;
}
// result.value: OrderReceipt
console.log("Swap order placed:", result.value.orderId);
// …
if (result.isErr()) {
console.error(result.error);
return;
}
// result.value: OrderReceipt
console.log("Swap order placed:", result.value.orderId);
In GraphQL, process the response based on the _:
Order: The order was placed. Use theReceipt orderto track its status.Id Order: Send theTransaction Request transactionrequest, then track the order usingorder.Receipt. order Id Insufficient: Inform the user about the insufficient balance.Balance Error
You placed your first supply swap order. Keep track of its status in the Monitor Swap Status section.