Skip to content

Commit

Permalink
feat: fallback to full mode from partial mode
Browse files Browse the repository at this point in the history
  • Loading branch information
doomsower committed Dec 18, 2024
1 parent 0a3dc6e commit 06fcf49
Show file tree
Hide file tree
Showing 10 changed files with 613 additions and 494 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@
"pino-pretty": "^13.0.0"
},
"devDependencies": {
"@aws-sdk/client-s3": "^3.709.0",
"@commitlint/cli": "^19.6.0",
"@aws-sdk/client-s3": "^3.713.0",
"@commitlint/cli": "^19.6.1",
"@commitlint/config-conventional": "^19.6.0",
"@flashbots/ethers-provider-bundle": "^1.0.0",
"@gearbox-protocol/eslint-config": "2.0.0-next.2",
"@gearbox-protocol/liquidator-v2-contracts": "^2.2.2",
"@gearbox-protocol/prettier-config": "2.0.0",
"@gearbox-protocol/sdk-gov": "^2.32.2",
"@gearbox-protocol/sdk-gov": "^2.33.0",
"@gearbox-protocol/types": "^1.13.1",
"@redstone-finance/evm-connector": "^0.7.3",
"@types/node": "^22.10.2",
Expand All @@ -54,7 +54,7 @@
"redstone-protocol": "^1.0.5",
"tsx": "^4.19.2",
"typescript": "^5.7.2",
"viem": "^2.21.54",
"viem": "^2.21.55",
"vitest": "^2.1.8"
},
"prettier": "@gearbox-protocol/prettier-config",
Expand Down
1 change: 1 addition & 0 deletions src/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const envConfigMapping: Record<keyof ConfigSchema, string | string[]> = {
aavePartialLiquidatorAddress: "AAVE_PARTIAL_LIQUIDATOR_ADDRESS",
ghoPartialLiquidatorAddress: "GHO_PARTIAL_LIQUIDATOR_ADDRESS",
dolaPartialLiquidatorAddress: "DOLA_PARTIAL_LIQUIDATOR_ADDRESS",
partialFallback: "PARTIAL_FALLBACK",
privateKey: "PRIVATE_KEY",
port: "PORT",
slippage: "SLIPPAGE",
Expand Down
4 changes: 4 additions & 0 deletions src/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ export const ConfigSchema = z.object({
* Address of deployed partiali liquidator contract for DOLA credit managers
*/
dolaPartialLiquidatorAddress: Address.optional(),
/**
* Fallback to use full liquidator when partial liquidator fails
*/
partialFallback: booleanLike.pipe(z.boolean().optional()),
/**
* The serive can deploy partial liquidator contracts.
* Usage: deploy them once from local machine then pass the address to production service
Expand Down
6 changes: 4 additions & 2 deletions src/services/liquidate/AbstractLiquidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default abstract class AbstractLiquidator {
#router?: Address;
#cmCache: Record<string, CreditManagerData> = {};

public async launch(): Promise<void> {
public async launch(asFallback?: boolean): Promise<void> {
this.#errorHandler = new ErrorHandler(this.config, this.logger);
const [pfAddr, dcAddr] = await Promise.all([
this.addressProvider.findService("ROUTER", 300),
Expand All @@ -82,7 +82,9 @@ export default abstract class AbstractLiquidator {
this.client.pub,
this.config.network,
);
this.notifier.notify(new StartedMessage());
if (!asFallback) {
this.notifier.notify(new StartedMessage());
}
}

protected newOptimisticResult(acc: CreditAccountData): OptimisticResult {
Expand Down
4 changes: 2 additions & 2 deletions src/services/liquidate/BatchLiquidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ export default class BatchLiquidator
{
#batchLiquidator?: Address;

public override async launch(): Promise<void> {
await super.launch();
public override async launch(asFallback?: boolean): Promise<void> {
await super.launch(asFallback);
await this.#deployContract();
}

Expand Down
16 changes: 7 additions & 9 deletions src/services/liquidate/SingularFullLiquidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@ import { iCreditFacadeV3Abi } from "@gearbox-protocol/types/abi";
import type { SimulateContractReturnType } from "viem";

import { type CreditAccountData, exceptionsAbis } from "../../data/index.js";
import type { PathFinderCloseResult } from "../../utils/ethers-6-temp/pathfinder/index.js";
import SingularLiquidator from "./SingularLiquidator.js";
import type { MakeLiquidatableResult, PriceUpdate } from "./types.js";
import type {
FullLiquidationPreview,
MakeLiquidatableResult,
} from "./types.js";

interface SinglularFullPreview extends PathFinderCloseResult {
priceUpdates: PriceUpdate[];
}

export default class SingularFullLiquidator extends SingularLiquidator<SinglularFullPreview> {
export default class SingularFullLiquidator extends SingularLiquidator<FullLiquidationPreview> {
protected readonly name = "full";
protected readonly adverb = "fully";

Expand All @@ -21,7 +19,7 @@ export default class SingularFullLiquidator extends SingularLiquidator<Singlular
return Promise.resolve({});
}

public async preview(ca: CreditAccountData): Promise<SinglularFullPreview> {
public async preview(ca: CreditAccountData): Promise<FullLiquidationPreview> {
try {
const cm = await this.getCreditManagerData(ca.creditManager);

Expand Down Expand Up @@ -55,7 +53,7 @@ export default class SingularFullLiquidator extends SingularLiquidator<Singlular

public async simulate(
account: CreditAccountData,
preview: SinglularFullPreview,
preview: FullLiquidationPreview,
): Promise<SimulateContractReturnType> {
return this.client.pub.simulateContract({
account: this.client.account,
Expand Down
1 change: 1 addition & 0 deletions src/services/liquidate/SingularLiquidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ export default abstract class SingularLiquidator<T extends StrategyPreview>
abstract makeLiquidatable(
ca: CreditAccountData,
): Promise<MakeLiquidatableResult>;

abstract preview(ca: CreditAccountData): Promise<T>;
/**
* Simulates liquidation
Expand Down
53 changes: 49 additions & 4 deletions src/services/liquidate/SingularPartialLiquidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@ import type { ILogger } from "../../log/index.js";
import AAVELiquidatorContract from "./AAVELiquidatorContract.js";
import GHOLiquidatorContract from "./GHOLiquidatorContract.js";
import type PartialLiquidatorContract from "./PartialLiquidatorContract.js";
import SingularFullLiquidator from "./SingularFullLiquidator.js";
import SingularLiquidator from "./SingularLiquidator.js";
import type {
MakeLiquidatableResult,
PartialLiquidationPreview,
PartialLiquidationPreviewWithFallback,
} from "./types.js";
import type { TokenPriceInfo } from "./viem-types.js";

Expand All @@ -44,7 +46,7 @@ interface TokenBalance extends ExcludeArrayProps<TokenPriceInfo> {
weightedBalance: bigint;
}

export default class SingularPartialLiquidator extends SingularLiquidator<PartialLiquidationPreview> {
export default class SingularPartialLiquidator extends SingularLiquidator<PartialLiquidationPreviewWithFallback> {
protected readonly name = "partial";
protected readonly adverb = "partially";

Expand All @@ -54,9 +56,16 @@ export default class SingularPartialLiquidator extends SingularLiquidator<Partia
* mapping of credit manager address to deployed partial liquidator
*/
#liquidatorForCM: Record<Address, PartialLiquidatorContract> = {};
#fallback?: SingularFullLiquidator;

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

if (this.config.partialFallback && !asFallback) {
this.#fallback = new SingularFullLiquidator();
this.logger.debug("launching full liquidator as fallback");
await this.#fallback.launch(true);
}

const router = await this.addressProvider.findService("ROUTER", 300);
const bot = await this.addressProvider.findService(
Expand Down Expand Up @@ -154,7 +163,28 @@ export default class SingularPartialLiquidator extends SingularLiquidator<Partia

public async preview(
ca: CreditAccountData,
): Promise<PartialLiquidationPreview> {
): Promise<PartialLiquidationPreviewWithFallback> {
const logger = this.#caLogger(ca);
try {
const partial = await this.#preview(ca);
return {
...partial,
fallback: false,
};
} catch (e) {
if (this.#fallback) {
logger.debug("previewing with fallback liquidator");
const result = await this.#fallback.preview(ca);
return {
...result,
fallback: true,
};
}
throw e;
}
}

async #preview(ca: CreditAccountData): Promise<PartialLiquidationPreview> {
const logger = this.#caLogger(ca);
const cm = await this.getCreditManagerData(ca.creditManager);
const priceUpdates = await this.redstone.liquidationPreviewUpdates(ca);
Expand Down Expand Up @@ -249,6 +279,21 @@ export default class SingularPartialLiquidator extends SingularLiquidator<Partia
}

public async simulate(
account: CreditAccountData,
preview: PartialLiquidationPreviewWithFallback,
): Promise<SimulateContractReturnType> {
const logger = this.#caLogger(account);
if (preview.fallback) {
if (!this.#fallback) {
throw new Error("fallback liquidator is not launched");
}
logger.debug("simulating with fallback liquidator");
return this.#fallback.simulate(account, preview);
}
return this.#simulate(account, preview);
}

async #simulate(
account: CreditAccountData,
preview: PartialLiquidationPreview,
): Promise<SimulateContractReturnType> {
Expand Down
13 changes: 12 additions & 1 deletion src/services/liquidate/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type {
MultiCall,
PriceOnDemand,
} from "../../data/index.js";
import type { PathFinderCloseResult } from "../../utils/ethers-6-temp/pathfinder/index.js";

export interface PriceOnDemandExtras extends PriceOnDemand {
/**
Expand All @@ -28,6 +29,10 @@ export interface PriceUpdate {
reserve: boolean;
}

export interface FullLiquidationPreview extends PathFinderCloseResult {
priceUpdates: PriceUpdate[];
}

export interface PartialLiquidationPreview {
calls: MultiCall[];
assetOut: Address;
Expand All @@ -38,8 +43,14 @@ export interface PartialLiquidationPreview {
skipOnFailure?: boolean;
}

export type PartialLiquidationPreviewWithFallback =
| (PartialLiquidationPreview & {
fallback: false;
})
| (FullLiquidationPreview & { fallback: true });

export interface ILiquidatorService {
launch: () => Promise<void>;
launch: (asFallback?: boolean) => Promise<void>;
liquidate: (accounts: CreditAccountData[]) => Promise<void>;
/**
*
Expand Down
Loading

0 comments on commit 06fcf49

Please sign in to comment.