1414import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate" ;
1515import { DirectSecp256k1HdWallet , DirectSecp256k1Wallet , type OfflineDirectSigner } from "@cosmjs/proto-signing" ;
1616import { GasPrice } from "@cosmjs/stargate" ;
17- import { priceUpdateCounter , priceStaleness } from "./metrics.ts" ;
17+ import { priceUpdateCounter , blockchainPriceStaleness } from "./metrics.ts" ;
1818import { latestValue } from "./price-stream/latest-value/latest-value.ts" ;
1919import { PriceUpdateConfirmed } from "./price-update/price-update-confirmed/price-update-confirmed.ts" ;
2020import type { Logger , PriceProducerFactory , PriceUpdate , PriceUpdater , PythPriceData } from "./types.ts" ;
@@ -153,23 +153,6 @@ interface OracleParamsResponse {
153153
154154const DEFAULT_PRICE_DEVIATION_TOLERANCE : Required < HermesConfig > [ "priceDeviationTolerance" ] = { type : "absolute" , value : 0 } ;
155155
156- export type ErrorCode = "insufficient_balance" | "timeout" | "connection_issue" | "unknown" ;
157-
158- export function classifyError ( error : unknown ) : ErrorCode {
159- const message = error instanceof Error ? error . message : "" ;
160-
161- if ( / i n s u f f i c i e n t f u n d s | i n s u f f i c i e n t f e e / i. test ( message ) ) {
162- return "insufficient_balance" ;
163- }
164- if ( / t i m e o u t | E T I M E D O U T / i. test ( message ) ) {
165- return "timeout" ;
166- }
167- if ( / E C O N N R E F U S E D | E C O N N R E S E T | E N O T F O U N D / i. test ( message ) ) {
168- return "connection_issue" ;
169- }
170- return "unknown" ;
171- }
172-
173156export class HermesClient {
174157 #cosmClient?: SigningCosmWasmClient ;
175158 #wallet?: OfflineDirectSigner ;
@@ -434,14 +417,21 @@ export class HermesClient {
434417 throw new Error ( "Client not initialized" ) ;
435418 }
436419
420+ if ( this . #insufficientBalanceCooldownUntil !== null ) {
421+ if ( Date . now ( ) < this . #insufficientBalanceCooldownUntil) {
422+ this . #logger. warn ( "Skipping price update: insufficient balance cooldown active" ) ;
423+ return ;
424+ }
425+ this . #logger. log ( "Insufficient balance cooldown expired, retrying..." ) ;
426+ }
427+
437428 const startTime = performance . now ( ) ;
438429
439430 try {
440431 const currentPrice = await this . queryCurrentPrice ( ) ;
441432
442- // Record staleness: how far behind on-chain is from Pyth
443433 const staleness = priceUpdate . priceData . price . publish_time - currentPrice . publish_time ;
444- priceStaleness . record ( staleness ) ;
434+ blockchainPriceStaleness . record ( staleness ) ;
445435
446436 if ( this . #canIgnorePriceUpdate( priceUpdate . priceData , currentPrice ) ) {
447437 priceUpdateCounter . add ( 1 , { result : "skipped" } ) ;
@@ -450,7 +440,6 @@ export class HermesClient {
450440
451441 const config = await this . queryConfig ( ) ;
452442
453- // Execute update
454443 this . #logger. log ( "Submitting VAA to Pyth contract..." ) ;
455444 this . #logger. log ( ` Wormhole contract: ${ config . wormhole_contract } ` ) ;
456445 this . #priceUpdater ??= new PriceUpdateConfirmed ( this . #getCosmClient( ) ) ;
@@ -469,6 +458,7 @@ export class HermesClient {
469458 this . #logger. log ( ` New price: ${ price . price } (expo: ${ price . expo } )` ) ;
470459 priceUpdateCounter . add ( 1 , { result : "success" } ) ;
471460 this . #lastPriceUpdateAt = new Date ( ) . toISOString ( ) ;
461+ this . #insufficientBalanceCooldownUntil = null ;
472462 } catch ( error ) {
473463 // SEC-04: Sanitize error messages to prevent information leakage
474464 const errorCode = classifyError ( error ) ;
@@ -585,15 +575,7 @@ export class HermesClient {
585575 const updatePrices = async ( ) => {
586576 for await ( const priceUpdate of priceUpdates ) {
587577 try {
588- if ( this . #insufficientBalanceCooldownUntil !== null ) {
589- if ( Date . now ( ) < this . #insufficientBalanceCooldownUntil) {
590- this . #logger. warn ( "Skipping price update: insufficient balance cooldown active" ) ;
591- continue ;
592- }
593- this . #logger. log ( "Insufficient balance cooldown expired, retrying..." ) ;
594- }
595578 await this . #updatePrice( priceUpdate ) ;
596- this . #insufficientBalanceCooldownUntil = null ;
597579 } catch ( error ) {
598580 this . #logger. error ( "Error in scheduled update:" , error ) ;
599581 }
@@ -637,7 +619,23 @@ export class HermesClient {
637619 }
638620}
639621
640- // Export types for external use
641622export type {
642623 ConfigResponse , DataSourceResponse , OracleParamsResponse , PriceFeedIdResponse , PriceFeedResponse , PriceResponse , RefreshOracleParamsMsg , TransferAdminMsg , UpdateFeeMsg ,
643624} ;
625+
626+ export type ErrorCode = "insufficient_balance" | "timeout" | "connection_issue" | "unknown" ;
627+
628+ export function classifyError ( error : unknown ) : ErrorCode {
629+ const message = error instanceof Error ? error . message : "" ;
630+
631+ if ( / i n s u f f i c i e n t f u n d s | i n s u f f i c i e n t f e e / i. test ( message ) ) {
632+ return "insufficient_balance" ;
633+ }
634+ if ( / t i m e o u t | E T I M E D O U T / i. test ( message ) ) {
635+ return "timeout" ;
636+ }
637+ if ( / E C O N N R E F U S E D | E C O N N R E S E T | E N O T F O U N D / i. test ( message ) ) {
638+ return "connection_issue" ;
639+ }
640+ return "unknown" ;
641+ }
0 commit comments