Skip to content

Commit db1e55b

Browse files
committed
Added Triton One improved priority fee API support
Added determinePriorityFeeTritonOne function
1 parent 5943b6b commit db1e55b

File tree

1 file changed

+111
-26
lines changed

1 file changed

+111
-26
lines changed

platforms/solana/src/signer.ts

+111-26
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import type {
1+
import {
22
Connection,
33
SendOptions,
44
Transaction,
55
TransactionInstruction,
66
VersionedTransaction,
77
PublicKey,
88
AddressLookupTableAccount,
9+
RecentPrioritizationFees,
910
} from '@solana/web3.js';
1011
import {
1112
ComputeBudgetProgram,
@@ -380,6 +381,37 @@ export async function determineComputeBudget(
380381
return computeBudget;
381382
}
382383

384+
// Helper function to get the writable accounts from a transaction
385+
export async function getWritableAccounts(
386+
connection: Connection,
387+
transaction: Transaction | VersionedTransaction,
388+
): Promise<PublicKey[]> {
389+
if (isVersionedTransaction(transaction)) {
390+
const luts = (
391+
await Promise.all(
392+
transaction.message.addressTableLookups.map((acc) =>
393+
connection.getAddressLookupTable(acc.accountKey),
394+
),
395+
)
396+
)
397+
.map((lut) => lut.value)
398+
.filter((val) => val !== null) as AddressLookupTableAccount[];
399+
const msg = transaction.message;
400+
const keys = msg.getAccountKeys({
401+
addressLookupTableAccounts: luts ?? undefined,
402+
});
403+
return msg.compiledInstructions
404+
.flatMap((ix) => ix.accountKeyIndexes)
405+
.map((k) => (msg.isAccountWritable(k) ? keys.get(k) : null))
406+
.filter((k) => !!k) as PublicKey[];
407+
} else {
408+
return transaction.instructions
409+
.flatMap((ix) => ix.keys)
410+
.map((k) => (k.isWritable ? k.pubkey : null))
411+
.filter((k) => !!k) as PublicKey[];
412+
}
413+
}
414+
383415
/**
384416
* A helper function to determine the priority fee to use for a transaction
385417
*
@@ -405,31 +437,10 @@ export async function determinePriorityFee(
405437
let fee = minPriorityFee;
406438

407439
// Figure out which accounts need write lock
408-
let lockedWritableAccounts = [];
409-
if (isVersionedTransaction(transaction)) {
410-
const luts = (
411-
await Promise.all(
412-
transaction.message.addressTableLookups.map((acc) =>
413-
connection.getAddressLookupTable(acc.accountKey),
414-
),
415-
)
416-
)
417-
.map((lut) => lut.value)
418-
.filter((val) => val !== null) as AddressLookupTableAccount[];
419-
const msg = transaction.message;
420-
const keys = msg.getAccountKeys({
421-
addressLookupTableAccounts: luts ?? undefined,
422-
});
423-
lockedWritableAccounts = msg.compiledInstructions
424-
.flatMap((ix) => ix.accountKeyIndexes)
425-
.map((k) => (msg.isAccountWritable(k) ? keys.get(k) : null))
426-
.filter((k) => k !== null) as PublicKey[];
427-
} else {
428-
lockedWritableAccounts = transaction.instructions
429-
.flatMap((ix) => ix.keys)
430-
.map((k) => (k.isWritable ? k.pubkey : null))
431-
.filter((k) => k !== null) as PublicKey[];
432-
}
440+
const lockedWritableAccounts = await getWritableAccounts(
441+
connection,
442+
transaction,
443+
);
433444

434445
try {
435446
const recentFeesResponse = await connection.getRecentPrioritizationFees({
@@ -461,6 +472,80 @@ export async function determinePriorityFee(
461472
return Math.min(Math.max(fee, minPriorityFee), maxPriorityFee);
462473
}
463474

475+
interface RpcResponse {
476+
jsonrpc: String;
477+
id?: String;
478+
result?: [];
479+
error?: any;
480+
}
481+
482+
// Helper function to calculate the priority fee using the Triton One API
483+
// See https://docs.triton.one/chains/solana/improved-priority-fees-api
484+
export async function determinePriorityFeeTritonOne(
485+
connection: Connection,
486+
transaction: Transaction | VersionedTransaction,
487+
percentile: number = DEFAULT_PRIORITY_FEE_PERCENTILE,
488+
multiple: number = DEFAULT_PERCENTILE_MULTIPLE,
489+
minPriorityFee: number = DEFAULT_MIN_PRIORITY_FEE,
490+
maxPriorityFee: number = DEFAULT_MAX_PRIORITY_FEE,
491+
): Promise<number> {
492+
// Start with min fee
493+
let fee = minPriorityFee;
494+
495+
// @ts-ignore
496+
const rpcRequest = connection._rpcRequest;
497+
498+
const accounts = await getWritableAccounts(connection, transaction);
499+
500+
const args = [
501+
accounts,
502+
{
503+
percentile: percentile * 10_000, // between 1 and 10_000
504+
},
505+
];
506+
507+
try {
508+
const response = (await rpcRequest(
509+
'getRecentPrioritizationFees',
510+
args,
511+
)) as RpcResponse;
512+
513+
if (response.error) {
514+
throw new Error(response.error);
515+
}
516+
517+
const recentPrioritizationFees =
518+
response.result as RecentPrioritizationFees[];
519+
520+
if (recentPrioritizationFees.length > 0) {
521+
const sortedFees = recentPrioritizationFees.sort(
522+
(a, b) => a.prioritizationFee - b.prioritizationFee,
523+
);
524+
525+
// Calculate the median
526+
const half = Math.floor(sortedFees.length / 2);
527+
if (sortedFees.length % 2 === 0) {
528+
fee = Math.floor(
529+
(sortedFees[half - 1]!.prioritizationFee +
530+
sortedFees[half]!.prioritizationFee) /
531+
2,
532+
);
533+
} else {
534+
fee = sortedFees[half]!.prioritizationFee;
535+
}
536+
537+
if (multiple > 0) {
538+
fee *= multiple;
539+
}
540+
}
541+
} catch (e) {
542+
console.error('Error fetching Triton One Solana recent fees', e);
543+
}
544+
545+
// Bound the return value by the parameters passed
546+
return Math.min(Math.max(fee, minPriorityFee), maxPriorityFee);
547+
}
548+
464549
export class SolanaSigner<N extends Network, C extends SolanaChains = 'Solana'>
465550
implements SignOnlySigner<N, C>
466551
{

0 commit comments

Comments
 (0)