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
- Set appropriate slippage
- Competetive priority fees
- Optimize compute units
- Transaction assembly & broadcasting
- Consider using Jito Bundles for complex, multi-transaction operations
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:
Field | Description |
---|---|
slippageBps | The optimized slippage used in the serialized transaction |
otherAmount | The actual amount received during simulation |
simulatedIncurredSlippageBps | The simulated slippage impact |
amplificationRatio | The 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.
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:
- Auto generate a priority fee instruction using the
swap
method. - Generate a priority fee instruction with custom parameters using the
swap
method. - 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
, orveryHigh
).
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
.
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
- How to Use Priority Fees on Solana
- Solana Priority Fees Add-on
- Priority Fees Add-on Documentation
- Sample Code - Solana Web3.js 2.0
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.
- Sample Confirm Transaction Polling Function
- Guide: Solana Transaction Propagation - Handling Dropped Transactions
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.
Recommended Reading
- Solana Docs: Strategies to Optimize Solana Transactions
- Guide: What are Jito Bundles and How to Use Them?
- Guide: Create a Jupiter Trading Bot
- Sample Code: Jupiter Swaps with Jito Bundles
- JupiterAPI.com Public Endpoints
- Metis Metis Jupiter V6 Swap API - Marketplace Add-on
- Lil' JIT Marketplace Add-on
- Solana Priority Fees Add-on
- Jupiter Station
We ❤️ Feedback!
If you have any feedback or questions about this documentation, let us know. We'd love to hear from you!