@@ -8,6 +8,7 @@ import type {
88} from "@gearbox-protocol/sdk" ;
99import {
1010 AbstractCreditAccountService ,
11+ AddressSet ,
1112 hexEq ,
1213 MAX_UINT256 ,
1314 PERCENTAGE_FACTOR ,
@@ -19,13 +20,15 @@ import {
1920 iCreditManagerV3Abi ,
2021 iPartialLiquidationBotV3Abi ,
2122} from "@gearbox-protocol/types/abi" ;
23+ import { throttle } from "es-toolkit" ;
2224import type { Address , Block , HttpTransportConfig , PublicClient } from "viem" ;
2325import { createPublicClient , getContract , http } from "viem" ;
2426import type { Config } from "../config/index.js" ;
2527import { DI } from "../di.js" ;
2628import { type ILogger , Logger } from "../log/index.js" ;
2729import type Client from "./Client.js" ;
2830import type { ILiquidatorService } from "./liquidate/index.js" ;
31+ import type { INotifier } from "./notifier/index.js" ;
2932
3033const RESTAKING_CMS : Partial < Record < NetworkType , Address > > = {
3134 Mainnet :
@@ -51,6 +54,9 @@ export class Scanner {
5154 @DI . Inject ( DI . CreditAccountService )
5255 caService ! : ICreditAccountsService ;
5356
57+ @DI . Inject ( DI . Notifier )
58+ notifier ! : INotifier ;
59+
5460 #processing: bigint | null = null ;
5561 #restakingCMAddr?: Address ;
5662 #restakingMinHF?: bigint ;
@@ -59,6 +65,14 @@ export class Scanner {
5965 #minHealthFactor = 0n ;
6066 #unwatch?: ( ) => void ;
6167
68+ constructor ( ) {
69+ this . #notifyOnZeroHFAccounts = throttle (
70+ this . #notifyOnZeroHFAccounts,
71+ 1000 * 60 * 5 ,
72+ { edges : [ "leading" ] } ,
73+ ) ;
74+ }
75+
6276 public async launch ( ) : Promise < void > {
6377 await this . liquidatorService . launch ( ) ;
6478 if ( this . config . restakingWorkaround ) {
@@ -161,7 +175,7 @@ export class Scanner {
161175 this . config . liquidationMode !== "deleverage" &&
162176 ! this . config . updateReservePrices ,
163177 } ;
164- accounts = await this . caService . getCreditAccounts ( queue , blockNumber ) ;
178+ accounts = await this . #getAllCreditAccounts ( queue , blockNumber ) ;
165179 }
166180 if ( this . config . restakingWorkaround ) {
167181 const before = accounts . length ;
@@ -214,6 +228,46 @@ export class Scanner {
214228 }
215229 }
216230
231+ async #getAllCreditAccounts(
232+ queue : GetCreditAccountsOptions ,
233+ blockNumber ?: bigint ,
234+ ) : Promise < CreditAccountData [ ] > {
235+ let accounts = await this . caService . getCreditAccounts ( queue , blockNumber ) ;
236+ let zeroHFAccs = accounts . filter ( ca => ca . healthFactor === 0n ) ;
237+
238+ if ( zeroHFAccs . length > 0 ) {
239+ this . log . warn (
240+ `found ${ zeroHFAccs . length } accounts with HF=0 on first attempt, retrying` ,
241+ ) ;
242+ accounts = await this . caService . getCreditAccounts ( queue , blockNumber ) ;
243+ zeroHFAccs = accounts . filter ( ca => ca . healthFactor === 0n ) ;
244+
245+ if ( zeroHFAccs . length > 0 ) {
246+ this . log . warn (
247+ `found ${ zeroHFAccs . length } accounts with HF=0 on second attempt, skipping them` ,
248+ ) ;
249+ accounts = accounts . filter ( ca => ca . healthFactor !== 0n ) ;
250+
251+ const badTokens = new AddressSet ( ) ;
252+ for ( const ca of zeroHFAccs ) {
253+ for ( const token of ca . tokens ) {
254+ if ( ! token . success ) {
255+ badTokens . add ( token . token ) ;
256+ }
257+ }
258+ }
259+ const badTokensStr = badTokens
260+ . asArray ( )
261+ . map ( t => this . caService . sdk . tokensMeta . get ( t ) ?. symbol )
262+ . join ( ", " ) ;
263+ this . log . warn ( `bad tokens: ${ badTokensStr } ` ) ;
264+ this . #notifyOnZeroHFAccounts( zeroHFAccs . length , badTokensStr ) ;
265+ }
266+ }
267+
268+ return accounts ;
269+ }
270+
217271 async #setupRestakingWorkaround( ) : Promise < void > {
218272 this . #restakingCMAddr = RESTAKING_CMS [ this . config . network ] ;
219273
@@ -350,6 +404,13 @@ export class Scanner {
350404 return result ;
351405 }
352406
407+ #notifyOnZeroHFAccounts = ( count : number , badTokens : string ) : void => {
408+ this . notifier . alert ( {
409+ plain : `found ${ count } accounts with HF=0, bad tokens: ${ badTokens } ` ,
410+ markdown : `found ${ count } accounts with HF=0, bad tokens: ${ badTokens } ` ,
411+ } ) ;
412+ } ;
413+
353414 public get lastUpdated ( ) : bigint {
354415 return this . #lastUpdated;
355416 }
0 commit comments