1
- import type {
1
+ import {
2
2
Connection ,
3
3
SendOptions ,
4
4
Transaction ,
5
5
TransactionInstruction ,
6
6
VersionedTransaction ,
7
7
PublicKey ,
8
8
AddressLookupTableAccount ,
9
+ RecentPrioritizationFees ,
9
10
} from '@solana/web3.js' ;
10
11
import {
11
12
ComputeBudgetProgram ,
@@ -380,6 +381,37 @@ export async function determineComputeBudget(
380
381
return computeBudget ;
381
382
}
382
383
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
+
383
415
/**
384
416
* A helper function to determine the priority fee to use for a transaction
385
417
*
@@ -405,31 +437,10 @@ export async function determinePriorityFee(
405
437
let fee = minPriorityFee ;
406
438
407
439
// 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
+ ) ;
433
444
434
445
try {
435
446
const recentFeesResponse = await connection . getRecentPrioritizationFees ( {
@@ -461,6 +472,80 @@ export async function determinePriorityFee(
461
472
return Math . min ( Math . max ( fee , minPriorityFee ) , maxPriorityFee ) ;
462
473
}
463
474
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
+
464
549
export class SolanaSigner < N extends Network , C extends SolanaChains = 'Solana' >
465
550
implements SignOnlySigner < N , C >
466
551
{
0 commit comments