All transactions on Solana use Compute Units (CU), which measure the computational resources your transaction uses on the network. When you pay priority fees on your transactions, you must specify the exact amount of compute units you expect to use; otherwise, you will overpay for your transaction. This guide will provide step-by-step instructions on optimizing the compute units for your transaction requests.
How to Request Compute Budget #
For precise control over your transaction's computational resources, use the
setComputeUnitLimit
instruction from the Compute Budget program. This
instruction allocates a specific number of compute units for your transaction,
ensuring you only pay for what you need.
// import { ComputeBudgetProgram } from "@solana/web3.js"
const modifyComputeUnits = ComputeBudgetProgram.setComputeUnitLimit({
units: 300,
});
This instruction will allocate a specific amount of compute units for your transaction. How do we come up with the number to use?
The simulateTransaction RPC method will return the estimated compute units consumed given a transaction.
The
Solana helpers npm package
includes
getSimulationComputeUnits
,
a small function that uses simulateTransaction
to calculate the compute units.
You can then set the compute units in your new transaction, and send the new
transaction for an optimal result.
npm i @solana-developers/helpers
The syntax is simply:
getSimulationComputeUnits(
connection: Connection,
instructions: Array<TransactionInstruction>,
payer: PublicKey,
lookupTables: Array<AddressLookupTableAccount>
);
For example:
const units = await getSimulationComputeUnits(
connection,
transactions,
payer.publicKey,
);
Using getSimulationComputeUnits
, you can build an optimal transaction that use
an appropriate amount of compute units for what the transaction consumes:
// import { ... } from "@solana/web3.js"
async function buildOptimalTransaction(
connection: Connection,
instructions: Array<TransactionInstruction>,
signer: Signer,
lookupTables: Array<AddressLookupTableAccount>,
) {
const [microLamports, units, recentBlockhash] = await Promise.all([
100 /* Get optimal priority fees - https://solana.com/developers/guides/advanced/how-to-use-priority-fees*/,
getSimulationComputeUnits(
connection,
instructions,
signer.publicKey,
lookupTables,
),
connection.getLatestBlockhash(),
]);
instructions.unshift(
ComputeBudgetProgram.setComputeUnitPrice({ microLamports }),
);
if (units) {
// probably should add some margin of error to units
instructions.unshift(ComputeBudgetProgram.setComputeUnitLimit({ units }));
}
return {
transaction: new VersionedTransaction(
new TransactionMessage({
instructions,
recentBlockhash: recentBlockhash.blockhash,
payerKey: signer.publicKey,
}).compileToV0Message(lookupTables),
),
recentBlockhash,
};
}
Credit to Sammmmmy, aka @stegaBOB, for the source code of these two functions.
Special Considerations #
Compute units for transactions are not always stable. For example, the compute
usage can change if the transaction you are executing has a call to
find_program_address
, such as when finding a program derived address.
If you have a variable compute usage on your transactions, you can do one of two things:
-
Run a test over your transactions over some time to find out the ceiling compute unit usage and use that number.
-
Take the compute units returned from
simulateTransaction
and add a percentage to the total. For example, if you chose to add 10% more CU and the result you received fromsimulateTransaction
was 1000 CU, you would set 1100 CU on your transaction.
Conclusion #
Requesting the optimal compute units for your transaction is essential to help you pay less for your transaction and to help schedule your transaction better on the network. Wallets, dApps, and other services should ensure their compute unit requests are optimal to provide the best experience possible for their users.
More Resources #
You can learn more about the Compute Budget and related topics with these resources:
- documentation for the Compute Budget
- Guide on how to use priority fees
- Guide on how to optimize compute units in programs