The idea is that the compute limit and compute limit price are instructions. And from the Jupiter API we already get a transactions object. Thus we have to add these priority fee instructions to the existing instructions of the transaction. The method I use for this is that I deconstruct the raw transaction object and rebuild it with the priority fee instructions added to it.
It is important to note that the priority fee instruction should normally be the first instruction thats executed thats why ix is set such that the priority fee instruction comes before the swapping instruction. Also the way I set up the priorityInstruction is that the program_id_index tells the instructions which address is associated to it in the account keys (in this case ComputeBudget111111111111111111111111111111) which is appended to the end of the accountKeys list, thus the index for this element in account keys is the length of the list itself.
rawTransaction=VersionedTransaction.from_bytes(base64.b64decode(apiTransaction))
priorityFee = set_compute_unit_price(gas)
accountKeys = rawTransaction.message.account_keys
lengthAccountKeys = len(accountKeys)
accountKeys.append(priorityFee.program_id)
rawInstructions = rawTransaction.message.instructions
priorityInstruction = CompiledInstruction(
program_id_index=lengthAccountKeys,
data=priorityFee.data,
accounts=rawInstructions[0].accounts,
)
ix = [priorityInstruction, *rawInstructions]
newTransactionMessage = Message.new_with_compiled_instructions(
num_required_signatures=rawTransaction.message.header.num_required_signatures,
num_readonly_signed_accounts=rawTransaction.message.header.num_readonly_signed_accounts,
num_readonly_unsigned_accounts=rawTransaction.message.header.num_readonly_unsigned_accounts,
account_keys=accountKeys,
recent_blockhash=recentBlockhash,
instructions=ix,
)
userSignature = userKeypair.sign_message(message.to_bytes_versioned(newTransactionMessage))
In response to comments
No, when inputting the priority fees you want to use into the API
request on Jupiter, that will be the amount you spend for the
priority fees in total. When adding the priority fees "manually" as
an instruction you should be aware of difference between the compute
unit price and compute unit limit. Lets first talk about what a
"compute unit" is. A compute unit is kind of a measurement of how
much computation you need in order to process your instructions. A
single Solana transaction can have multiple instructions (luckily
Jupiter transactions are normally only a single big instruction).
By default, each instruction within a transaction has a compute unit
limit of 200,000. This can be changed (to a max of 1.4M) using the
set_compute_unit_limit(). But beware that a higher compute unit
limit can decrease the chance that your transaction will be included
on chain, since it takes more computation for a validator to process
it.
In the Jupiter API request in your question the param
"dynamicComputeUnitLimit" is set to True. This parameter will
basically simulate the transaction and then use
set_compute_unit_limit() to set the compute unit of your transaction
to an appropriate amount, whereas if that was false it would be set
to 1,400,000, this a default value set by Jupiter. (If you are creating a transaction and its instructions from scratch it could be a good idea to use the same method as Jupiter does where you simulate the transaction and then use that as a ballpark as to how much your compute unit limit should be, but in the scope of using Jupiter just leave that param to True).
The compute unit price is the price (in lamports) you are paying to
the validator per unit of computation.
For example, if you send a transaction with a single instruction,
which has a compute unit limit of 200,000 and you set your compute
unit price to 2.8 lamports per unit. Then you will end up paying a
priority fee of 560000 lamports which is (560000 * 10^(-9) =)
0.00056 SOL.
No, it only sets the price you are going to pay per compute unit.
The function is defined in the solders python library.
Remember that if you're using the Jupiter API and you are using the
"prioritizationFeeLamports" param in your API request then there is
no reason to change the compute unit price, since this is already
done by Jupiter. Jupiter will automatically calculate how much you
need to pay per compute unit in order for the priority fee to be the
amount you specified. Thus the transaction already has the compute
unit price instruction present and there is no reason to add it
again.
If you want to add it to a transaction which doesnt have it, follow
the steps I mentioned in my initial answer, where you need to add
the instruction manually.
Also Solana is having a lot of congestion recently and some
transactions do fail more often than others. Maybe try setting a
higher priority fee.