@@ -14,6 +14,7 @@ import {
14
14
import { SearcherClient } from "jito-ts/dist/sdk/block-engine/searcher" ;
15
15
import { sliceAccumulatorUpdateData } from "@pythnetwork/price-service-sdk" ;
16
16
import { Logger } from "pino" ;
17
+ import { LAMPORTS_PER_SOL } from "@solana/web3.js" ;
17
18
18
19
const HEALTH_CHECK_TIMEOUT_SECONDS = 60 ;
19
20
@@ -34,21 +35,24 @@ export class SolanaPriceListener extends ChainPriceListener {
34
35
// and ensuring it is not older than 30 seconds.
35
36
private async checkHealth ( ) {
36
37
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
+ }
50
53
}
51
- throw new Error ( "Solana connection is unhealthy" ) ;
54
+ } catch ( err ) {
55
+ this . logger . error ( { err } , "checkHealth failed" ) ;
52
56
}
53
57
}
54
58
@@ -155,17 +159,48 @@ export class SolanaPricePusherJito implements IPricePusher {
155
159
private priceServiceConnection : PriceServiceConnection ,
156
160
private logger : Logger ,
157
161
private shardId : number ,
158
- private jitoTipLamports : number ,
162
+ private defaultJitoTipLamports : number ,
163
+ private dynamicJitoTips : boolean ,
164
+ private maxJitoTipLamports : number ,
159
165
private searcherClient : SearcherClient ,
160
166
private jitoBundleSize : number ,
161
167
private updatesPerJitoBundle : number
162
168
) { }
163
169
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
+
164
192
async updatePriceFeed (
165
193
priceIds : string [ ] ,
166
194
// eslint-disable-next-line @typescript-eslint/no-unused-vars
167
195
_pubTimesToPush : number [ ]
168
196
) : 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
+
169
204
let priceFeedUpdateData : string [ ] ;
170
205
try {
171
206
priceFeedUpdateData = await this . priceServiceConnection . getLatestVaas (
@@ -192,7 +227,7 @@ export class SolanaPricePusherJito implements IPricePusher {
192
227
) ;
193
228
194
229
const transactions = await transactionBuilder . buildVersionedTransactions ( {
195
- jitoTipLamports : this . jitoTipLamports ,
230
+ jitoTipLamports : cappedJitoTip ,
196
231
tightComputeBudget : true ,
197
232
jitoBundleSize : this . jitoBundleSize ,
198
233
} ) ;
0 commit comments