From e37ebbfcb50d9ad5b594a8b54a755d05b9f79862 Mon Sep 17 00:00:00 2001 From: Vadim Date: Wed, 22 Mar 2023 12:09:53 +0100 Subject: [PATCH 1/4] wip --- src/modules/system/system.service.ts | 2 ++ src/providers/web3.provider.ts | 6 ++++++ src/services/worker/worker.service.ts | 12 +++++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/modules/system/system.service.ts b/src/modules/system/system.service.ts index 974c502..9097ff1 100644 --- a/src/modules/system/system.service.ts +++ b/src/modules/system/system.service.ts @@ -7,9 +7,11 @@ import { System } from './system.entity'; export enum SystemType { GENERAL_LAST_BLOCK_NUMBER = 'GENERAL_LAST_BLOCK_NUMBER', EARNINGS_LAST_BLOCK_NUMBER = 'EARNINGS_LAST_BLOCK_NUMBER', + MINIMUM_LIQUIDATION_COLLATERAL = 'MINIMUM_LIQUIDATION_COLLATERAL', // event names EVENT_OPERATOR_ADDED = 'OperatorAdded', EVENT_OPERATOR_REMOVED = 'OperatorRemoved', + EVENT_COLLATERAL_UPDATED = 'MinimumLiquidationCollateralUpdated', EVENT_OPERATOR_FEE_APPROVED = 'OperatorFeeExecuted', EVENT_VALIDATOR_ADDED = 'ValidatorAdded', EVENT_VALIDATOR_REMOVED = 'ValidatorRemoved', diff --git a/src/providers/web3.provider.ts b/src/providers/web3.provider.ts index d6b2dcf..e7417cb 100644 --- a/src/providers/web3.provider.ts +++ b/src/providers/web3.provider.ts @@ -95,6 +95,12 @@ export default class Web3Provider { .call(); } + static async getMinimumLiquidationCollateral(): Promise { + return Web3Provider.contractViews.methods + .getMinimumLiquidationCollateral() + .call(); + } + static toClusterTuple(obj) { return [ obj.validatorCount, diff --git a/src/services/worker/worker.service.ts b/src/services/worker/worker.service.ts index 070f4c0..b23cc6e 100644 --- a/src/services/worker/worker.service.ts +++ b/src/services/worker/worker.service.ts @@ -1,5 +1,8 @@ import { Injectable, Logger } from '@nestjs/common'; -import { SystemType } from '@cli/modules/system/system.service'; + +import Web3Provider from '@cli/providers/web3.provider'; + +import { SystemService, SystemType } from '@cli/modules/system/system.service'; import { ClusterService } from '@cli/modules/clusters/cluster.service'; import { EarningService } from '@cli/modules/earnings/earning.service'; @@ -10,6 +13,7 @@ export class WorkerService { constructor( private _clusterService: ClusterService, private _earningService: EarningService, + private _systemService: SystemService, ) {} async processEvents(events: Array): Promise { @@ -47,6 +51,12 @@ export class WorkerService { case SystemType.EVENT_VALIDATOR_ADDED: await this._clusterService.create(dataItem); break; + case SystemType.EVENT_COLLATERAL_UPDATED: + await this._systemService.save( + SystemType.MINIMUM_LIQUIDATION_COLLATERAL, + await Web3Provider.getMinimumLiquidationCollateral(), + ); + break; } } } From db6d5805358a1653000b723fe363dc12610159f8 Mon Sep 17 00:00:00 2001 From: Vadim Date: Wed, 22 Mar 2023 15:50:07 +0100 Subject: [PATCH 2/4] add logic --- .../clusters/cli/cluster.container.tsx | 3 -- .../clusters/cli/cluster.transformer.tsx | 9 ++--- src/modules/clusters/cluster.entity.ts | 3 -- src/modules/clusters/cluster.service.ts | 2 +- src/services/worker/tasks/burn-rates.task.ts | 35 +++++++++++++------ src/services/worker/tasks/liquidation.task.ts | 9 ++--- src/services/worker/worker.service.ts | 11 ++++-- 7 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/modules/clusters/cli/cluster.container.tsx b/src/modules/clusters/cli/cluster.container.tsx index 4412f04..2ad48d7 100644 --- a/src/modules/clusters/cli/cluster.container.tsx +++ b/src/modules/clusters/cli/cluster.container.tsx @@ -53,12 +53,9 @@ export class Clusters extends Component { const items = await this.props.service.findAll(); const currentBlockNumber = await this.props.web3Provider.currentBlockNumber(); - const minimumBlocksBeforeLiquidation = - await this.props.web3Provider.minimumBlocksBeforeLiquidation(); this.setStateSafely({ items: transformClusterData(items, { currentBlockNumber, - minimumBlocksBeforeLiquidation, }), }); }, 1000); diff --git a/src/modules/clusters/cli/cluster.transformer.tsx b/src/modules/clusters/cli/cluster.transformer.tsx index 79429a0..4d7429b 100644 --- a/src/modules/clusters/cli/cluster.transformer.tsx +++ b/src/modules/clusters/cli/cluster.transformer.tsx @@ -23,14 +23,12 @@ export const colorCodeStatus = status => { }; const textStatus = (item, extra: any) => { - const { currentBlockNumber, minimumBlocksBeforeLiquidation } = extra; - const blockDiff = item.balanceToBlockNumber - ? item.balanceToBlockNumber - currentBlockNumber - : null; + const { currentBlockNumber } = extra; switch (true) { case item.isLiquidated: return 'Liquidated'; - case blockDiff !== null && blockDiff < minimumBlocksBeforeLiquidation: + case item.liquidationBlockNumber !== null && + item.liquidationBlockNumber <= currentBlockNumber: return 'To liquidate'; default: return 'Running'; @@ -62,7 +60,6 @@ export const transformClusterData = (items, extra: any) => { extraPadding: 1, }, liquidationBlockNumber: { text: item.liquidationBlockNumber }, - balanceToBlockNumber: { text: item.balanceToBlockNumber }, updated: { text: timeAgo.format(item.updatedAt, 'round-minute'), }, diff --git a/src/modules/clusters/cluster.entity.ts b/src/modules/clusters/cluster.entity.ts index 07da902..2dd51c5 100644 --- a/src/modules/clusters/cluster.entity.ts +++ b/src/modules/clusters/cluster.entity.ts @@ -31,9 +31,6 @@ export class Cluster { @Column({ default: false }) isLiquidated: boolean; - @Column({ default: null }) - balanceToBlockNumber: number; - @Column({ default: null }) liquidationBlockNumber: number; diff --git a/src/modules/clusters/cluster.service.ts b/src/modules/clusters/cluster.service.ts index cf19dd0..7f0eda4 100644 --- a/src/modules/clusters/cluster.service.ts +++ b/src/modules/clusters/cluster.service.ts @@ -13,7 +13,7 @@ export class ClusterService { async findAll(): Promise { return this._clusterRepository.find({ order: { - balanceToBlockNumber: 'ASC', + liquidationBlockNumber: 'ASC', }, }); } diff --git a/src/services/worker/tasks/burn-rates.task.ts b/src/services/worker/tasks/burn-rates.task.ts index c08d3da..e1c5048 100644 --- a/src/services/worker/tasks/burn-rates.task.ts +++ b/src/services/worker/tasks/burn-rates.task.ts @@ -205,16 +205,31 @@ export class BurnRatesTask { // Prepare final data record.cluster = JSON.stringify(record.cluster); // If cluster won't be liquidated, at which block number his balance becomes zero - record.balanceToBlockNumber = - record.burnRate > 0 - ? currentBlockNumber + - +(record.balance / record.burnRate).toFixed(0) - : null; - // Deduct from block number where cluster balance becomes zero, - // value of Liquidation Threshold Period - record.liquidationBlockNumber = record.balanceToBlockNumber - ? record.balanceToBlockNumber - minimumBlocksBeforeLiquidation - : null; + if (record.burnRate > 0 && record.balance > 0) { + const liveUntilBlockByBalance = + currentBlockNumber + + record.balance / record.burnRate - + minimumBlocksBeforeLiquidation; + + const latestLiveBlockBalance = + record.balance - + (liveUntilBlockByBalance - currentBlockNumber) * record.burnRate; + + const collateralAmount = + +(await Web3Provider.getMinimumLiquidationCollateral()); + + if (record.balance <= collateralAmount) { + record.liquidationBlockNumber = currentBlockNumber; + } else if (latestLiveBlockBalance < collateralAmount) { + record.liquidationBlockNumber = + currentBlockNumber + + (record.balance - collateralAmount) / record.burnRate; + } else { + record.liquidationBlockNumber = liveUntilBlockByBalance; + } + } else { + record.liquidationBlockNumber = null; + } // Save cluster updated data to database await this._atomicRetry( diff --git a/src/services/worker/tasks/liquidation.task.ts b/src/services/worker/tasks/liquidation.task.ts index 0a29d76..74fad65 100644 --- a/src/services/worker/tasks/liquidation.task.ts +++ b/src/services/worker/tasks/liquidation.task.ts @@ -35,15 +35,13 @@ export class LiquidationTask { }, }) async liquidate(): Promise { - const minimumBlocksBeforeLiquidation = - +(await Web3Provider.minimumBlocksBeforeLiquidation()); const currentBlockNumber = +(await Web3Provider.currentBlockNumber()); const toLiquidateRecords = await this._clusterService.findBy({ where: { - balanceToBlockNumber: LessThanOrEqual( - // Current block + Liquidation Threshold Period should higher + liquidationBlockNumber: LessThanOrEqual( + // Current block // than the block number when balance becomes zero if not liquidated - currentBlockNumber + minimumBlocksBeforeLiquidation, + currentBlockNumber, ), }, }); @@ -83,7 +81,6 @@ export class LiquidationTask { { burnRate: null, isLiquidated: true, - balanceToBlockNumber: null, liquidationBlockNumber: null, }, ); diff --git a/src/services/worker/worker.service.ts b/src/services/worker/worker.service.ts index b23cc6e..1a7bcdb 100644 --- a/src/services/worker/worker.service.ts +++ b/src/services/worker/worker.service.ts @@ -1,4 +1,4 @@ -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import Web3Provider from '@cli/providers/web3.provider'; @@ -7,7 +7,7 @@ import { ClusterService } from '@cli/modules/clusters/cluster.service'; import { EarningService } from '@cli/modules/earnings/earning.service'; @Injectable() -export class WorkerService { +export class WorkerService implements OnModuleInit { private readonly _logger = new Logger(WorkerService.name); constructor( @@ -16,6 +16,13 @@ export class WorkerService { private _systemService: SystemService, ) {} + async onModuleInit() { + await this._systemService.save( + SystemType.MINIMUM_LIQUIDATION_COLLATERAL, + await Web3Provider.getMinimumLiquidationCollateral(), + ); + } + async processEvents(events: Array): Promise { if (!events.length) { this._logger.log(`There is no events in this block range`); From 618fe3b10a1a6209968ba011abf8316f3f474988 Mon Sep 17 00:00:00 2001 From: Vadim Date: Wed, 22 Mar 2023 15:58:26 +0100 Subject: [PATCH 3/4] fix balance for liquidated --- src/services/worker/tasks/liquidation.task.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/worker/tasks/liquidation.task.ts b/src/services/worker/tasks/liquidation.task.ts index 74fad65..26dbf63 100644 --- a/src/services/worker/tasks/liquidation.task.ts +++ b/src/services/worker/tasks/liquidation.task.ts @@ -79,6 +79,7 @@ export class LiquidationTask { await this._clusterService.update( { owner: item.owner, operatorIds: item.operatorIds }, { + balance: null, burnRate: null, isLiquidated: true, liquidationBlockNumber: null, From 22c3510bc76769468e1291a33cf31cf3f117d35d Mon Sep 17 00:00:00 2001 From: Vadim Date: Wed, 22 Mar 2023 16:30:51 +0100 Subject: [PATCH 4/4] add comments --- src/services/worker/tasks/burn-rates.task.ts | 9 +++++++++ src/services/worker/worker.service.ts | 3 +-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/services/worker/tasks/burn-rates.task.ts b/src/services/worker/tasks/burn-rates.task.ts index e1c5048..cd7c831 100644 --- a/src/services/worker/tasks/burn-rates.task.ts +++ b/src/services/worker/tasks/burn-rates.task.ts @@ -205,26 +205,35 @@ export class BurnRatesTask { // Prepare final data record.cluster = JSON.stringify(record.cluster); // If cluster won't be liquidated, at which block number his balance becomes zero + // check if burnRate and balance are valid, > 0 if (record.burnRate > 0 && record.balance > 0) { + // Calculate in which block the cluster will start to be ready for liquidation const liveUntilBlockByBalance = currentBlockNumber + record.balance / record.burnRate - minimumBlocksBeforeLiquidation; + // Calculate balance at the block when the cluster will start to be ready for liquidation const latestLiveBlockBalance = record.balance - (liveUntilBlockByBalance - currentBlockNumber) * record.burnRate; + // Get minimum collateral amount (in SSV) const collateralAmount = +(await Web3Provider.getMinimumLiquidationCollateral()); if (record.balance <= collateralAmount) { + // If balance less than minimum collateral amount set a flag to liquidate asap record.liquidationBlockNumber = currentBlockNumber; } else if (latestLiveBlockBalance < collateralAmount) { + // If balance at the block when the cluster will start to be ready for liquidation + // less than minimum collateral amount, set the block when need to liquidate that to get at least minimum collateral amount record.liquidationBlockNumber = currentBlockNumber + (record.balance - collateralAmount) / record.burnRate; } else { + // If balance at the block when the cluster will start to be ready for liquidation + // more or equal than minimum collateral amount, set the block when need to liquidate by actual balance record.liquidationBlockNumber = liveUntilBlockByBalance; } } else { diff --git a/src/services/worker/worker.service.ts b/src/services/worker/worker.service.ts index 1a7bcdb..b843d74 100644 --- a/src/services/worker/worker.service.ts +++ b/src/services/worker/worker.service.ts @@ -1,7 +1,6 @@ -import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; - import Web3Provider from '@cli/providers/web3.provider'; +import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { SystemService, SystemType } from '@cli/modules/system/system.service'; import { ClusterService } from '@cli/modules/clusters/cluster.service'; import { EarningService } from '@cli/modules/earnings/earning.service';