Skip to main content

Tips to Improve Jupiter Swap Landing Rates on Solana

Updated on
Nov 20, 2024

Optimizing transactions on the Solana network is crucial for ensuring their inclusion in blocks, especially during periods of high network traffic. This is particularly necessary for swaps on Jupiter because the program experiences millions of successful transactions daily and its transactions require a relatively high level of compute. This document outlines key strategies for improving transaction performance and reliability for Jupiter swaps when using the Jupiter API or the Metis Jupiter V6 Swap API.

There are several strategies you can take to increase the likelihood of your transaction being included in a block and confirmed by the network quickly. These include:


Restrict Intermediate Tokens

When using Jupiter Swaps, you can restrict the intermediate tokens that are used to make the swap. This prevents swaps being routed through token pairs with low liquidity and high slippage, both of which can cause your transaction to fail.

To restrict intermediate tokens, set the restrictIntermediateTokens parameter to true when making the quote request. This will ensure that the swap is only made through token pairs that have a high liquidity and low slippage.

Example Use

curl -G "https://public.jupiterapi.com/quote" \
--data-urlencode "inputMint=So11111111111111111111111111111111111111112" \
--data-urlencode "outputMint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" \
--data-urlencode "amount=100000000" \
--data-urlencode "restrictIntermediateTokens=true"

Set Appropriate Slippage

When executing trades on decentralized exchanges (DEXs), slippage refers to the difference between the expected price and the actual executed price of your trade. A slippage check is performed on-chain to ensure that the trade is executed within the specified slippage tolerance, otherwise the transaction will fail.

Setting the right slippage tolerance is crucial:

  • Too high: Your transaction could be vulnerable to MEV attacks (e.g., setting 10% slippage on a stable pair like USDC/PYUSD could let arbitrage bots extract value from your trade)
  • Too low: Your transaction might fail to execute (e.g., setting 0.1% slippage on a volatile pair like SOL/NEWMEMECOIN may cause frequent failures during price movements) (you may get an 0x1771 error in your program logs when the slippage tolerance is exceeded)

Static Slippage

Slippage can be set when getting a quote using the quote or when creating a swap transaction using the swap method using theslippageBps parameter:

slippageBps (integer)
The basis point (BPS) value of the slippage tolerance. If the output token amount exceeds the slippage then the swap transaction will fail. 100 BPS is 1%.

Example Use

curl -G "https://public.jupiterapi.com/quote" \
--data-urlencode "inputMint=So11111111111111111111111111111111111111112" \
--data-urlencode "outputMint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" \
--data-urlencode "amount=100000000" \
--data-urlencode "restrictIntermediateTokens=true" \
--data-urlencode "slippageBps=20"

Dynamic Slippage

In addition to setting a slippage limit, Jupiter offers dynamic slippage calculation that automatically optimizes the slippage tolerance based on:

  • The specific token pair being traded
  • Current market volatility
  • Real-time market conditions

To enable dynamic slippage, include the dynamicSlippage parameter in your swap request:

curl --location 'https://public.jupiterapi.com/swap' \
--header 'Content-Type: application/json' \
--data '{
"userPublicKey": "USER_PUBLIC_KEY",
"dynamicSlippage": {
"minBps": 50,
"maxBps": 300
},
"quoteResponse": {
// ... response object from quote request
}
}'

The API will return a dynamicSlippageReport that includes:

FieldDescription
slippageBpsThe optimized slippage used in the serialized transaction
otherAmountThe actual amount received during simulation
simulatedIncurredSlippageBpsThe simulated slippage impact
amplificationRatioThe amplification ratio used to calculate the slippage

Dynamic slippage eliminates the need to manually adjust slippage settings and helps improve transaction success rates by automatically finding the optimal tolerance for each trade.


Slippage Risk

Be very careful setting or automating your slippage tolerance. Inadvertantly setting a slippage too high can result in irreversible loss of funds. Make sure you test your slippage settings thoroughly before deploying your application.

Competetive Priority Fees

Solana's fee priority system allows you to set an additional fee on top of the base fee for a transaction, which gives your transaction a higher priority in the leader's queue. By bidding more for priority status, your transaction will be more likely to be confirmed quickly by the network.

There are several ways to set a priority fee using the Jupiter API:

  1. Auto generate a priority fee instruction using the swap method.
  2. Generate a priority fee instruction with custom parameters using the swap method.
  3. Specify a priority fee amount in the swap method.

Auto-Generate Priority Fee Instruction

The swap method can automatically generate a priority fee instruction for you. To do this, simply include the prioritizationFeeLamports parameter in your swap request:

curl --location 'https://public.jupiterapi.com/swap' \
--header 'Content-Type: application/json' \
--data '{
"userPublicKey": "USER_PUBLIC_KEY",
"prioritizationFeeLamports": "auto",
"quoteResponse": {
// ... response object from quote request
}
}'

If 'auto' is used, Jupiter will automatically set a priority fee for the transaction, it will be capped at 5,000,000 lamports / 0.005 SOL.

Generate Priority Fee Instruction with Custom Parameters

