Skip to content

Commit 433a13e

Browse files
committed
feat: liquidate expired accounts
1 parent e460d4f commit 433a13e

File tree

4 files changed

+153
-86
lines changed

4 files changed

+153
-86
lines changed

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@
2424
"@aws-sdk/client-s3": "^3.943.0",
2525
"@biomejs/biome": "^2.3.8",
2626
"@commander-js/extra-typings": "^14.0.0",
27-
"@commitlint/cli": "^20.1.0",
28-
"@commitlint/config-conventional": "^20.0.0",
27+
"@commitlint/cli": "^20.2.0",
28+
"@commitlint/config-conventional": "^20.2.0",
2929
"@gearbox-protocol/biome-config": "^1.0.14",
3030
"@gearbox-protocol/cli-utils": "^5.61.1",
3131
"@gearbox-protocol/liquidator-contracts": "^1.36.0-experimental.67",
3232
"@gearbox-protocol/liquidator-v2-contracts": "^2.4.0",
33-
"@gearbox-protocol/sdk": "11.8.9",
33+
"@gearbox-protocol/sdk": "11.9.0",
3434
"@gearbox-protocol/types": "^1.14.8",
3535
"@types/node": "^24.10.1",
3636
"@uniswap/sdk-core": "^7.9.0",

src/services/Scanner.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,9 @@ export class Scanner {
169169
!this.config.updateReservePrices,
170170
};
171171
accounts = await this.#getAllCreditAccounts(queue, blockNumber);
172+
if (accounts.length === 0) {
173+
accounts = await this.#getExpiredCreditAccounts(blockNumber);
174+
}
172175
}
173176
if (this.config.restakingWorkaround) {
174177
const before = accounts.length;
@@ -261,6 +264,64 @@ export class Scanner {
261264
return accounts;
262265
}
263266

267+
async #getExpiredCreditAccounts(
268+
blockNumber?: bigint,
269+
): Promise<CreditAccountData[]> {
270+
const timestamp = this.caService.sdk.timestamp;
271+
const expiredCMs = new AddressSet();
272+
273+
for (const m of this.caService.sdk.marketRegister.markets) {
274+
// nothing borrowed === no accounts
275+
if (m.pool.pool.totalBorrowed === 0n) {
276+
continue;
277+
}
278+
for (const cm of m.creditManagers) {
279+
const borrowed =
280+
m.pool.pool.creditManagerDebtParams.get(cm.creditManager.address)
281+
?.borrowed ?? 0n;
282+
const expired =
283+
cm.creditFacade.expirable &&
284+
cm.creditFacade.expirationDate < timestamp;
285+
286+
if (expired && borrowed > 0n) {
287+
expiredCMs.add(cm.creditManager.address);
288+
}
289+
}
290+
}
291+
292+
if (expiredCMs.size === 0) {
293+
return [];
294+
}
295+
this.log.info(`found ${expiredCMs.size} expired credit managers`);
296+
297+
let result: CreditAccountData[] = [];
298+
if (this.config.optimistic) {
299+
result = await this.caService.getCreditAccounts(
300+
{
301+
ignoreReservePrices: true,
302+
minHealthFactor: 0n,
303+
maxHealthFactor: MAX_UINT256,
304+
},
305+
blockNumber,
306+
);
307+
result = result.filter(ca => expiredCMs.has(ca.creditManager));
308+
} else {
309+
// we can take first expired credit manager, and continue with next one on next block
310+
result = await this.caService.getCreditAccounts(
311+
{
312+
creditManager: expiredCMs.asArray()[0],
313+
ignoreReservePrices: true,
314+
minHealthFactor: 0n,
315+
maxHealthFactor: MAX_UINT256,
316+
},
317+
blockNumber,
318+
);
319+
}
320+
321+
this.log.debug(`found ${result.length} expired credit accounts`);
322+
return result;
323+
}
324+
264325
async #setupRestakingWorkaround(): Promise<void> {
265326
this.#restakingCMAddr = RESTAKING_CMS[this.config.network];
266327

src/services/liquidate/LiquidationStrategyFull.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,11 @@ export default class LiquidationStrategyFull
168168
try {
169169
const isV310 = this.checkAccountVersion(ca, VERSION_RANGE_310);
170170
const ignoreReservePrices = !this.config.updateReservePrices && isV310;
171+
const cm = this.sdk.marketRegister.findCreditManager(ca.creditManager);
172+
// TODO: try to liquidate with debt only, then normally as a fallback
173+
const expired =
174+
cm.creditFacade.expirable &&
175+
cm.creditFacade.expirationDate < this.sdk.timestamp;
171176
const { tx, routerCloseResult, calls } =
172177
await this.creditAccountService.fullyLiquidate({
173178
account: ca,
@@ -176,6 +181,7 @@ export default class LiquidationStrategyFull
176181
keepAssets: this.config.keepAssets,
177182
ignoreReservePrices,
178183
applyLossPolicy: this.#applyLossPolicy,
184+
debtOnly: expired,
179185
});
180186
return { ...routerCloseResult, calls, rawTx: tx };
181187
} catch (e) {

0 commit comments

Comments
 (0)