In solana, generally there're three types of fees -
- Rental fees
- Transaction fees
- Prioritization fees
The first one is related to storage space rental when new accounts are created on the network. The later twos are related to the transactions and we will focus on the transactions here.
Total fees required to submit transaction to the network can be calculated by combination of Base Fees (and optionally Prioritization fees).
By default, solana networks (and validators) only charge fixed Base Fees for a transaction. Base Fee is usually the cost to verify signature and has fixed amount of 5000 lamports per signature. In other words, without any extra configuration, users only need to pay signature validation fees for transactions. For example,
- for a simple SOL transfer, the sender only needs to pay fixed amount of
0.000005
SOL as transaction fee for the sender's signature regardless of the network traffic and amounts. - for
AccountCreation
, the transaction is needed to be signed by both new account and the fee payer. So, the total transaction cost will be2 signatures * 5k lamports = 10k lamports
. - Optionally, you can run the these scripts (
src/1.createAccount.ts
andsrc/2.transaction.ts
) to inspect tx costs
However, in the recent proposal for the complex transactions (such as precompiled program instructions
) will be charged as base fees due to the high computation costs.
Base fees are charged upfront before any computation and hence they do not have any influence on the Computation costs on chain and validators' transaction scheduling decisions.
Optionally, we can check this script
src/3.priorityFees.ts
to inspect how prioritization fee works and affects on the transaction on chain.
Transactions can be boosted and increase the guarantee of successful landings on chain by setting Prioritization Fees
. Transactions with higher priority fees are more likely to be included on chain, compared to the transactions with based fees. Users can send transactions only with the Base Fees but when blocks are saturated with transactions with priority fees, validators will drop transactions without priority fees. Prioritization fees are highly dependable on the Compute Units required to execute the transaction.
Prioritization fees are set upon each compute unit and can be set by modifying ComputeUnitPrice
value in ComputeBudget
program. By default, ComputeUnitPrice
is zero. The calculated prioritization fees are added on top of the Base Fees to form the final fee.
All the operations on chain require certain amount of computation resources and Validators are responsible to execute those operations using their computation resources. Depending on each operation in Instructions within a transaction, the computation unit may differ.
In solana, each transaction has default value of 200K Compute Units
per transaction. This can be modified by setting ComputeUnitLimit
in ComputeBudget
program. The maximum value of ComputeUnitLimit
for a transaction is 1.4 million CUs
and 200K CUs
for an instruction respectively.
As a transaction is processed, compute units are incrementally consumed by each of its instructions being executed and will result in failure when consumed units exceed the ComputeUnitLimit
.
Prioritization fees can be computed by ComputeUnitPrice * ComputeUnitLimit
and is later added to the Base Fee.
Final fee => (ComputeUnitPrice * ComputeUnitLimit) + (5K lamports * No.of.Signature used)
.
Actual consumed units must be always less than or equal ComputeUnitLimit
, otherwise transaction will fail. Most of the time the actual Compute Units consumed by transaction is way less than the default ComputeUnitLimit(200K CU)
. Please run this script to view in action how much actual Compute Units consumed by a normal transaction is less than default ComputeUnitLimit
.
Users need to pay for the requested
ComputeUnitLimit
, instead of actual consumedComputeUnit
, so it's important to set the optimal value forComputeUnitLimit
. E.g, A simple transaction which transfer SOL, only consumes150 CU
for the whole operation, however with the defaultComputeUnitLimit
, (assumingComputeUnitPrice
is set to 1 lamport) user will have to pay1 * 200_000 + 5000 = 205_000 lamports
instead of1 * 150 + 5000 = 5_150 lamports
.
Over requesting the ComputeUnitLimit
doesn't mean that the transaction will have higher priority in scheduling. When two transactions have the same ComputeUnitPrice
value, the transaction with less ComputeUnitLimit
has higher priority to be included in the block (solana-labs/solana#34888). In another word, transaction with less ComputeUnitLimit
are more likely to be included in currently processing thread in the validator.
Therefore, setting optimal ComputeUnitLimit
is not only cost effective but also have higher chance of success.
Some of the program instructions (e.g. SystemProgram and ComputeBudget Program) have fixed amount of Compute Unit
. As a transaction gets complicated with variable Compute Unit
amounts, it's difficult to calculate the minimal ComputeUnitLimit
required to submit the transaction.
However, with the help of transaction simulation, we can compute the exact amount of ComputeUnitLimit
required for a transaction which relatively reduces the transaction costs and increases the higher guarantee of landings on chain.