If you would like more control over how Jupiter estimates you can pass in a priorityLevelWithMaxLamports to the prioritizationFeeLamports parameter. You can specify:

  • maxLamports value to cap the priority fee at a specific amount of lamports,
  • global (boolean) to indicate whether the fee is calculated globally across the Solana network or based on the local fee market for relevant programs,
  • priorityLevel to indicate the level of priority fee to use (medium, high, or veryHigh).
curl --location 'https://public.jupiterapi.com/swap' \
--header 'Content-Type: application/json' \
--data '{
"userPublicKey": "USER_PUBLIC_KEY",
"prioritizationFeeLamports": {
"priorityLevelWithMaxLamports": {
"maxLamports": 4000000,
"global": false,
"priorityLevel": "veryHigh"
}
},
"quoteResponse": {
// ... response object from quote request
}
}'

Specifying a Priority Fee Amount

Alternatively you can specify a specific priority fee amount in lamports, for example:

curl --location 'https://public.jupiterapi.com/swap' \
--header 'Content-Type: application/json' \
--data '{
"userPublicKey": "USER_PUBLIC_KEY",
"prioritizationFeeLamports": 1000000,
"quoteResponse": {
// ... response object from quote request
}
}'
Calculating the Right Priority Fee

QuickNode provides a Priority Fee API (Add-on Details | Docs) to fetch recent priority fees for a given Program over a specified number of blocks.

curl https://docs-demo.solana-mainnet.quiknode.pro/ \
-X POST \
-H "Content-Type: application/json" \
-H "x-qn-api-version: 1" \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "qn_estimatePriorityFees",
"params": {
"last_n_blocks": 100,
"account": "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4",
"api_version": 2
}
}'

The method returns an object with a per_compute_unit property that includes estimates for priority fees (in microlamports) based on recent network activity. The response provides fee estimates in four categories: low, medium, high, and extreme.


Priority Fees During High Traffic Periods

During periods of high network congestion, to increase the likelihood of successful transaction processing, we recommend using the 80th percentile or higher of recent priority fees. This corresponds to either the high or extreme priority fees returned by the qn_estimatePriorityFees method.

Priority Fees Resources

Compute Unit Optimization

Optimizing compute units (CU) helps prevent transactions from being dropped due to exceeding block limits. Every transaction on Solana uses CU to process. The network has a limit on the number of compute units that can be processed in a single block. Jupiter swaps involve multiple Cross Program Invocations to other Solana programs, often resulting in a large number of CUs. For for information on Compute Units, check out our Docs.

To ensure your swap transaction is created with an optimal compute unit limit, you can set the dynamicComputeUnitLimit parameter to true when making the swap request:

curl --location 'https://public.jupiterapi.com/swap' \
--header 'Content-Type: application/json' \
--data '{
"userPublicKey": "USER_PUBLIC_KEY",
"dynamicComputeUnitLimit": "true",
"quoteResponse": {
// ... response object from quote request
}
}'

This will ensure the returned transaction includes a computeBudgetInstruction that sets the compute unit limit to the appropriate value based on the copmlexity of the swap (instead of using the maxiumum value of 1,400,000 compute units).

Transaction Assembly & Broadcasting

The Jupiter API returns a simulated transacion, so you can skip preflight checks by setting the skipPreflight parameter to true when sending the transaction:

const swapTransactionBuf = Buffer.from(swapTransaction, 'base64');
let transaction = VersionedTransaction.deserialize(swapTransactionBuf);
transaction.sign([wallet.payer]);
const rawTransaction = transaction.serialize()
const signature = await connection.sendRawTransaction(rawTransaction, {
skipPreflight: true,
});

Create a simple polling function using getSignatureStatuses to check on the status of your transaction.

const { value: statuses } = await connection.getSignatureStatuses([signature]);

If it is not confirmed after 150 slots (about 60 seconds), your blockhash will expire, and you can retry the transaction.

Jito Bundles

Alternatively, you send transactions to the Solana cluster using Jito Bundles. Jito Bundles are a feature provided by Jito Labs that enables sequential and atomic execution of multiple transactions on the Solana blockchain. Check out our Guide: What are Jito Bundles and How to Use Them? for more information. The TLDR is that:

  • you must append a tip to the validator in the last transaction of your bundle to ensure it is processed successfully, and
  • you must send the transaction using a Jito-enabled Solana endpoint -- you can get one by signing up for Lil' JIT Marketplace Add-on.

You can append a tip to the validator using the prioritizationFeeLamports parameter in the swap method:

curl --location 'https://public.jupiterapi.com/swap' \
--header 'Content-Type: application/json' \
--data '{
"userPublicKey": "USER_PUBLIC_KEY",
"prioritizationFeeLamports": {
"jitoTipLamports": 1000000,
},
"quoteResponse": {
// ... response object from quote request
}
}'

You can then send the transaction using Jito sendTransaction or sendBundle methods. Check out our Guide on Jito Bundles or Code Example (Jupiter Swaps with Jito Bundles) for more information.

We ❤️ Feedback!

If you have any feedback or questions about this documentation, let us know. We'd love to hear from you!

Share this doc