Skip to content

Commit

Permalink
fix: setup conditions for partial liquidation WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
doomsower committed Apr 11, 2024
1 parent d37c308 commit 57f7c15
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 9 deletions.
16 changes: 10 additions & 6 deletions src/services/liquidate/AbstractLiquidatorService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ export default abstract class AbstractLiquidatorService

try {
const balanceBefore = await this.getBalance(ca);
logger.debug("previewing...");
snapshotId = await this.strategy.makeLiquidatable(ca);
logger.debug({ snapshotId }, "previewing...");
const preview = await this.strategy.preview(ca);
logger.debug({ preview });
optimisticResult.calls = preview.calls;
Expand Down Expand Up @@ -158,11 +159,14 @@ export default abstract class AbstractLiquidatorService
}
}

// save snapshot after all read requests are done
snapshotId = await (this.provider as providers.JsonRpcProvider).send(
"evm_snapshot",
[],
);
// snapshotId might be present if we had to setup liquidation conditions for single account
// otherwise, not write requests has been made up to this point, and it's safe to take snapshot now
if (!snapshotId) {
snapshotId = await (this.provider as providers.JsonRpcProvider).send(
"evm_snapshot",
[],
);
}
// Actual liquidation (write requests start here)
try {
// this is needed because otherwise it's possible to hit deadlines in uniswap calls
Expand Down
7 changes: 7 additions & 0 deletions src/services/liquidate/LiquidationStrategyV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ export default class LiquidationStrategyV2
);
}

public async makeLiquidatable(
ca: CreditAccountData,
): Promise<number | undefined> {
// not supported
return Promise.resolve(undefined);
}

public async preview(
ca: CreditAccountData,
): Promise<PathFinderV1CloseResult> {
Expand Down
7 changes: 7 additions & 0 deletions src/services/liquidate/LiquidationStrategyV3Full.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ export default class LiquidationStrategyV3Full
@Logger("LiquidationStrategyV3Full")
logger: LoggerInterface;

public async makeLiquidatable(
ca: CreditAccountData,
): Promise<number | undefined> {
// not supported
return Promise.resolve(undefined);
}

public async preview(
ca: CreditAccountData,
): Promise<PathFinderV1CloseResult> {
Expand Down
51 changes: 49 additions & 2 deletions src/services/liquidate/LiquidationStrategyV3Partial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type { ILiquidationStrategy, PartialLiquidationPreview } from "./types";
interface TokenBalance {
balance: bigint;
balanceInUnderlying: bigint;
lt: bigint;
}

@Service()
Expand All @@ -38,6 +39,47 @@ export default class LiquidationStrategyV3Partial

#partialLiquidator?: ILiquidator;

public async makeLiquidatable(
ca: CreditAccountData,
): Promise<number | undefined> {
if (!this.config.optimistic) {
throw new Error("makeLiquidatable only works in optimistic mode");
}
const logger = this.logger.child({
account: ca.addr,
borrower: ca.borrower,
manager: managerName(ca),
});

const cm = new CreditManagerData(
await this.compressor.getCreditManagerData(ca.creditManager),
);
const balances = await this.#prepareAccountTokens(ca, cm);
// const snapshotId = await (
// this.executor.provider as providers.JsonRpcProvider
// ).send("evm_snapshot", []);

// LTnew = LT * k, where
//
// totalDebt - Bunderlying * LTunderlying
// k = ----------------------------------------------
// sum(p * b* LT)
let divisor = 0n;
let dividend = ca.borrowedAmountPlusInterestAndFees; // TODO: USDT fee
for (const [t, { balance, balanceInUnderlying, lt }] of Object.entries(
balances,
)) {
if (t === cm.underlyingToken) {
dividend -= balance * lt;
} else {
divisor += balanceInUnderlying * lt;
}
}
const k = Number((dividend * 10000n) / divisor) / 10000;
logger.debug({ k }, "calculated LT lowering multiplier");
return undefined;
}

public async launch(): Promise<void> {
await super.launch();

Expand Down Expand Up @@ -147,6 +189,7 @@ export default class LiquidationStrategyV3Partial
async #prepareAccountTokens(
ca: CreditAccountData,
cm: CreditManagerData,
skipDust = true,
): Promise<Record<string, TokenBalance>> {
// sort by liquidation threshold ASC, place underlying with lowest priority
const balances = Object.entries(ca.allBalances)
Expand All @@ -155,7 +198,7 @@ export default class LiquidationStrategyV3Partial
const minBalance = 10n ** BigInt(Math.max(8, getDecimals(t)) - 8);
// gearbox liquidator only cares about enabled tokens.
// third-party liquidators might want to handle disabled tokens too
return isEnabled && balance > minBalance;
return isEnabled && (balance > minBalance || !skipDust);
})
.map(
([t, b]) => [t, b.balance, cm.liquidationThresholds[t] ?? 0n] as const,
Expand All @@ -173,7 +216,11 @@ export default class LiquidationStrategyV3Partial
return Object.fromEntries(
Object.entries(converted).map(([t, balanceInUnderlying]) => [
t,
{ balance: ca.allBalances[t].balance, balanceInUnderlying },
{
balance: ca.allBalances[t].balance,
balanceInUnderlying,
lt: cm.liquidationThresholds[t],
},
]),
);
}
Expand Down
8 changes: 8 additions & 0 deletions src/services/liquidate/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ export interface ILiquidationStrategy<T extends StrategyPreview> {
name: string;
adverb: string;
launch: () => Promise<void>;
/**
* For optimistic liquidations only: create conditions that make this account liquidatable
* If strategy implements this scenario, it must make evm_snapshot beforehand and return it as a result
* Id strategy does not support this, return undefined
* @param ca
* @returns evm snapshotId or underfined
*/
makeLiquidatable: (ca: CreditAccountData) => Promise<number | undefined>;
preview: (ca: CreditAccountData) => Promise<T>;
estimate: (account: CreditAccountData, preview: T) => Promise<BigNumberish>;
liquidate: (
Expand Down
2 changes: 1 addition & 1 deletion src/services/scan/ScanServiceV3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class ScanServiceV3 extends AbstractScanService {
atBlock,
);
this.log.debug(
`${accounts.length} v3 potential accounts to liquidate${blockS}: ${accounts.map(a => a.addr).join(",")}, failed tokens: ${failedTokens.length}`,
`${accounts.length} v3 potential accounts to liquidate${blockS}, failed tokens: ${failedTokens.length}`,
);
const redstoneUpdates = await this.redstone.updatesForTokens(
failedTokens,
Expand Down

0 comments on commit 57f7c15

Please sign in to comment.