@@ -14,6 +14,7 @@ import {
1414import { SearcherClient } from "jito-ts/dist/sdk/block-engine/searcher" ;
1515import { sliceAccumulatorUpdateData } from "@pythnetwork/price-service-sdk" ;
1616import { Logger } from "pino" ;
17+ import { LAMPORTS_PER_SOL } from "@solana/web3.js" ;
1718
1819const HEALTH_CHECK_TIMEOUT_SECONDS = 60 ;
1920
@@ -34,21 +35,24 @@ export class SolanaPriceListener extends ChainPriceListener {
3435 // and ensuring it is not older than 30 seconds.
3536 private async checkHealth ( ) {
3637 const slot = await this . pythSolanaReceiver . connection . getSlot ( "finalized" ) ;
37- const blockTime = await this . pythSolanaReceiver . connection . getBlockTime (
38- slot
39- ) ;
40- if (
41- blockTime === null ||
42- blockTime < Date . now ( ) / 1000 - HEALTH_CHECK_TIMEOUT_SECONDS
43- ) {
44- if ( blockTime !== null ) {
45- this . logger . info (
46- `Solana connection is behind by ${
47- Date . now ( ) / 1000 - blockTime
48- } seconds`
49- ) ;
38+ try {
39+ const blockTime = await this . pythSolanaReceiver . connection . getBlockTime (
40+ slot
41+ ) ;
42+ if (
43+ blockTime === null ||
44+ blockTime < Date . now ( ) / 1000 - HEALTH_CHECK_TIMEOUT_SECONDS
45+ ) {
46+ if ( blockTime !== null ) {
47+ this . logger . info (
48+ `Solana connection is behind by ${
49+ Date . now ( ) / 1000 - blockTime
50+ } seconds`
51+ ) ;
52+ }
5053 }
51- throw new Error ( "Solana connection is unhealthy" ) ;
54+ } catch ( err ) {
55+ this . logger . error ( { err } , "checkHealth failed" ) ;
5256 }
5357 }
5458
@@ -155,17 +159,48 @@ export class SolanaPricePusherJito implements IPricePusher {
155159 private priceServiceConnection : PriceServiceConnection ,
156160 private logger : Logger ,
157161 private shardId : number ,
158- private jitoTipLamports : number ,
162+ private defaultJitoTipLamports : number ,
163+ private dynamicJitoTips : boolean ,
164+ private maxJitoTipLamports : number ,
159165 private searcherClient : SearcherClient ,
160166 private jitoBundleSize : number ,
161167 private updatesPerJitoBundle : number
162168 ) { }
163169
170+ async getRecentJitoTipLamports ( ) : Promise < number | undefined > {
171+ try {
172+ const response = await fetch (
173+ "http://bundles-api-rest.jito.wtf/api/v1/bundles/tip_floor"
174+ ) ;
175+ if ( ! response . ok ) {
176+ this . logger . error (
177+ { status : response . status , statusText : response . statusText } ,
178+ "getRecentJitoTips http request failed"
179+ ) ;
180+ return undefined ;
181+ }
182+ const data = await response . json ( ) ;
183+ return Math . floor (
184+ Number ( data [ 0 ] . landed_tips_25th_percentile ) * LAMPORTS_PER_SOL
185+ ) ;
186+ } catch ( err : any ) {
187+ this . logger . error ( { err } , "getRecentJitoTips failed" ) ;
188+ return undefined ;
189+ }
190+ }
191+
164192 async updatePriceFeed (
165193 priceIds : string [ ] ,
166194 // eslint-disable-next-line @typescript-eslint/no-unused-vars
167195 _pubTimesToPush : number [ ]
168196 ) : Promise < void > {
197+ const jitoTip = this . dynamicJitoTips
198+ ? ( await this . getRecentJitoTipLamports ( ) ) ?? this . defaultJitoTipLamports
199+ : this . defaultJitoTipLamports ;
200+
201+ const cappedJitoTip = Math . min ( jitoTip , this . maxJitoTipLamports ) ;
202+ this . logger . info ( { cappedJitoTip } , "using jito tip of" ) ;
203+
169204 let priceFeedUpdateData : string [ ] ;
170205 try {
171206 priceFeedUpdateData = await this . priceServiceConnection . getLatestVaas (
@@ -192,7 +227,7 @@ export class SolanaPricePusherJito implements IPricePusher {
192227 ) ;
193228
194229 const transactions = await transactionBuilder . buildVersionedTransactions ( {
195- jitoTipLamports : this . jitoTipLamports ,
230+ jitoTipLamports : cappedJitoTip ,
196231 tightComputeBudget : true ,
197232 jitoBundleSize : this . jitoBundleSize ,
198233 } ) ;
0 commit comments