Skip to content

Commit

Permalink
feat: partial liquidator for GHO
Browse files Browse the repository at this point in the history
BREAKING CHANGE: this changes config variables for partial liquidator
  • Loading branch information
doomsower committed Sep 2, 2024
1 parent d5d8418 commit 95ddff8
Show file tree
Hide file tree
Showing 16 changed files with 703 additions and 434 deletions.
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,21 @@
},
"devDependencies": {
"@aws-sdk/client-s3": "^3.637.0",
"@commitlint/cli": "^19.4.0",
"@commitlint/config-conventional": "^19.2.2",
"@commitlint/cli": "^19.4.1",
"@commitlint/config-conventional": "^19.4.1",
"@flashbots/ethers-provider-bundle": "^1.0.0",
"@gearbox-protocol/eslint-config": "2.0.0-next.2",
"@gearbox-protocol/liquidator-v2-contracts": "^2.1.0",
"@gearbox-protocol/liquidator-v2-contracts": "^2.2.1",
"@gearbox-protocol/prettier-config": "2.0.0-next.0",
"@gearbox-protocol/sdk-gov": "^2.18.5",
"@gearbox-protocol/sdk-gov": "^2.20.0",
"@gearbox-protocol/types": "^1.12.1",
"@redstone-finance/evm-connector": "^0.6.1",
"@types/node": "^22.5.0",
"@types/node": "^22.5.2",
"@uniswap/sdk-core": "^5.3.1",
"@uniswap/v3-sdk": "^3.13.1",
"@vlad-yakovlev/telegram-md": "^2.0.0",
"abitype": "^1.0.6",
"axios": "^1.7.5",
"axios": "^1.7.7",
"axios-retry": "^4.5.0",
"date-fns": "^3.6.0",
"di-at-home": "^0.0.7",
Expand All @@ -46,15 +46,15 @@
"eslint": "^8.57.0",
"ethers": "^6.13.2",
"husky": "^9.1.5",
"lint-staged": "^15.2.9",
"lint-staged": "^15.2.10",
"nanoid": "^5.0.7",
"node-pty": "^1.0.0",
"pino": "^9.3.2",
"prettier": "^3.3.3",
"redstone-protocol": "^1.0.5",
"tsx": "^4.19.0",
"typescript": "^5.5.4",
"viem": "^2.20.1",
"viem": "^2.21.1",
"vitest": "^2.0.5"
},
"prettier": "@gearbox-protocol/prettier-config",
Expand Down
5 changes: 2 additions & 3 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Config } from "./config/index.js";
import { loadConfig } from "./config/index.js";
import { Config } from "./config/index.js";
import { DI } from "./di.js";
import { type ILogger, Logger } from "./log/index.js";
import type { AddressProviderService } from "./services/AddressProviderService.js";
Expand Down Expand Up @@ -68,7 +67,7 @@ class App {
}

