From 19d0b5d3a84955fd3a770df48796f240cee0e961 Mon Sep 17 00:00:00 2001 From: phamphong9981 Date: Thu, 12 Sep 2024 14:17:52 +0700 Subject: [PATCH 1/4] refactor: merge --- .../evm/20240502080101_erc20_statistic.ts | 16 ++++++ src/models/erc20_contract.ts | 11 ++++ src/models/erc20_statistic.ts | 44 ++++++++++++++++ src/models/index.ts | 1 + src/services/evm/erc20.service.ts | 52 ++++++++++++++++++- 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 migrations/evm/20240502080101_erc20_statistic.ts create mode 100644 src/models/erc20_statistic.ts diff --git a/migrations/evm/20240502080101_erc20_statistic.ts b/migrations/evm/20240502080101_erc20_statistic.ts new file mode 100644 index 000000000..8ec81e57e --- /dev/null +++ b/migrations/evm/20240502080101_erc20_statistic.ts @@ -0,0 +1,16 @@ +import { Knex } from 'knex'; + +export async function up(knex: Knex): Promise { + await knex.schema.createTable('erc20_statistic', (table) => { + table.increments(); + table.integer('erc20_contract_id').notNullable(); + table.foreign('erc20_contract_id').references('erc20_contract.id'); + table.integer('total_holder'); + table.date('date').index().notNullable(); + table.unique(['erc20_contract_id', 'date']); + }); +} + +export async function down(knex: Knex): Promise { + await knex.schema.dropTableIfExists('erc20_statistic'); +} diff --git a/src/models/erc20_contract.ts b/src/models/erc20_contract.ts index 7694b430c..51a58a3c1 100644 --- a/src/models/erc20_contract.ts +++ b/src/models/erc20_contract.ts @@ -3,8 +3,11 @@ import BaseModel from './base'; import { EVMSmartContract } from './evm_smart_contract'; // eslint-disable-next-line import/no-cycle import { Erc20Activity } from './erc20_activity'; +import { AccountBalance } from './account_balance'; export class Erc20Contract extends BaseModel { + [relation: string]: any; + static softDelete = false; id!: number; @@ -61,6 +64,14 @@ export class Erc20Contract extends BaseModel { from: 'erc20_contract.address', }, }, + holders: { + relation: Model.HasManyRelation, + modelClass: AccountBalance, + join: { + to: 'account_balance.denom', + from: 'erc20_contract.address', + }, + }, }; } diff --git a/src/models/erc20_statistic.ts b/src/models/erc20_statistic.ts new file mode 100644 index 000000000..2dfadfa7a --- /dev/null +++ b/src/models/erc20_statistic.ts @@ -0,0 +1,44 @@ +import { Model } from 'objection'; +import BaseModel from './base'; +import { Erc20Contract } from './erc20_contract'; + +export class Erc20Statistic extends BaseModel { + static softDelete = false; + + [relation: string]: any; + + date!: Date; + + erc20_contract_id!: number; + + total_holder!: number; + + static get tableName() { + return 'erc20_statistic'; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['erc20_contract_id', 'total_holder', 'date'], + properties: { + erc20_contract_id: { type: 'number' }, + total_holder: { type: 'number' }, + date: { type: 'object' }, + }, + }; + } + + static get relationMappings() { + return { + erc20_contract: { + relation: Model.BelongsToOneRelation, + modelClass: Erc20Contract, + join: { + from: 'erc20_statistic.erc20_contract_id', + to: 'erc20_contract.id', + }, + }, + }; + } +} diff --git a/src/models/index.ts b/src/models/index.ts index 1d4e16dda..3ff790365 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -48,3 +48,4 @@ export * from './erc721_stats'; export * from './evm_block'; export * from './optimism_deposit'; export * from './optimism_withdrawal'; +export * from './erc20_statistic'; diff --git a/src/services/evm/erc20.service.ts b/src/services/evm/erc20.service.ts index c3fc06503..a14a925b7 100644 --- a/src/services/evm/erc20.service.ts +++ b/src/services/evm/erc20.service.ts @@ -11,7 +11,12 @@ import BullableService, { QueueHandler } from '../../base/bullable.service'; import { SERVICE as COSMOS_SERVICE, Config } from '../../common'; import knex from '../../common/utils/db_connection'; import { getViemClient } from '../../common/utils/etherjs_client'; -import { BlockCheckpoint, EVMSmartContract } from '../../models'; +import { + Block, + BlockCheckpoint, + EVMSmartContract, + Erc20Statistic, +} from '../../models'; import { Erc20Activity } from '../../models/erc20_activity'; import { Erc20Contract } from '../../models/erc20_contract'; import { BULL_JOB_NAME, SERVICE as EVM_SERVICE, SERVICE } from './constant'; @@ -129,6 +134,7 @@ export default class Erc20Service extends BullableService { [BULL_JOB_NAME.HANDLE_ERC20_ACTIVITY], config.erc20.key ); + await this.handleStatistic(startBlock); // get Erc20 activities let erc20Activities = await Erc20Handler.getErc20Activities( startBlock, @@ -358,6 +364,50 @@ export default class Erc20Service extends BullableService { } } + async handleStatistic(startBlock: number) { + const systemDate = ( + await Block.query() + .where('height', startBlock + 1) + .first() + .throwIfNotFound() + ).time; + const lastUpdatedDate = (await Erc20Statistic.query().max('date').first()) + ?.max; + if (lastUpdatedDate) { + systemDate.setHours(0, 0, 0, 0); + lastUpdatedDate.setHours(0, 0, 0, 0); + if (systemDate > lastUpdatedDate) { + await this.handleTotalHolderStatistic(systemDate); + } + } else { + await this.handleTotalHolderStatistic(systemDate); + } + } + + async handleTotalHolderStatistic(systemDate: Date) { + const totalHolder = await Erc20Contract.query() + .joinRelated('holders') + .where('erc20_contract.track', true) + .groupBy('erc20_contract.id') + .select( + 'erc20_contract.id as erc20_contract_id', + knex.raw( + 'count(CASE when holders.amount > 0 THEN 1 ELSE null END) as count' + ) + ); + if (totalHolder.length > 0) { + await Erc20Statistic.query().insert( + totalHolder.map((e) => + Erc20Statistic.fromJson({ + erc20_contract_id: e.erc20_contract_id, + total_holder: e.count, + date: systemDate, + }) + ) + ); + } + } + public async _start(): Promise { this.viemClient = getViemClient(); if (NODE_ENV !== 'test') { From da6c6dc91bdcf3bce6b791e5e4016adfed1790a8 Mon Sep 17 00:00:00 2001 From: phamphong9981 Date: Wed, 15 May 2024 09:48:52 +0700 Subject: [PATCH 2/4] refactor: review --- src/services/cw20/cw20.service.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/cw20/cw20.service.ts b/src/services/cw20/cw20.service.ts index 33e8fb962..d79eb64ba 100644 --- a/src/services/cw20/cw20.service.ts +++ b/src/services/cw20/cw20.service.ts @@ -272,7 +272,7 @@ export default class Cw20Service extends BullableService { } async handleTotalHolderStatistic(systemDate: Date) { - const totalHolder = await Cw20Contract.query() + const totalHolders = await Cw20Contract.query() .joinRelated('holders') .where('cw20_contract.track', true) .groupBy('cw20_contract.id') @@ -282,9 +282,9 @@ export default class Cw20Service extends BullableService { 'count(CASE when holders.amount > 0 THEN 1 ELSE null END) as count' ) ); - if (totalHolder.length > 0) { + if (totalHolders.length > 0) { await CW20TotalHolderStats.query().insert( - totalHolder.map((e) => + totalHolders.map((e) => CW20TotalHolderStats.fromJson({ cw20_contract_id: e.cw20_contract_id, total_holder: e.count, From 802eea42edc05e69d5e269888d87ed367f86f0c5 Mon Sep 17 00:00:00 2001 From: phamphong9981 Date: Wed, 15 May 2024 16:08:32 +0700 Subject: [PATCH 3/4] refactor: review --- src/services/cw20/cw20.service.ts | 6 +++--- src/services/evm/erc20.service.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/services/cw20/cw20.service.ts b/src/services/cw20/cw20.service.ts index d79eb64ba..33e8fb962 100644 --- a/src/services/cw20/cw20.service.ts +++ b/src/services/cw20/cw20.service.ts @@ -272,7 +272,7 @@ export default class Cw20Service extends BullableService { } async handleTotalHolderStatistic(systemDate: Date) { - const totalHolders = await Cw20Contract.query() + const totalHolder = await Cw20Contract.query() .joinRelated('holders') .where('cw20_contract.track', true) .groupBy('cw20_contract.id') @@ -282,9 +282,9 @@ export default class Cw20Service extends BullableService { 'count(CASE when holders.amount > 0 THEN 1 ELSE null END) as count' ) ); - if (totalHolders.length > 0) { + if (totalHolder.length > 0) { await CW20TotalHolderStats.query().insert( - totalHolders.map((e) => + totalHolder.map((e) => CW20TotalHolderStats.fromJson({ cw20_contract_id: e.cw20_contract_id, total_holder: e.count, diff --git a/src/services/evm/erc20.service.ts b/src/services/evm/erc20.service.ts index a14a925b7..a8517f4d0 100644 --- a/src/services/evm/erc20.service.ts +++ b/src/services/evm/erc20.service.ts @@ -385,7 +385,7 @@ export default class Erc20Service extends BullableService { } async handleTotalHolderStatistic(systemDate: Date) { - const totalHolder = await Erc20Contract.query() + const totalHolders = await Erc20Contract.query() .joinRelated('holders') .where('erc20_contract.track', true) .groupBy('erc20_contract.id') @@ -395,9 +395,9 @@ export default class Erc20Service extends BullableService { 'count(CASE when holders.amount > 0 THEN 1 ELSE null END) as count' ) ); - if (totalHolder.length > 0) { + if (totalHolders.length > 0) { await Erc20Statistic.query().insert( - totalHolder.map((e) => + totalHolders.map((e) => Erc20Statistic.fromJson({ erc20_contract_id: e.erc20_contract_id, total_holder: e.count, From 607d6f7b9149e381afb271d9c8ea7b29c2a78c1b Mon Sep 17 00:00:00 2001 From: phamphong9981 Date: Wed, 3 Jul 2024 10:57:23 +0700 Subject: [PATCH 4/4] refactor: review --- src/services/evm/erc20.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/evm/erc20.service.ts b/src/services/evm/erc20.service.ts index a8517f4d0..fe25efb1d 100644 --- a/src/services/evm/erc20.service.ts +++ b/src/services/evm/erc20.service.ts @@ -371,8 +371,8 @@ export default class Erc20Service extends BullableService { .first() .throwIfNotFound() ).time; - const lastUpdatedDate = (await Erc20Statistic.query().max('date').first()) - ?.max; + const lastUpdatedRecord = await Erc20Statistic.query().max('date').first(); + const lastUpdatedDate = lastUpdatedRecord?.max; if (lastUpdatedDate) { systemDate.setHours(0, 0, 0, 0); lastUpdatedDate.setHours(0, 0, 0, 0);