export async function launchApp(): Promise<void> {
const config = await loadConfig();
const config = await Config.load();
DI.set(DI.Config, config);
const app = new App();
await app.launch();
Expand Down
52 changes: 52 additions & 0 deletions src/config/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import type { NetworkType } from "@gearbox-protocol/sdk-gov";
import { createPublicClient, http } from "viem";

import { createClassFromType, detectNetwork } from "../utils/index.js";
import { envConfig } from "./env.js";
import { ConfigSchema } from "./schema.js";

interface DynamicConfig {
readonly network: NetworkType;
readonly chainId: number;
readonly startBlock: bigint;
}

const ConfigClass = createClassFromType<ConfigSchema & DynamicConfig>();

export class Config extends ConfigClass {
static async load(): Promise<Config> {
const schema = ConfigSchema.parse(envConfig);

const client = createPublicClient({
transport: http(schema.ethProviderRpcs[0]),
name: "detect network client",
});

const [startBlock, chainId, network] = await Promise.all([
client.getBlockNumber(),
client.getChainId(),
detectNetwork(client),
]);
return new Config({
...schema,
startBlock,
chainId: Number(chainId),
network,
});
}

public get isPartial(): boolean {
return !!(
this.aavePartialLiquidatorAddress ||
this.ghoPartialLiquidatorAddress ||
this.deployAaveLiquidatorContracts ||
this.deployGhoLiquidatorContracts
);
}

public get isBatch(): boolean {
return !!(
this.deployBatchLiquidatorContracts || this.batchLiquidatorAddress
);
}
}
6 changes: 4 additions & 2 deletions src/config/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ const envConfigMapping: Record<keyof ConfigSchema, string | string[]> = {
debugManagers: "DEBUG_MANAGERS",
batchSize: "BATCH_SIZE",
castBin: "CAST_BIN",
deployPartialLiquidatorContracts: "DEPLOY_PARTIAL_LIQUIDATOR",
deployAaveLiquidatorContracts: "DEPLOY_AAVE_PARTIAL_LIQUIDATOR",
deployGhoLiquidatorContracts: "DEPLOY_GHO_PARTIAL_LIQUIDATOR",
deployBatchLiquidatorContracts: "DEPLOY_BATCH_LIQUIDATOR",
ethProviderRpcs: ["JSON_RPC_PROVIDERS", "JSON_RPC_PROVIDER"],
hfThreshold: "HF_TRESHOLD",
Expand All @@ -22,7 +23,8 @@ const envConfigMapping: Record<keyof ConfigSchema, string | string[]> = {
outFileName: "OUT_FILE_NAME",
outS3Bucket: "OUT_S3_BUCKET",
outS3Prefix: "OUT_S3_PREFIX",
partialLiquidatorAddress: "PARTIAL_LIQUIDATOR_ADDRESS",
aavePartialLiquidatorAddress: "AAVE_PARTIAL_LIQUIDATOR_ADDRESS",
ghoPartialLiquidatorAddress: "GHO_PARTIAL_LIQUIDATOR_ADDRESS",
privateKey: "PRIVATE_KEY",
port: "PORT",
slippage: "SLIPPAGE",
Expand Down
30 changes: 1 addition & 29 deletions src/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1 @@
import { createPublicClient, http } from "viem";

import { detectNetwork } from "../utils/index.js";
import { envConfig } from "./env.js";
import type { Config } from "./schema.js";
import { ConfigSchema } from "./schema.js";

export async function loadConfig(): Promise<Config> {
const schema = ConfigSchema.parse(envConfig);

const client = createPublicClient({
transport: http(schema.ethProviderRpcs[0]),
name: "detect network client",
});

const [startBlock, chainId, network] = await Promise.all([
client.getBlockNumber(),
client.getChainId(),
detectNetwork(client),
]);
return {
...schema,
startBlock,
chainId: Number(chainId),
network,
};
}

export type { Config } from "./schema.js";
export { Config } from "./config.js";
17 changes: 5 additions & 12 deletions src/config/schema.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MAX_INT, type NetworkType } from "@gearbox-protocol/sdk-gov";
import { MAX_INT } from "@gearbox-protocol/sdk-gov";
import { Address } from "abitype/zod";
import { type Hex, isHex } from "viem";
import { z } from "zod";
Expand Down Expand Up @@ -48,8 +48,10 @@ export const ConfigSchema = z.object({
*/
hfThreshold: z.coerce.bigint().min(0n).max(MAX_INT).default(MAX_INT),
optimistic: booleanLike.pipe(z.boolean().optional()),
deployPartialLiquidatorContracts: booleanLike.pipe(z.boolean().optional()),
partialLiquidatorAddress: Address.optional(),
deployAaveLiquidatorContracts: booleanLike.pipe(z.boolean().optional()),
aavePartialLiquidatorAddress: Address.optional(),
deployGhoLiquidatorContracts: booleanLike.pipe(z.boolean().optional()),
ghoPartialLiquidatorAddress: Address.optional(),
deployBatchLiquidatorContracts: booleanLike.pipe(z.boolean().optional()),
batchSize: z.coerce.number().nonnegative().default(10),
batchLiquidatorAddress: Address.optional(),
Expand All @@ -72,12 +74,3 @@ export const ConfigSchema = z.object({
});

export type ConfigSchema = z.infer<typeof ConfigSchema>;

/**
* Config + derived fields
*/
export type Config = ConfigSchema & {
network: NetworkType;
chainId: number;
startBlock: bigint;
};
100 changes: 100 additions & 0 deletions src/services/liquidate/AAVELiquidatorContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import {
aaveFlTakerAbi,
aaveLiquidatorAbi,
} from "@gearbox-protocol/liquidator-v2-contracts/abi";
import {
AaveFLTaker_bytecode,
AaveLiquidator_bytecode,
} from "@gearbox-protocol/liquidator-v2-contracts/bytecode";
import { contractsByNetwork } from "@gearbox-protocol/sdk-gov";
import type { Address } from "viem";

import type { ILogger } from "../../log/index.js";
import { Logger } from "../../log/index.js";
import PartialLiquidatorContract from "./PartialLiquidatorContract.js";

export default class AAVELiquidatorContract extends PartialLiquidatorContract {
@Logger("AAVEPartialLiquidator")
logger!: ILogger;

constructor(router: Address, bot: Address) {
super("AAVE Partial Liquidator", router, bot);
}

public async deploy(): Promise<void> {
let address = this.config.aavePartialLiquidatorAddress;
const aavePool =
contractsByNetwork[this.config.network].AAVE_V3_LENDING_POOL;
if (!address) {
this.logger.debug(
{ aavePool, router: this.router, bot: this.bot },
"deploying partial liquidator",
);

let hash = await this.client.wallet.deployContract({
abi: aaveFlTakerAbi,
bytecode: AaveFLTaker_bytecode,
args: [aavePool],
});
this.logger.debug(`waiting for AaveFLTaker to deploy, tx hash: ${hash}`);
const { contractAddress: aaveFlTakerAddr } =
await this.client.pub.waitForTransactionReceipt({
hash,
timeout: 120_000,
});
if (!aaveFlTakerAddr) {
throw new Error(`AaveFLTaker was not deployed, tx hash: ${hash}`);
}
let owner = await this.client.pub.readContract({
abi: aaveFlTakerAbi,
functionName: "owner",
address: aaveFlTakerAddr,
});
this.logger.debug(
`deployed AaveFLTaker at ${aaveFlTakerAddr} owned by ${owner} in tx ${hash}`,
);

hash = await this.client.wallet.deployContract({
abi: aaveLiquidatorAbi,
bytecode: AaveLiquidator_bytecode,
args: [this.router, this.bot, aavePool, aaveFlTakerAddr],
});
this.logger.debug(`waiting for liquidator to deploy, tx hash: ${hash}`);
const { contractAddress: liquidatorAddr } =
await this.client.pub.waitForTransactionReceipt({
hash,
timeout: 120_000,
});
if (!liquidatorAddr) {
throw new Error(`liquidator was not deployed, tx hash: ${hash}`);
}
owner = await this.client.pub.readContract({
abi: aaveLiquidatorAbi,
address: liquidatorAddr,
functionName: "owner",
});
this.logger.debug(
`deployed Liquidator at ${liquidatorAddr} owned by ${owner} in tx ${hash}`,
);

const receipt = await this.client.simulateAndWrite({
address: aaveFlTakerAddr,
abi: aaveFlTakerAbi,
functionName: "setAllowedFLReceiver",
args: [liquidatorAddr, true],
});
if (receipt.status === "reverted") {
throw new Error(
`AaveFLTaker.setAllowedFLReceiver reverted, tx hash: ${receipt.transactionHash}`,
);
}
this.logger.debug(
`set allowed flashloan receiver on FLTaker ${aaveFlTakerAddr} to ${liquidatorAddr} in tx ${receipt.transactionHash}`,
);

address = liquidatorAddr;
}
this.logger.info(`partial liquidator contract addesss: ${address}`);
this.address = address;
}
}
Loading

0 comments on commit 95ddff8

Please sign in to comment.