From 9b68be47214b8c78517572cc2be3961502d6af64 Mon Sep 17 00:00:00 2001 From: cauta Date: Thu, 18 Apr 2024 09:14:30 +0700 Subject: [PATCH 01/18] create transaction history module --- .../src/shared_modules.module.ts | 8 +- .../schemas/transaction_history.schema.ts | 184 ++++++++++++++++++ .../transaction_history.module.ts | 7 + .../transaction_history.service.spec.ts | 18 ++ .../transaction_history.service.ts | 4 + 5 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts create mode 100644 app/libs/shared_modules/src/transaction_history/transaction_history.module.ts create mode 100644 app/libs/shared_modules/src/transaction_history/transaction_history.service.spec.ts create mode 100644 app/libs/shared_modules/src/transaction_history/transaction_history.service.ts diff --git a/app/libs/shared_modules/src/shared_modules.module.ts b/app/libs/shared_modules/src/shared_modules.module.ts index b12ad82..4bf862a 100644 --- a/app/libs/shared_modules/src/shared_modules.module.ts +++ b/app/libs/shared_modules/src/shared_modules.module.ts @@ -3,9 +3,15 @@ import { SharedModulesService } from './shared_modules.service'; import { MonitorModule } from './monitor/monitor.module'; import { ProjectModule } from './project/project.module'; import { WebhookModule } from './webhook/webhook.module'; +import { TransactionHistoryModule } from './transaction_history/transaction_history.module'; @Module({ - imports: [MonitorModule, ProjectModule, WebhookModule], + imports: [ + MonitorModule, + ProjectModule, + WebhookModule, + TransactionHistoryModule, + ], providers: [SharedModulesService], exports: [SharedModulesService, MonitorModule, ProjectModule, WebhookModule], }) diff --git a/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts b/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts new file mode 100644 index 0000000..99f6984 --- /dev/null +++ b/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts @@ -0,0 +1,184 @@ +import { generateWebhookEventId } from '@app/utils/uuidUtils'; +import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; +import { Log, TransactionResponse, ethers } from 'ethers'; +import { HydratedDocument } from 'mongoose'; + +export enum WebhookCategory { + ERC721 = 'ERC721', + Native = 'Native', + ERC20 = 'ERC20', + INTERNAL = 'INTERNAL', +} + +export enum WebhookType { + in = 'in', + out = 'out', +} +@Schema() +export class TransactionHistory { + @Prop({ index: 1 }) + id: string; + + @Prop({ index: 1, unique: true }) + uniqueId: string; // md5 of message exclude timestamp and confirm + + @Prop() + chain: string; + + @Prop({ index: 1 }) + monitorId: string; + + @Prop() + hash: string; + + @Prop() + blockNum: number; // decimal string + + @Prop() + contract: { + address: string; + name: string; + symbol: string; + }; + + @Prop() + fromAddress: string; + + @Prop() + toAddress: string; + + @Prop() + tokenId: string; // decimal string + + @Prop() + tokenValue: string; // decimal string + + @Prop() + nativeAmount: string; // decimal string + + @Prop() + type: WebhookType; + + @Prop() + confirm: boolean; + + @Prop() + category: WebhookCategory; + + @Prop() + rawLog: { + topics: string[]; + data: string; + }; + + @Prop() + logIndex: number; + + @Prop() + txnIndex: number; + + @Prop() + tags: string[]; + + toString(): string { + return JSON.stringify(this); + } + + public static fromLogToERC20( + log: Log, + chain: string, + monitorId: string, + type: WebhookType, + confirm: boolean, + tokenValue: string, + ): TransactionHistory { + const instance = new TransactionHistory(); + instance.id = generateWebhookEventId(); + instance.chain = chain; + instance.monitorId = monitorId; + instance.hash = log.transactionHash; + instance.blockNum = log.blockNumber; + instance.contract = { + address: ethers.getAddress(log.address).toLowerCase(), + name: null, + symbol: null, + }; + instance.fromAddress = log.topics[1].substring(26); + instance.toAddress = log.topics[2].substring(26); + instance.tokenId = '0'; + instance.tokenValue = tokenValue; + instance.nativeAmount = '0'; + instance.rawLog = { + topics: log.topics as string[], + data: log.data, + }; + instance.type = type; + instance.confirm = confirm; + instance.category = WebhookCategory.ERC20; + + return instance; + } + + public static fromLogToERC721( + log: Log, + chain: string, + monitorId: string, + type: WebhookType, + confirm: boolean, + tokenId: string, + ): TransactionHistory { + const instance = new TransactionHistory(); + instance.id = generateWebhookEventId(); + instance.chain = chain; + instance.monitorId = monitorId; + instance.hash = log.transactionHash; + instance.blockNum = log.blockNumber; + instance.contract = { + address: ethers.getAddress(log.address).toLowerCase(), + name: null, + symbol: null, + }; + instance.fromAddress = log.topics[1].substring(26); + instance.toAddress = log.topics[2].substring(26); + instance.tokenId = tokenId; + instance.tokenValue = '0'; + instance.nativeAmount = '0'; + instance.rawLog = { + topics: log.topics as string[], + data: log.data, + }; + instance.type = type; + instance.confirm = confirm; + instance.category = WebhookCategory.ERC721; + + return instance; + } + + public static fromTransactionToNative( + transaction: TransactionResponse, + chain: string, + monitorId: string, + type: WebhookType, + confirm: boolean, + ): TransactionHistory { + const instance = new TransactionHistory(); + instance.id = generateWebhookEventId(); + instance.chain = chain; + instance.monitorId = monitorId; + instance.hash = transaction.hash; + instance.blockNum = transaction.blockNumber; + instance.fromAddress = transaction.from.toLowerCase(); + instance.toAddress = transaction.to.toLowerCase(); + + instance.tokenId = '0'; + instance.tokenValue = '0'; + instance.nativeAmount = transaction.value.toString(); + instance.type = type; + instance.confirm = confirm; + instance.category = WebhookCategory.Native; + return instance; + } +} +export type TransactionHistoryDocument = HydratedDocument; +export const WebhookDeliverySchema = + SchemaFactory.createForClass(TransactionHistory); diff --git a/app/libs/shared_modules/src/transaction_history/transaction_history.module.ts b/app/libs/shared_modules/src/transaction_history/transaction_history.module.ts new file mode 100644 index 0000000..55fc7e2 --- /dev/null +++ b/app/libs/shared_modules/src/transaction_history/transaction_history.module.ts @@ -0,0 +1,7 @@ +import { Module } from '@nestjs/common'; +import { TransactionHistoryService } from './transaction_history.service'; + +@Module({ + providers: [TransactionHistoryService], +}) +export class TransactionHistoryModule {} diff --git a/app/libs/shared_modules/src/transaction_history/transaction_history.service.spec.ts b/app/libs/shared_modules/src/transaction_history/transaction_history.service.spec.ts new file mode 100644 index 0000000..dcb8adf --- /dev/null +++ b/app/libs/shared_modules/src/transaction_history/transaction_history.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { TransactionHistoryService } from './transaction_history.service'; + +describe('TransactionHistoryService', () => { + let service: TransactionHistoryService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [TransactionHistoryService], + }).compile(); + + service = module.get(TransactionHistoryService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/app/libs/shared_modules/src/transaction_history/transaction_history.service.ts b/app/libs/shared_modules/src/transaction_history/transaction_history.service.ts new file mode 100644 index 0000000..86b60ea --- /dev/null +++ b/app/libs/shared_modules/src/transaction_history/transaction_history.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class TransactionHistoryService {} From feefc4db3a9b4d75804a82c6f68a687478cdd332 Mon Sep 17 00:00:00 2001 From: cauta Date: Thu, 18 Apr 2024 11:59:01 +0700 Subject: [PATCH 02/18] update transaction history --- .../transaction_history.repository.ts | 81 ++++++++++++ .../schemas/transaction_history.schema.ts | 123 ++++-------------- .../transaction_history.provider.ts | 15 +++ 3 files changed, 123 insertions(+), 96 deletions(-) create mode 100644 app/libs/shared_modules/src/transaction_history/repositories/transaction_history.repository.ts create mode 100644 app/libs/shared_modules/src/transaction_history/transaction_history.provider.ts diff --git a/app/libs/shared_modules/src/transaction_history/repositories/transaction_history.repository.ts b/app/libs/shared_modules/src/transaction_history/repositories/transaction_history.repository.ts new file mode 100644 index 0000000..3921e41 --- /dev/null +++ b/app/libs/shared_modules/src/transaction_history/repositories/transaction_history.repository.ts @@ -0,0 +1,81 @@ +import { MonitorNetwork } from '@app/shared_modules/monitor/schemas/monitor.schema'; +import { Inject, Injectable } from '@nestjs/common'; +import { Model } from 'mongoose'; +import { TransactionHistory } from '../schemas/transaction_history.schema'; + +export class TransactionHistoryRepository { + static repositories: Map = + new Map(); + + static getRepository(network: MonitorNetwork): TransactionHistoryRepository { + return TransactionHistoryRepository.repositories[network]; + } + + constructor( + network: MonitorNetwork, + private readonly model: Model, + ) { + TransactionHistoryRepository.repositories[network] = this; + } + + async findByUniqueId(uniqueId: string): Promise { + return this.model.findOne({ uniqueId: uniqueId }); + } + + async saveTransactionHistory( + transactionHistory: TransactionHistory, + ): Promise { + return new this.model(transactionHistory).save(); + } + + async findByMonitorAndAssociatedAddress( + monitor: string, + associatedAddress: string, + ): Promise { + return this.model.find({ + monitorId: monitor, + associatedAddress: associatedAddress, + }); + } + + async findByMonitorId(monitorId: string): Promise { + return this.model.find({ monitorId: monitorId }); + } + + async getTransactionHistory( + monitorId: string, + limit: number, + offset: number, + ): Promise { + return this.model + .find({ monitorId: monitorId }) + .limit(limit) + .skip(offset) + .sort({ dateCreated: -1 }); + } + + async findTransactionHistoryByMonitorAndHash( + monitorId: string, + hash: string, + ): Promise { + return this.model.find({ monitorId: monitorId, hash: hash }); + } +} + +@Injectable() +export class EthTransactionHistoryRepository extends TransactionHistoryRepository { + constructor( + @Inject('ETH_TRANSACTION_HISTORY_MODEL') model: Model, + ) { + super(MonitorNetwork.Ethereum, model); + } +} + +@Injectable() +export class BscTransactionHistoryRepository extends TransactionHistoryRepository { + constructor( + @Inject('BSC_TRANSACTION_HISTORY_MODEL') model: Model, + ) { + super(MonitorNetwork.BSC, model); + } +} diff --git a/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts b/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts index 99f6984..1db84bd 100644 --- a/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts +++ b/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts @@ -1,3 +1,4 @@ +import { hashMd5 } from '@app/utils/md5'; import { generateWebhookEventId } from '@app/utils/uuidUtils'; import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Log, TransactionResponse, ethers } from 'ethers'; @@ -16,9 +17,6 @@ export enum WebhookType { } @Schema() export class TransactionHistory { - @Prop({ index: 1 }) - id: string; - @Prop({ index: 1, unique: true }) uniqueId: string; // md5 of message exclude timestamp and confirm @@ -28,6 +26,9 @@ export class TransactionHistory { @Prop({ index: 1 }) monitorId: string; + @Prop() + associatedAddress: string; + @Prop() hash: string; @@ -80,105 +81,35 @@ export class TransactionHistory { @Prop() tags: string[]; + @Prop({ required: true, index: -1 }) + dateCreated: Date; + toString(): string { return JSON.stringify(this); } - public static fromLogToERC20( - log: Log, - chain: string, - monitorId: string, - type: WebhookType, - confirm: boolean, - tokenValue: string, - ): TransactionHistory { - const instance = new TransactionHistory(); - instance.id = generateWebhookEventId(); - instance.chain = chain; - instance.monitorId = monitorId; - instance.hash = log.transactionHash; - instance.blockNum = log.blockNumber; - instance.contract = { - address: ethers.getAddress(log.address).toLowerCase(), - name: null, - symbol: null, - }; - instance.fromAddress = log.topics[1].substring(26); - instance.toAddress = log.topics[2].substring(26); - instance.tokenId = '0'; - instance.tokenValue = tokenValue; - instance.nativeAmount = '0'; - instance.rawLog = { - topics: log.topics as string[], - data: log.data, - }; - instance.type = type; - instance.confirm = confirm; - instance.category = WebhookCategory.ERC20; - - return instance; - } - - public static fromLogToERC721( - log: Log, - chain: string, - monitorId: string, - type: WebhookType, - confirm: boolean, - tokenId: string, - ): TransactionHistory { - const instance = new TransactionHistory(); - instance.id = generateWebhookEventId(); - instance.chain = chain; - instance.monitorId = monitorId; - instance.hash = log.transactionHash; - instance.blockNum = log.blockNumber; - instance.contract = { - address: ethers.getAddress(log.address).toLowerCase(), - name: null, - symbol: null, - }; - instance.fromAddress = log.topics[1].substring(26); - instance.toAddress = log.topics[2].substring(26); - instance.tokenId = tokenId; - instance.tokenValue = '0'; - instance.nativeAmount = '0'; - instance.rawLog = { - topics: log.topics as string[], - data: log.data, + generateUniqueId(): string { + const data = { + chain: this.chain, + monitorId: this.monitorId, + associatedAddress: this.associatedAddress, + hash: this.hash, + blockNum: this.blockNum, + contract: this.contract, + fromAddress: this.fromAddress, + toAddress: this.toAddress, + tokenId: this.tokenId, + tokenValue: this.tokenValue, + nativeAmount: this.nativeAmount, + type: this.type, + category: this.category, + rawLog: this.rawLog, + logIndex: this.logIndex, + txnIndex: this.txnIndex, }; - instance.type = type; - instance.confirm = confirm; - instance.category = WebhookCategory.ERC721; - - return instance; - } - - public static fromTransactionToNative( - transaction: TransactionResponse, - chain: string, - monitorId: string, - type: WebhookType, - confirm: boolean, - ): TransactionHistory { - const instance = new TransactionHistory(); - instance.id = generateWebhookEventId(); - instance.chain = chain; - instance.monitorId = monitorId; - instance.hash = transaction.hash; - instance.blockNum = transaction.blockNumber; - instance.fromAddress = transaction.from.toLowerCase(); - instance.toAddress = transaction.to.toLowerCase(); - - instance.tokenId = '0'; - instance.tokenValue = '0'; - instance.nativeAmount = transaction.value.toString(); - instance.type = type; - instance.confirm = confirm; - instance.category = WebhookCategory.Native; - return instance; + return hashMd5(JSON.stringify(data)); } } export type TransactionHistoryDocument = HydratedDocument; -export const WebhookDeliverySchema = +export const TransactionHistorySchema = SchemaFactory.createForClass(TransactionHistory); diff --git a/app/libs/shared_modules/src/transaction_history/transaction_history.provider.ts b/app/libs/shared_modules/src/transaction_history/transaction_history.provider.ts new file mode 100644 index 0000000..2c53c98 --- /dev/null +++ b/app/libs/shared_modules/src/transaction_history/transaction_history.provider.ts @@ -0,0 +1,15 @@ +import { Connection } from 'mongoose'; +import { TransactionHistorySchema } from './schemas/transaction_history.schema'; + +export const TransactionHistoryProviders = [ + { + provide: 'ETH_TRANSACTION_HISTORY_MODEL', + useFactory: (connection: Connection) => + connection.model( + 'EthTransactionHistory', + TransactionHistorySchema, + 'eth_transaction_history', + ), + inject: ['DATABASE_CONNECTION'], + }, +]; From c35d48e66515dbb576aa7c93b2935e94c54f7feb Mon Sep 17 00:00:00 2001 From: cauta Date: Thu, 18 Apr 2024 16:05:41 +0700 Subject: [PATCH 03/18] fix dispatch to any message --- app/libs/shared_modules/src/webhook/webhook.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/libs/shared_modules/src/webhook/webhook.service.ts b/app/libs/shared_modules/src/webhook/webhook.service.ts index 0f0c45a..391ce44 100644 --- a/app/libs/shared_modules/src/webhook/webhook.service.ts +++ b/app/libs/shared_modules/src/webhook/webhook.service.ts @@ -163,7 +163,7 @@ export class WebhookService { */ async dispatchMessage( webhookId: string, - body: WebhookDeliveryDto, + body: any, ): Promise { try { const response = await sendPost(`${this.webhookUrl}/v1/deliveries`, { From db40de4687c767dd6e2e15b4a6fb0033bde38290 Mon Sep 17 00:00:00 2001 From: cauta Date: Thu, 18 Apr 2024 16:06:13 +0700 Subject: [PATCH 04/18] update transaction history repository --- .../transaction_history.repository.ts | 15 +- .../schemas/transaction_history.schema.ts | 129 +++++++++++++++++- .../transaction_history.module.ts | 19 ++- .../transaction_history.provider.ts | 10 ++ 4 files changed, 161 insertions(+), 12 deletions(-) diff --git a/app/libs/shared_modules/src/transaction_history/repositories/transaction_history.repository.ts b/app/libs/shared_modules/src/transaction_history/repositories/transaction_history.repository.ts index 3921e41..a364535 100644 --- a/app/libs/shared_modules/src/transaction_history/repositories/transaction_history.repository.ts +++ b/app/libs/shared_modules/src/transaction_history/repositories/transaction_history.repository.ts @@ -38,10 +38,6 @@ export class TransactionHistoryRepository { }); } - async findByMonitorId(monitorId: string): Promise { - return this.model.find({ monitorId: monitorId }); - } - async getTransactionHistory( monitorId: string, limit: number, @@ -60,6 +56,17 @@ export class TransactionHistoryRepository { ): Promise { return this.model.find({ monitorId: monitorId, hash: hash }); } + + async pushDeliveryId(id: string, deliveryId: string) { + return this.model.updateOne( + { uniqueId: id }, + { + $push: { + deliveryIds: deliveryId, + }, + }, + ); + } } @Injectable() diff --git a/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts b/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts index 1db84bd..ff9020f 100644 --- a/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts +++ b/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts @@ -1,5 +1,4 @@ import { hashMd5 } from '@app/utils/md5'; -import { generateWebhookEventId } from '@app/utils/uuidUtils'; import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'; import { Log, TransactionResponse, ethers } from 'ethers'; import { HydratedDocument } from 'mongoose'; @@ -17,13 +16,13 @@ export enum WebhookType { } @Schema() export class TransactionHistory { - @Prop({ index: 1, unique: true }) + @Prop({ required: true, unique: true }) uniqueId: string; // md5 of message exclude timestamp and confirm @Prop() chain: string; - @Prop({ index: 1 }) + @Prop({ required: true, index: 1 }) monitorId: string; @Prop() @@ -35,7 +34,7 @@ export class TransactionHistory { @Prop() blockNum: number; // decimal string - @Prop() + @Prop({ type: Object }) contract: { address: string; name: string; @@ -66,7 +65,7 @@ export class TransactionHistory { @Prop() category: WebhookCategory; - @Prop() + @Prop({ type: Object }) rawLog: { topics: string[]; data: string; @@ -84,11 +83,14 @@ export class TransactionHistory { @Prop({ required: true, index: -1 }) dateCreated: Date; + @Prop() + deliveryIds: string[]; + toString(): string { return JSON.stringify(this); } - generateUniqueId(): string { + private generateId(): string { const data = { chain: this.chain, monitorId: this.monitorId, @@ -109,6 +111,121 @@ export class TransactionHistory { }; return hashMd5(JSON.stringify(data)); } + + public static fromLogToERC20( + log: Log, + chain: string, + monitorId: string, + type: WebhookType, + confirm: boolean, + tokenValue: string, + ): TransactionHistory { + const instance = new TransactionHistory(); + instance.chain = chain; + instance.monitorId = monitorId; + instance.hash = log.transactionHash; + instance.blockNum = log.blockNumber; + instance.contract = { + address: ethers.getAddress(log.address).toLowerCase(), + name: null, + symbol: null, + }; + instance.fromAddress = log.topics[1].substring(26); + instance.toAddress = log.topics[2].substring(26); + instance.tokenId = '0'; + instance.tokenValue = tokenValue; + instance.nativeAmount = '0'; + instance.rawLog = { + topics: log.topics as string[], + data: log.data, + }; + instance.type = type; + instance.confirm = confirm; + instance.category = WebhookCategory.ERC20; + instance.dateCreated = new Date(); + if (type === WebhookType.out) { + instance.associatedAddress = instance.fromAddress; + } + if (type === WebhookType.in) { + instance.associatedAddress = instance.toAddress; + } + instance.uniqueId = instance.generateId(); + return instance; + } + + public static fromLogToERC721( + log: Log, + chain: string, + monitorId: string, + type: WebhookType, + confirm: boolean, + tokenId: string, + ): TransactionHistory { + const instance = new TransactionHistory(); + instance.chain = chain; + instance.monitorId = monitorId; + instance.hash = log.transactionHash; + instance.blockNum = log.blockNumber; + instance.contract = { + address: ethers.getAddress(log.address).toLowerCase(), + name: null, + symbol: null, + }; + instance.fromAddress = log.topics[1].substring(26); + instance.toAddress = log.topics[2].substring(26); + instance.tokenId = tokenId; + instance.tokenValue = '0'; + instance.nativeAmount = '0'; + instance.rawLog = { + topics: log.topics as string[], + data: log.data, + }; + instance.type = type; + instance.confirm = confirm; + instance.category = WebhookCategory.ERC721; + instance.dateCreated = new Date(); + if (type === WebhookType.out) { + instance.associatedAddress = instance.fromAddress; + } + if (type === WebhookType.in) { + instance.associatedAddress = instance.toAddress; + } + instance.uniqueId = instance.generateId(); + return instance; + } + + public static fromTransactionToNative( + transaction: TransactionResponse, + chain: string, + monitorId: string, + type: WebhookType, + confirm: boolean, + ): TransactionHistory { + const instance = new TransactionHistory(); + instance.chain = chain; + instance.monitorId = monitorId; + instance.hash = transaction.hash; + instance.blockNum = transaction.blockNumber; + instance.fromAddress = transaction.from.toLowerCase(); + instance.toAddress = transaction.to.toLowerCase(); + + instance.tokenId = '0'; + instance.tokenValue = '0'; + instance.nativeAmount = transaction.value.toString(); + instance.type = type; + instance.confirm = confirm; + instance.category = WebhookCategory.Native; + instance.dateCreated = new Date(); + // @todo assign data from transaction data + if (type === WebhookType.out) { + instance.associatedAddress = instance.fromAddress; + } + if (type === WebhookType.in) { + instance.associatedAddress = instance.toAddress; + } + instance.uniqueId = instance.generateId(); + return instance; + } } export type TransactionHistoryDocument = HydratedDocument; export const TransactionHistorySchema = diff --git a/app/libs/shared_modules/src/transaction_history/transaction_history.module.ts b/app/libs/shared_modules/src/transaction_history/transaction_history.module.ts index 55fc7e2..c46de41 100644 --- a/app/libs/shared_modules/src/transaction_history/transaction_history.module.ts +++ b/app/libs/shared_modules/src/transaction_history/transaction_history.module.ts @@ -1,7 +1,22 @@ +import { DatabaseModule } from '@app/database'; import { Module } from '@nestjs/common'; -import { TransactionHistoryService } from './transaction_history.service'; +import { + BscTransactionHistoryRepository, + EthTransactionHistoryRepository, +} from './repositories/transaction_history.repository'; +import { TransactionHistoryProviders } from './transaction_history.provider'; @Module({ - providers: [TransactionHistoryService], + imports: [DatabaseModule], + providers: [ + ...TransactionHistoryProviders, + EthTransactionHistoryRepository, + BscTransactionHistoryRepository, + ], + exports: [ + ...TransactionHistoryProviders, + EthTransactionHistoryRepository, + BscTransactionHistoryRepository, + ], }) export class TransactionHistoryModule {} diff --git a/app/libs/shared_modules/src/transaction_history/transaction_history.provider.ts b/app/libs/shared_modules/src/transaction_history/transaction_history.provider.ts index 2c53c98..a348180 100644 --- a/app/libs/shared_modules/src/transaction_history/transaction_history.provider.ts +++ b/app/libs/shared_modules/src/transaction_history/transaction_history.provider.ts @@ -12,4 +12,14 @@ export const TransactionHistoryProviders = [ ), inject: ['DATABASE_CONNECTION'], }, + { + provide: 'BSC_TRANSACTION_HISTORY_MODEL', + useFactory: (connection: Connection) => + connection.model( + 'BscTransactionHistory', + TransactionHistorySchema, + 'bsc_transaction_history', + ), + inject: ['DATABASE_CONNECTION'], + }, ]; From 508a3c8448a509e7bcbb3455bda9df764de6828c Mon Sep 17 00:00:00 2001 From: cauta Date: Thu, 18 Apr 2024 16:06:23 +0700 Subject: [PATCH 05/18] update ethereum service --- .../src/ethereum/ethereum.module.ts | 2 + .../src/ethereum/ethereum.service.ts | 61 ++++++++++++++----- 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/app/apps/monitor-service/src/ethereum/ethereum.module.ts b/app/apps/monitor-service/src/ethereum/ethereum.module.ts index 96cb0ef..bce8c9a 100644 --- a/app/apps/monitor-service/src/ethereum/ethereum.module.ts +++ b/app/apps/monitor-service/src/ethereum/ethereum.module.ts @@ -5,6 +5,7 @@ import { ClientsModule, Transport } from '@nestjs/microservices'; import { EthereumController } from './ethereum.controller'; import { EthereumService } from './ethereum.service'; import { ProjectModule } from '@app/shared_modules/project/project.module'; +import { TransactionHistoryModule } from '@app/shared_modules/transaction_history/transaction_history.module'; @Module({ providers: [EthereumService], @@ -31,6 +32,7 @@ import { ProjectModule } from '@app/shared_modules/project/project.module'; WebhookModule, MonitorModule, ProjectModule, + TransactionHistoryModule, ], }) export class EthereumModule {} diff --git a/app/apps/monitor-service/src/ethereum/ethereum.service.ts b/app/apps/monitor-service/src/ethereum/ethereum.service.ts index eea247b..3a634b2 100644 --- a/app/apps/monitor-service/src/ethereum/ethereum.service.ts +++ b/app/apps/monitor-service/src/ethereum/ethereum.service.ts @@ -7,15 +7,20 @@ import { WebhookNotification, } from '@app/shared_modules/monitor/schemas/monitor.schema'; import { ProjectQuotaService } from '@app/shared_modules/project/services/project.quota.service'; -import { WebhookService } from '@app/shared_modules/webhook/webhook.service'; +import { + DispatchWebhookResponse, + WebhookService, +} from '@app/shared_modules/webhook/webhook.service'; import { SupportedChain } from '@app/utils/supportedChain.util'; import { Inject, Injectable, Logger } from '@nestjs/common'; import { ClientKafka } from '@nestjs/microservices'; import { ethers, Log, TransactionResponse } from 'ethers'; +import { EthTransactionHistoryRepository } from '@app/shared_modules/transaction_history/repositories/transaction_history.repository'; import { - WebhookDeliveryDto, + TransactionHistory, WebhookType, -} from './dto/eth.webhook-delivery.dto'; +} from '@app/shared_modules/transaction_history/schemas/transaction_history.schema'; +import { response } from 'express'; @Injectable() export class EthereumService { @@ -36,6 +41,9 @@ export class EthereumService { @Inject() private readonly projectQuotaService: ProjectQuotaService; + @Inject() + private readonly transactionHistoryRepository: EthTransactionHistoryRepository; + async findEthAddress(address: string): Promise { return this.ethMonitorAddressRepository.findByAddress(address); } @@ -134,7 +142,7 @@ export class EthereumService { ]); // return if value is zero - if (transaction.value.toString() === '0') { + if (transaction.value == 0n) { return; } @@ -185,7 +193,7 @@ export class EthereumService { continue; } - const body = WebhookDeliveryDto.fromTransactionToNative( + const txnHistory = TransactionHistory.fromTransactionToNative( transaction, SupportedChain.ETH.name, monitor.monitorId, @@ -193,10 +201,11 @@ export class EthereumService { confirm, ); - await this.dispathMessageToWebhook(monitor, body); + const response = await this.dispathMessageToWebhook(monitor, txnHistory); + this.saveHistory(txnHistory, response); this.logger.debug( - `Confirmed: ${confirm} native transfer:\n${JSON.stringify(body)}`, + `Confirmed: ${confirm} native transfer:\n${JSON.stringify(txnHistory)}`, ); } } @@ -222,7 +231,7 @@ export class EthereumService { continue; } // @todo check condition on specific cryptos - const body = WebhookDeliveryDto.fromLogToERC721( + const transaction = TransactionHistory.fromLogToERC721( event, SupportedChain.ETH.name, monitor.monitorId, @@ -231,11 +240,12 @@ export class EthereumService { tokenId, ); - await this.dispathMessageToWebhook(monitor, body); + const response = await this.dispathMessageToWebhook(monitor, transaction); + this.saveHistory(transaction, response); this.logger.debug( `Confirmed: ${confirm} ERC721 transfer ${type.toUpperCase()}:\n${JSON.stringify( - body, + transaction, )}`, ); } @@ -262,7 +272,7 @@ export class EthereumService { continue; } // @todo check condition on specific cryptos - const body = WebhookDeliveryDto.fromLogToERC20( + const txnHistory = TransactionHistory.fromLogToERC20( event, SupportedChain.ETH.name, monitor.monitorId, @@ -271,17 +281,35 @@ export class EthereumService { value, ); - await this.dispathMessageToWebhook(monitor, body); + const response = await this.dispathMessageToWebhook(monitor, txnHistory); + this.saveHistory(txnHistory, response); this.logger.debug( `Confirmed: ${confirm} ERC20 transfer ${type.toUpperCase()}:\n${JSON.stringify( - body, + txnHistory, )}`, ); } } - private async sendMessage(monitor: Monitor, body: WebhookDeliveryDto) { + private async saveHistory( + transaction: TransactionHistory, + delivery: DispatchWebhookResponse, + ) { + if (!transaction.confirm) { + transaction.deliveryIds = [delivery.id]; + await this.transactionHistoryRepository.saveTransactionHistory( + transaction, + ); + } else { + this.transactionHistoryRepository.pushDeliveryId( + transaction.uniqueId, + delivery.id, + ); + } + } + + private async sendMessage(monitor: Monitor, body: TransactionHistory) { if (!monitor.notification) { return; } @@ -312,8 +340,8 @@ export class EthereumService { private async dispathMessageToWebhook( monitor: Monitor, - body: WebhookDeliveryDto, - ) { + body: TransactionHistory, + ): Promise { if (!monitor.notification) { return; } @@ -328,6 +356,7 @@ export class EthereumService { `Dispatch webhook successfully response: ${JSON.stringify(respone)}`, ); this.projectQuotaService.increaseUsed(monitor.projectId); + return respone; } catch (error) { this.logger.error( `Error while sending webhook request to: ${webhook.url}`, From c85516183784d561b9382747a4ddf1369abd1f13 Mon Sep 17 00:00:00 2001 From: cauta Date: Thu, 18 Apr 2024 16:06:31 +0700 Subject: [PATCH 06/18] update wehbook dto --- .../monitor-service/src/ethereum/dto/eth.webhook-delivery.dto.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/apps/monitor-service/src/ethereum/dto/eth.webhook-delivery.dto.ts b/app/apps/monitor-service/src/ethereum/dto/eth.webhook-delivery.dto.ts index eea21e6..de1cca0 100644 --- a/app/apps/monitor-service/src/ethereum/dto/eth.webhook-delivery.dto.ts +++ b/app/apps/monitor-service/src/ethereum/dto/eth.webhook-delivery.dto.ts @@ -18,6 +18,7 @@ export class WebhookDeliveryDto { monitorId: string; hash: string; blockNum: number; // decimal string + associatedAddress: string; contract: { address: string; name: string; From 8f13f917bea0c1523e5fa774fd01f8c4b861add9 Mon Sep 17 00:00:00 2001 From: cauta Date: Thu, 18 Apr 2024 12:00:25 +0700 Subject: [PATCH 07/18] fix broken block when getting error in block or log --- .../src/worker/ethereum.worker.ts | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/app/apps/worker-service/src/worker/ethereum.worker.ts b/app/apps/worker-service/src/worker/ethereum.worker.ts index 2267971..82dc221 100644 --- a/app/apps/worker-service/src/worker/ethereum.worker.ts +++ b/app/apps/worker-service/src/worker/ethereum.worker.ts @@ -1,6 +1,6 @@ import { Inject, Injectable, Logger } from '@nestjs/common'; import { ClientKafka } from '@nestjs/microservices'; -import { ethers } from 'ethers'; +import { Block, ethers, Log } from 'ethers'; import { TopicName } from '@app/utils/topicUtils'; @Injectable() @@ -23,10 +23,22 @@ export class EthereumWorker { try { this.logger.log(`DETECT handle block ${blockNumber}`); + // Retrieve all transaction in block + const block = await this.provider.getBlock(blockNumber, true); + + // Retrieve transfer event the block's logs + const logs = await this.provider.getLogs({ + fromBlock: blockNumber, + toBlock: blockNumber, + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + ], + }); + // handle native transfer - this.handleNativeTransfer(blockNumber, false); + this.emitNativeTransaction(block, false); // handle extracted event for erc20 and nft - this.handleLog(blockNumber, false); + this.emitLog(logs, false); //only update last sync for confirm // await this.updateLastSyncBlock(blockNumber); } catch (error) { @@ -45,10 +57,20 @@ export class EthereumWorker { const blockNumber = data.blockNumber; try { this.logger.log(`CONFIRM Scanning block ${blockNumber}`); + // Retrieve all transaction in block + const block = await this.provider.getBlock(blockNumber, true); + // Retrieve transfer event the block's logs + const logs = await this.provider.getLogs({ + fromBlock: blockNumber, + toBlock: blockNumber, + topics: [ + '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', + ], + }); // handle native transfer - this.handleNativeTransfer(blockNumber, true); + this.emitNativeTransaction(block, true); // handle extracted event for erc20 and nft - this.handleLog(blockNumber, true); + this.emitLog(logs, true); } catch (error) { this.logger.error([ 'CONFIRM', @@ -59,19 +81,7 @@ export class EthereumWorker { return; } - private async handleLog( - blockNumber: number, - confirm: boolean, - ): Promise { - // Retrieve transfer event the block's logs - const logs = await this.provider.getLogs({ - fromBlock: blockNumber, - toBlock: blockNumber, - topics: [ - '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef', - ], - }); - + private async emitLog(logs: Log[], confirm: boolean): Promise { // handle extracted event for erc20 and nft logs.forEach((event) => { if (event.topics.length === 3) { @@ -90,13 +100,10 @@ export class EthereumWorker { }); } - private async handleNativeTransfer( - blockNumber: number, + private async emitNativeTransaction( + block: Block, confirm: boolean, ): Promise { - // Retrieve all transaction in block - const block = await this.provider.getBlock(blockNumber, true); - // handle extracted event for native block.prefetchedTransactions.forEach((transaction) => { this.logger.debug(`emit event on NATIVE ${JSON.stringify(transaction)}`); From 95413c514ab88510212196f587bd2eb713e9f7a1 Mon Sep 17 00:00:00 2001 From: "thong.nguyen5" Date: Thu, 18 Apr 2024 21:53:50 +0700 Subject: [PATCH 08/18] CRYP-46 Optimize project quota counting --- .../project/services/project.quota.service.ts | 39 ++++++++++++++++++- app/package.json | 1 + app/yarn.lock | 12 ++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/app/libs/shared_modules/src/project/services/project.quota.service.ts b/app/libs/shared_modules/src/project/services/project.quota.service.ts index f64d9d6..f090a52 100644 --- a/app/libs/shared_modules/src/project/services/project.quota.service.ts +++ b/app/libs/shared_modules/src/project/services/project.quota.service.ts @@ -1,16 +1,42 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, Logger } from '@nestjs/common'; import { ProjectQuotaRepository } from '../repositories/project.quota.repository'; import { ProjectRepository } from '../repositories/project.repository'; import { ProjectQuota } from '../schemas/project.schema'; +import NodeCache = require('node-cache'); @Injectable() export class ProjectQuotaService { + private cache: NodeCache; constructor( private readonly projectQuotaRepository: ProjectQuotaRepository, private readonly projectRepository: ProjectRepository, - ) {} + ) { + this.cache = new NodeCache({ + stdTTL: 60, + checkperiod: 60, + useClones: false, + }); + this.cache.on('expired', (_, value) => { + this.increaseUsedInDB(value.projectId, value.used); + Logger.debug('Cache stats: ', this.cache.stats); + }); + } async increaseUsed(projectId: string, used = 1): Promise { + const minute = (new Date().getTime() / 1000 / 60).toFixed(0); + const cacheKey = projectId + '_' + minute; + let cache: ProjectQuotaCache = this.cache.get(cacheKey); + if (!cache) { + cache = new ProjectQuotaCache(projectId, 0); + this.cache.set(cacheKey, cache); + } + cache.used += used; + Logger.log(`Project Quota cache ${cacheKey}: ${JSON.stringify(cache)}`); + return true; + } + + async increaseUsedInDB(projectId: string, used = 1): Promise { + Logger.log(`increaseUsedInDB: ${projectId}-${used}`); const project = await this.projectRepository.findById(projectId); if (!project) return false; return this.projectQuotaRepository.increaseUsed(project, used); @@ -20,3 +46,12 @@ export class ProjectQuotaService { return this.projectQuotaRepository.getCurrentMonthQuota(projectId); } } + +class ProjectQuotaCache { + projectId: string; + used: number; + constructor(projectId: string, used: number) { + this.projectId = projectId; + this.used = used; + } +} diff --git a/app/package.json b/app/package.json index 38561da..5b0b10e 100644 --- a/app/package.json +++ b/app/package.json @@ -46,6 +46,7 @@ "express-basic-auth": "^1.2.1", "kafkajs": "^2.2.4", "mongoose": "^8.2.2", + "node-cache": "^5.1.2", "nodemailer": "^6.9.12", "passport": "^0.7.0", "passport-facebook": "^3.0.0", diff --git a/app/yarn.lock b/app/yarn.lock index 185ac5c..5f75dcd 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -2120,6 +2120,11 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" +clone@2.x: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== + clone@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" @@ -4393,6 +4398,13 @@ node-addon-api@^5.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== +node-cache@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/node-cache/-/node-cache-5.1.2.tgz#f264dc2ccad0a780e76253a694e9fd0ed19c398d" + integrity sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg== + dependencies: + clone "2.x" + node-emoji@1.11.0: version "1.11.0" resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.11.0.tgz#69a0150e6946e2f115e9d7ea4df7971e2628301c" From 2e626ec7c696a909b4bc523601b137755961089d Mon Sep 17 00:00:00 2001 From: cauta Date: Fri, 19 Apr 2024 09:53:08 +0700 Subject: [PATCH 09/18] set get block number timeout --- .../src/polling.block/polling.block.service.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/apps/onebox/src/polling.block/polling.block.service.ts b/app/apps/onebox/src/polling.block/polling.block.service.ts index 89c221d..38205d4 100644 --- a/app/apps/onebox/src/polling.block/polling.block.service.ts +++ b/app/apps/onebox/src/polling.block/polling.block.service.ts @@ -145,7 +145,13 @@ export class PollingBlockService { private async getBlockNumber(): Promise { try { - const blockNumber = await this.provider.getBlockNumber(); + // Perform an asynchronous operation (e.g., fetching data) + const blockNumber = await Promise.race([ + this.provider.getBlockNumber(), // Your asynchronous operation + delay(5000).then(() => { + throw new Error('Get block number Timeout'); + }), // Timeout promise + ]); this.logger.log('got latest block from network: ' + blockNumber); return blockNumber; } catch (error) { @@ -154,3 +160,9 @@ export class PollingBlockService { return 0; } } + +function delay(ms: number) { + return new Promise((resolve) => { + setTimeout(resolve, ms); + }); +} From da805df263272c6b96cd3c2d6fd5cc291765cde3 Mon Sep 17 00:00:00 2001 From: cauta Date: Fri, 19 Apr 2024 10:48:48 +0700 Subject: [PATCH 10/18] migrate transaction history to event history --- .../src/ethereum/ethereum.module.ts | 6 +- .../src/ethereum/ethereum.service.ts | 34 ++++--- .../src/event_history/event_history.module.ts | 22 +++++ .../event_history/event_history.provider.ts | 25 ++++++ .../event_history.service.spec.ts | 18 ++++ .../event_history.service.ts} | 2 +- .../repositories/event_history.repository.ts | 81 +++++++++++++++++ .../schemas/event_history.schema.ts} | 27 +++--- .../src/shared_modules.module.ts | 9 +- .../transaction_history.repository.ts | 88 ------------------- .../transaction_history.module.ts | 22 ----- .../transaction_history.provider.ts | 25 ------ .../transaction_history.service.spec.ts | 18 ---- 13 files changed, 181 insertions(+), 196 deletions(-) create mode 100644 app/libs/shared_modules/src/event_history/event_history.module.ts create mode 100644 app/libs/shared_modules/src/event_history/event_history.provider.ts create mode 100644 app/libs/shared_modules/src/event_history/event_history.service.spec.ts rename app/libs/shared_modules/src/{transaction_history/transaction_history.service.ts => event_history/event_history.service.ts} (58%) create mode 100644 app/libs/shared_modules/src/event_history/repositories/event_history.repository.ts rename app/libs/shared_modules/src/{transaction_history/schemas/transaction_history.schema.ts => event_history/schemas/event_history.schema.ts} (89%) delete mode 100644 app/libs/shared_modules/src/transaction_history/repositories/transaction_history.repository.ts delete mode 100644 app/libs/shared_modules/src/transaction_history/transaction_history.module.ts delete mode 100644 app/libs/shared_modules/src/transaction_history/transaction_history.provider.ts delete mode 100644 app/libs/shared_modules/src/transaction_history/transaction_history.service.spec.ts diff --git a/app/apps/monitor-service/src/ethereum/ethereum.module.ts b/app/apps/monitor-service/src/ethereum/ethereum.module.ts index bce8c9a..e3c6341 100644 --- a/app/apps/monitor-service/src/ethereum/ethereum.module.ts +++ b/app/apps/monitor-service/src/ethereum/ethereum.module.ts @@ -1,11 +1,11 @@ +import { EventHistoryModule } from '@app/shared_modules/event_history/event_history.module'; import { MonitorModule } from '@app/shared_modules/monitor/monitor.module'; +import { ProjectModule } from '@app/shared_modules/project/project.module'; import { WebhookModule } from '@app/shared_modules/webhook/webhook.module'; import { Module } from '@nestjs/common'; import { ClientsModule, Transport } from '@nestjs/microservices'; import { EthereumController } from './ethereum.controller'; import { EthereumService } from './ethereum.service'; -import { ProjectModule } from '@app/shared_modules/project/project.module'; -import { TransactionHistoryModule } from '@app/shared_modules/transaction_history/transaction_history.module'; @Module({ providers: [EthereumService], @@ -32,7 +32,7 @@ import { TransactionHistoryModule } from '@app/shared_modules/transaction_histor WebhookModule, MonitorModule, ProjectModule, - TransactionHistoryModule, + EventHistoryModule, ], }) export class EthereumModule {} diff --git a/app/apps/monitor-service/src/ethereum/ethereum.service.ts b/app/apps/monitor-service/src/ethereum/ethereum.service.ts index 3a634b2..af36e14 100644 --- a/app/apps/monitor-service/src/ethereum/ethereum.service.ts +++ b/app/apps/monitor-service/src/ethereum/ethereum.service.ts @@ -1,3 +1,8 @@ +import { EthEventHistoryRepository } from '@app/shared_modules/event_history/repositories/event_history.repository'; +import { + EventHistory, + WebhookType, +} from '@app/shared_modules/event_history/schemas/event_history.schema'; import { EthMonitorAddressRepository } from '@app/shared_modules/monitor/repositories/monitor.address.repository'; import { MonitorRepository } from '@app/shared_modules/monitor/repositories/monitor.repository'; import { MonitorAddress } from '@app/shared_modules/monitor/schemas/monitor.address.schema'; @@ -15,12 +20,6 @@ import { SupportedChain } from '@app/utils/supportedChain.util'; import { Inject, Injectable, Logger } from '@nestjs/common'; import { ClientKafka } from '@nestjs/microservices'; import { ethers, Log, TransactionResponse } from 'ethers'; -import { EthTransactionHistoryRepository } from '@app/shared_modules/transaction_history/repositories/transaction_history.repository'; -import { - TransactionHistory, - WebhookType, -} from '@app/shared_modules/transaction_history/schemas/transaction_history.schema'; -import { response } from 'express'; @Injectable() export class EthereumService { @@ -42,7 +41,7 @@ export class EthereumService { private readonly projectQuotaService: ProjectQuotaService; @Inject() - private readonly transactionHistoryRepository: EthTransactionHistoryRepository; + private readonly eventHistoryRepository: EthEventHistoryRepository; async findEthAddress(address: string): Promise { return this.ethMonitorAddressRepository.findByAddress(address); @@ -193,7 +192,7 @@ export class EthereumService { continue; } - const txnHistory = TransactionHistory.fromTransactionToNative( + const txnHistory = EventHistory.fromTransactionToNative( transaction, SupportedChain.ETH.name, monitor.monitorId, @@ -231,7 +230,7 @@ export class EthereumService { continue; } // @todo check condition on specific cryptos - const transaction = TransactionHistory.fromLogToERC721( + const transaction = EventHistory.fromLogToERC721( event, SupportedChain.ETH.name, monitor.monitorId, @@ -272,7 +271,7 @@ export class EthereumService { continue; } // @todo check condition on specific cryptos - const txnHistory = TransactionHistory.fromLogToERC20( + const txnHistory = EventHistory.fromLogToERC20( event, SupportedChain.ETH.name, monitor.monitorId, @@ -293,23 +292,22 @@ export class EthereumService { } private async saveHistory( - transaction: TransactionHistory, + transaction: EventHistory, delivery: DispatchWebhookResponse, ) { + // @todo handle when dispatch message to webhook service if (!transaction.confirm) { transaction.deliveryIds = [delivery.id]; - await this.transactionHistoryRepository.saveTransactionHistory( - transaction, - ); + await this.eventHistoryRepository.saveEventHistory(transaction); } else { - this.transactionHistoryRepository.pushDeliveryId( - transaction.uniqueId, + this.eventHistoryRepository.pushDeliveryId( + transaction.eventId, delivery.id, ); } } - private async sendMessage(monitor: Monitor, body: TransactionHistory) { + private async sendMessage(monitor: Monitor, body: EventHistory) { if (!monitor.notification) { return; } @@ -340,7 +338,7 @@ export class EthereumService { private async dispathMessageToWebhook( monitor: Monitor, - body: TransactionHistory, + body: EventHistory, ): Promise { if (!monitor.notification) { return; diff --git a/app/libs/shared_modules/src/event_history/event_history.module.ts b/app/libs/shared_modules/src/event_history/event_history.module.ts new file mode 100644 index 0000000..405b7fe --- /dev/null +++ b/app/libs/shared_modules/src/event_history/event_history.module.ts @@ -0,0 +1,22 @@ +import { DatabaseModule } from '@app/database'; +import { Module } from '@nestjs/common'; +import { + BscEventHistoryRepository, + EthEventHistoryRepository, +} from './repositories/event_history.repository'; +import { EventHistoryProviders } from './event_history.provider'; + +@Module({ + imports: [DatabaseModule], + providers: [ + ...EventHistoryProviders, + EthEventHistoryRepository, + BscEventHistoryRepository, + ], + exports: [ + ...EventHistoryProviders, + EthEventHistoryRepository, + BscEventHistoryRepository, + ], +}) +export class EventHistoryModule {} diff --git a/app/libs/shared_modules/src/event_history/event_history.provider.ts b/app/libs/shared_modules/src/event_history/event_history.provider.ts new file mode 100644 index 0000000..c7176ea --- /dev/null +++ b/app/libs/shared_modules/src/event_history/event_history.provider.ts @@ -0,0 +1,25 @@ +import { Connection } from 'mongoose'; +import { EventHistorySchema } from './schemas/event_history.schema'; + +export const EventHistoryProviders = [ + { + provide: 'ETH_EVENT_HISTORY_MODEL', + useFactory: (connection: Connection) => + connection.model( + 'EthEventHistory', + EventHistorySchema, + 'eth_event_history', + ), + inject: ['DATABASE_CONNECTION'], + }, + { + provide: 'BSC_EVENT_HISTORY_MODEL', + useFactory: (connection: Connection) => + connection.model( + 'BscEventHistory', + EventHistorySchema, + 'bsc_event_history', + ), + inject: ['DATABASE_CONNECTION'], + }, +]; diff --git a/app/libs/shared_modules/src/event_history/event_history.service.spec.ts b/app/libs/shared_modules/src/event_history/event_history.service.spec.ts new file mode 100644 index 0000000..e88e27a --- /dev/null +++ b/app/libs/shared_modules/src/event_history/event_history.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { EventHistoryService } from './event_history.service'; + +describe('EventHistoryService', () => { + let service: EventHistoryService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [EventHistoryService], + }).compile(); + + service = module.get(EventHistoryService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/app/libs/shared_modules/src/transaction_history/transaction_history.service.ts b/app/libs/shared_modules/src/event_history/event_history.service.ts similarity index 58% rename from app/libs/shared_modules/src/transaction_history/transaction_history.service.ts rename to app/libs/shared_modules/src/event_history/event_history.service.ts index 86b60ea..5807c23 100644 --- a/app/libs/shared_modules/src/transaction_history/transaction_history.service.ts +++ b/app/libs/shared_modules/src/event_history/event_history.service.ts @@ -1,4 +1,4 @@ import { Injectable } from '@nestjs/common'; @Injectable() -export class TransactionHistoryService {} +export class EventHistoryService {} diff --git a/app/libs/shared_modules/src/event_history/repositories/event_history.repository.ts b/app/libs/shared_modules/src/event_history/repositories/event_history.repository.ts new file mode 100644 index 0000000..c65fe0b --- /dev/null +++ b/app/libs/shared_modules/src/event_history/repositories/event_history.repository.ts @@ -0,0 +1,81 @@ +import { MonitorNetwork } from '@app/shared_modules/monitor/schemas/monitor.schema'; +import { Inject, Injectable } from '@nestjs/common'; +import { Model } from 'mongoose'; +import { EventHistory } from '../schemas/event_history.schema'; + +export class EventHistoryRepository { + static repositories: Map = new Map(); + + static getRepository(network: MonitorNetwork): EventHistoryRepository { + return EventHistoryRepository.repositories[network]; + } + + constructor( + network: MonitorNetwork, + private readonly model: Model, + ) { + EventHistoryRepository.repositories[network] = this; + } + + async findByEventId(eventId: string): Promise { + return this.model.findOne({ eventId: eventId }); + } + + async saveEventHistory(eventHistory: EventHistory): Promise { + return new this.model(eventHistory).save(); + } + + async findByMonitorAndAssociatedAddress( + monitor: string, + associatedAddress: string, + ): Promise { + return this.model.find({ + monitorId: monitor, + associatedAddress: associatedAddress, + }); + } + + async getEventHistory( + monitorId: string, + limit: number, + offset: number, + ): Promise { + return this.model + .find({ monitorId: monitorId }) + .limit(limit) + .skip(offset) + .sort({ dateCreated: -1 }); + } + + async findEventHistoryByMonitorAndHash( + monitorId: string, + hash: string, + ): Promise { + return this.model.find({ monitorId: monitorId, hash: hash }); + } + + async pushDeliveryId(eventId: string, deliveryId: string) { + return this.model.updateOne( + { eventId: eventId }, + { + $push: { + deliveryIds: deliveryId, + }, + }, + ); + } +} + +@Injectable() +export class EthEventHistoryRepository extends EventHistoryRepository { + constructor(@Inject('ETH_EVENT_HISTORY_MODEL') model: Model) { + super(MonitorNetwork.Ethereum, model); + } +} + +@Injectable() +export class BscEventHistoryRepository extends EventHistoryRepository { + constructor(@Inject('BSC_EVENT_HISTORY_MODEL') model: Model) { + super(MonitorNetwork.BSC, model); + } +} diff --git a/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts b/app/libs/shared_modules/src/event_history/schemas/event_history.schema.ts similarity index 89% rename from app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts rename to app/libs/shared_modules/src/event_history/schemas/event_history.schema.ts index ff9020f..0caeefd 100644 --- a/app/libs/shared_modules/src/transaction_history/schemas/transaction_history.schema.ts +++ b/app/libs/shared_modules/src/event_history/schemas/event_history.schema.ts @@ -15,9 +15,9 @@ export enum WebhookType { out = 'out', } @Schema() -export class TransactionHistory { +export class EventHistory { @Prop({ required: true, unique: true }) - uniqueId: string; // md5 of message exclude timestamp and confirm + eventId: string; // md5 of message exclude timestamp and confirm @Prop() chain: string; @@ -119,8 +119,8 @@ export class TransactionHistory { type: WebhookType, confirm: boolean, tokenValue: string, - ): TransactionHistory { - const instance = new TransactionHistory(); + ): EventHistory { + const instance = new EventHistory(); instance.chain = chain; instance.monitorId = monitorId; instance.hash = log.transactionHash; @@ -149,7 +149,7 @@ export class TransactionHistory { if (type === WebhookType.in) { instance.associatedAddress = instance.toAddress; } - instance.uniqueId = instance.generateId(); + instance.eventId = instance.generateId(); return instance; } @@ -160,8 +160,8 @@ export class TransactionHistory { type: WebhookType, confirm: boolean, tokenId: string, - ): TransactionHistory { - const instance = new TransactionHistory(); + ): EventHistory { + const instance = new EventHistory(); instance.chain = chain; instance.monitorId = monitorId; instance.hash = log.transactionHash; @@ -190,7 +190,7 @@ export class TransactionHistory { if (type === WebhookType.in) { instance.associatedAddress = instance.toAddress; } - instance.uniqueId = instance.generateId(); + instance.eventId = instance.generateId(); return instance; } @@ -200,8 +200,8 @@ export class TransactionHistory { monitorId: string, type: WebhookType, confirm: boolean, - ): TransactionHistory { - const instance = new TransactionHistory(); + ): EventHistory { + const instance = new EventHistory(); instance.chain = chain; instance.monitorId = monitorId; instance.hash = transaction.hash; @@ -223,10 +223,9 @@ export class TransactionHistory { if (type === WebhookType.in) { instance.associatedAddress = instance.toAddress; } - instance.uniqueId = instance.generateId(); + instance.eventId = instance.generateId(); return instance; } } -export type TransactionHistoryDocument = HydratedDocument; -export const TransactionHistorySchema = - SchemaFactory.createForClass(TransactionHistory); +export type EventHistoryDocument = HydratedDocument; +export const EventHistorySchema = SchemaFactory.createForClass(EventHistory); diff --git a/app/libs/shared_modules/src/shared_modules.module.ts b/app/libs/shared_modules/src/shared_modules.module.ts index 4bf862a..c83988d 100644 --- a/app/libs/shared_modules/src/shared_modules.module.ts +++ b/app/libs/shared_modules/src/shared_modules.module.ts @@ -3,15 +3,10 @@ import { SharedModulesService } from './shared_modules.service'; import { MonitorModule } from './monitor/monitor.module'; import { ProjectModule } from './project/project.module'; import { WebhookModule } from './webhook/webhook.module'; -import { TransactionHistoryModule } from './transaction_history/transaction_history.module'; +import { EventHistoryModule } from './event_history/event_history.module'; @Module({ - imports: [ - MonitorModule, - ProjectModule, - WebhookModule, - TransactionHistoryModule, - ], + imports: [MonitorModule, ProjectModule, WebhookModule, EventHistoryModule], providers: [SharedModulesService], exports: [SharedModulesService, MonitorModule, ProjectModule, WebhookModule], }) diff --git a/app/libs/shared_modules/src/transaction_history/repositories/transaction_history.repository.ts b/app/libs/shared_modules/src/transaction_history/repositories/transaction_history.repository.ts deleted file mode 100644 index a364535..0000000 --- a/app/libs/shared_modules/src/transaction_history/repositories/transaction_history.repository.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { MonitorNetwork } from '@app/shared_modules/monitor/schemas/monitor.schema'; -import { Inject, Injectable } from '@nestjs/common'; -import { Model } from 'mongoose'; -import { TransactionHistory } from '../schemas/transaction_history.schema'; - -export class TransactionHistoryRepository { - static repositories: Map = - new Map(); - - static getRepository(network: MonitorNetwork): TransactionHistoryRepository { - return TransactionHistoryRepository.repositories[network]; - } - - constructor( - network: MonitorNetwork, - private readonly model: Model, - ) { - TransactionHistoryRepository.repositories[network] = this; - } - - async findByUniqueId(uniqueId: string): Promise { - return this.model.findOne({ uniqueId: uniqueId }); - } - - async saveTransactionHistory( - transactionHistory: TransactionHistory, - ): Promise { - return new this.model(transactionHistory).save(); - } - - async findByMonitorAndAssociatedAddress( - monitor: string, - associatedAddress: string, - ): Promise { - return this.model.find({ - monitorId: monitor, - associatedAddress: associatedAddress, - }); - } - - async getTransactionHistory( - monitorId: string, - limit: number, - offset: number, - ): Promise { - return this.model - .find({ monitorId: monitorId }) - .limit(limit) - .skip(offset) - .sort({ dateCreated: -1 }); - } - - async findTransactionHistoryByMonitorAndHash( - monitorId: string, - hash: string, - ): Promise { - return this.model.find({ monitorId: monitorId, hash: hash }); - } - - async pushDeliveryId(id: string, deliveryId: string) { - return this.model.updateOne( - { uniqueId: id }, - { - $push: { - deliveryIds: deliveryId, - }, - }, - ); - } -} - -@Injectable() -export class EthTransactionHistoryRepository extends TransactionHistoryRepository { - constructor( - @Inject('ETH_TRANSACTION_HISTORY_MODEL') model: Model, - ) { - super(MonitorNetwork.Ethereum, model); - } -} - -@Injectable() -export class BscTransactionHistoryRepository extends TransactionHistoryRepository { - constructor( - @Inject('BSC_TRANSACTION_HISTORY_MODEL') model: Model, - ) { - super(MonitorNetwork.BSC, model); - } -} diff --git a/app/libs/shared_modules/src/transaction_history/transaction_history.module.ts b/app/libs/shared_modules/src/transaction_history/transaction_history.module.ts deleted file mode 100644 index c46de41..0000000 --- a/app/libs/shared_modules/src/transaction_history/transaction_history.module.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { DatabaseModule } from '@app/database'; -import { Module } from '@nestjs/common'; -import { - BscTransactionHistoryRepository, - EthTransactionHistoryRepository, -} from './repositories/transaction_history.repository'; -import { TransactionHistoryProviders } from './transaction_history.provider'; - -@Module({ - imports: [DatabaseModule], - providers: [ - ...TransactionHistoryProviders, - EthTransactionHistoryRepository, - BscTransactionHistoryRepository, - ], - exports: [ - ...TransactionHistoryProviders, - EthTransactionHistoryRepository, - BscTransactionHistoryRepository, - ], -}) -export class TransactionHistoryModule {} diff --git a/app/libs/shared_modules/src/transaction_history/transaction_history.provider.ts b/app/libs/shared_modules/src/transaction_history/transaction_history.provider.ts deleted file mode 100644 index a348180..0000000 --- a/app/libs/shared_modules/src/transaction_history/transaction_history.provider.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Connection } from 'mongoose'; -import { TransactionHistorySchema } from './schemas/transaction_history.schema'; - -export const TransactionHistoryProviders = [ - { - provide: 'ETH_TRANSACTION_HISTORY_MODEL', - useFactory: (connection: Connection) => - connection.model( - 'EthTransactionHistory', - TransactionHistorySchema, - 'eth_transaction_history', - ), - inject: ['DATABASE_CONNECTION'], - }, - { - provide: 'BSC_TRANSACTION_HISTORY_MODEL', - useFactory: (connection: Connection) => - connection.model( - 'BscTransactionHistory', - TransactionHistorySchema, - 'bsc_transaction_history', - ), - inject: ['DATABASE_CONNECTION'], - }, -]; diff --git a/app/libs/shared_modules/src/transaction_history/transaction_history.service.spec.ts b/app/libs/shared_modules/src/transaction_history/transaction_history.service.spec.ts deleted file mode 100644 index dcb8adf..0000000 --- a/app/libs/shared_modules/src/transaction_history/transaction_history.service.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { TransactionHistoryService } from './transaction_history.service'; - -describe('TransactionHistoryService', () => { - let service: TransactionHistoryService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [TransactionHistoryService], - }).compile(); - - service = module.get(TransactionHistoryService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); From 5a3d04e527c11e3fc087cf12d692d30f750fe7aa Mon Sep 17 00:00:00 2001 From: cauta Date: Fri, 19 Apr 2024 12:09:06 +0700 Subject: [PATCH 11/18] upgrade etherjs to new verion becuase of txn index error --- app/package.json | 2 +- app/yarn.lock | 49 ++++++++++++------------------------------------ 2 files changed, 13 insertions(+), 38 deletions(-) diff --git a/app/package.json b/app/package.json index 5b0b10e..128335f 100644 --- a/app/package.json +++ b/app/package.json @@ -42,7 +42,7 @@ "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "dotenv": "^16.3.1", - "ethers": "^6.9.0", + "ethers": "^6.12.0", "express-basic-auth": "^1.2.1", "kafkajs": "^2.2.4", "mongoose": "^8.2.2", diff --git a/app/yarn.lock b/app/yarn.lock index 5f75dcd..7f959dc 100644 --- a/app/yarn.lock +++ b/app/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== -"@adraffy/ens-normalize@1.10.0": - version "1.10.0" - resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7" - integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q== +"@adraffy/ens-normalize@1.10.1": + version "1.10.1" + resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" + integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== "@ampproject/remapping@^2.2.0": version "2.2.1" @@ -2682,12 +2682,12 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -ethers@^6.9.0: - version "6.9.0" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.9.0.tgz#a4534bdcdfde306aee94ef32f3d5c70d7e33fcb9" - integrity sha512-pmfNyQzc2mseLe91FnT2vmNaTt8dDzhxZ/xItAV7uGsF4dI4ek2ufMu3rAkgQETL/TIs0GS5A+U05g9QyWnv3Q== +ethers@^6.12.0: + version "6.12.0" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.12.0.tgz#b0c2ce207ae5a3b5125be966e32ffea7c1f2481a" + integrity sha512-zL5NlOTjML239gIvtVJuaSk0N9GQLi1Hom3ZWUszE5lDTQE/IVB62mrPkQ2W1bGcZwVGSLaetQbWNQSvI4rGDQ== dependencies: - "@adraffy/ens-normalize" "1.10.0" + "@adraffy/ens-normalize" "1.10.1" "@noble/curves" "1.2.0" "@noble/hashes" "1.3.2" "@types/node" "18.15.13" @@ -5213,16 +5213,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -5254,14 +5245,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -5822,7 +5806,7 @@ wide-align@^1.1.2: dependencies: string-width "^1.0.2 || 2 || 3 || 4" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -5840,15 +5824,6 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From 7202a79e9e56bd501bba684b727fb6dd4fa41207 Mon Sep 17 00:00:00 2001 From: cauta Date: Fri, 19 Apr 2024 12:09:24 +0700 Subject: [PATCH 12/18] update event history data --- .../schemas/event_history.schema.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/app/libs/shared_modules/src/event_history/schemas/event_history.schema.ts b/app/libs/shared_modules/src/event_history/schemas/event_history.schema.ts index 0caeefd..8c9c881 100644 --- a/app/libs/shared_modules/src/event_history/schemas/event_history.schema.ts +++ b/app/libs/shared_modules/src/event_history/schemas/event_history.schema.ts @@ -132,9 +132,9 @@ export class EventHistory { }; instance.fromAddress = log.topics[1].substring(26); instance.toAddress = log.topics[2].substring(26); - instance.tokenId = '0'; + // instance.tokenId = '0'; instance.tokenValue = tokenValue; - instance.nativeAmount = '0'; + // instance.nativeAmount = '0'; instance.rawLog = { topics: log.topics as string[], data: log.data, @@ -143,6 +143,8 @@ export class EventHistory { instance.confirm = confirm; instance.category = WebhookCategory.ERC20; instance.dateCreated = new Date(); + instance.logIndex = log.index; + instance.txnIndex = log.transactionIndex; if (type === WebhookType.out) { instance.associatedAddress = instance.fromAddress; } @@ -174,8 +176,8 @@ export class EventHistory { instance.fromAddress = log.topics[1].substring(26); instance.toAddress = log.topics[2].substring(26); instance.tokenId = tokenId; - instance.tokenValue = '0'; - instance.nativeAmount = '0'; + // instance.tokenValue = '0'; + // instance.nativeAmount = '0'; instance.rawLog = { topics: log.topics as string[], data: log.data, @@ -184,6 +186,8 @@ export class EventHistory { instance.confirm = confirm; instance.category = WebhookCategory.ERC721; instance.dateCreated = new Date(); + instance.logIndex = log.index; + instance.txnIndex = log.transactionIndex; if (type === WebhookType.out) { instance.associatedAddress = instance.fromAddress; } @@ -209,13 +213,14 @@ export class EventHistory { instance.fromAddress = transaction.from.toLowerCase(); instance.toAddress = transaction.to.toLowerCase(); - instance.tokenId = '0'; - instance.tokenValue = '0'; + // instance.tokenId = '0'; + // instance.tokenValue = '0'; instance.nativeAmount = transaction.value.toString(); instance.type = type; instance.confirm = confirm; instance.category = WebhookCategory.Native; instance.dateCreated = new Date(); + instance.txnIndex = transaction.index; // @todo assign data from transaction data if (type === WebhookType.out) { instance.associatedAddress = instance.fromAddress; From 7391ca0250fc3f7f611273798919b7f4b08530b4 Mon Sep 17 00:00:00 2001 From: cauta Date: Fri, 19 Apr 2024 14:25:31 +0700 Subject: [PATCH 13/18] fix typo --- app/apps/monitor-service/src/ethereum/ethereum.service.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/apps/monitor-service/src/ethereum/ethereum.service.ts b/app/apps/monitor-service/src/ethereum/ethereum.service.ts index af36e14..783a33a 100644 --- a/app/apps/monitor-service/src/ethereum/ethereum.service.ts +++ b/app/apps/monitor-service/src/ethereum/ethereum.service.ts @@ -200,7 +200,7 @@ export class EthereumService { confirm, ); - const response = await this.dispathMessageToWebhook(monitor, txnHistory); + const response = await this.dispatchMessageToWebhook(monitor, txnHistory); this.saveHistory(txnHistory, response); this.logger.debug( @@ -239,7 +239,7 @@ export class EthereumService { tokenId, ); - const response = await this.dispathMessageToWebhook(monitor, transaction); + const response = await this.dispatchMessageToWebhook(monitor, transaction); this.saveHistory(transaction, response); this.logger.debug( @@ -280,7 +280,7 @@ export class EthereumService { value, ); - const response = await this.dispathMessageToWebhook(monitor, txnHistory); + const response = await this.dispatchMessageToWebhook(monitor, txnHistory); this.saveHistory(txnHistory, response); this.logger.debug( @@ -336,7 +336,7 @@ export class EthereumService { } } - private async dispathMessageToWebhook( + private async dispatchMessageToWebhook( monitor: Monitor, body: EventHistory, ): Promise { From deba451580a27b8f7264b06c14850b243907ee23 Mon Sep 17 00:00:00 2001 From: cauta Date: Fri, 19 Apr 2024 14:51:13 +0700 Subject: [PATCH 14/18] fix bug, confirm event history handle error on send transaction to webhook service --- .../src/ethereum/ethereum.service.ts | 38 ++++++++++++------- .../repositories/event_history.repository.ts | 5 ++- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/app/apps/monitor-service/src/ethereum/ethereum.service.ts b/app/apps/monitor-service/src/ethereum/ethereum.service.ts index 783a33a..42da928 100644 --- a/app/apps/monitor-service/src/ethereum/ethereum.service.ts +++ b/app/apps/monitor-service/src/ethereum/ethereum.service.ts @@ -216,7 +216,6 @@ export class EthereumService { tokenId: string, type: WebhookType, ) { - // @todo check condition of monitor and event log if it match for (const address of addresses) { const monitor = await this.findMonitor(address.monitorId); // ignore monitor condition on erc721 @@ -239,7 +238,10 @@ export class EthereumService { tokenId, ); - const response = await this.dispatchMessageToWebhook(monitor, transaction); + const response = await this.dispatchMessageToWebhook( + monitor, + transaction, + ); this.saveHistory(transaction, response); this.logger.debug( @@ -257,7 +259,6 @@ export class EthereumService { value: string, type: WebhookType, ) { - // @todo check condition of monitor and event log if it match for (const address of addresses) { const monitor = await this.findMonitor(address.monitorId); // ignore monitor condition on erc20 @@ -281,7 +282,7 @@ export class EthereumService { ); const response = await this.dispatchMessageToWebhook(monitor, txnHistory); - this.saveHistory(txnHistory, response); + await this.saveHistory(txnHistory, response); this.logger.debug( `Confirmed: ${confirm} ERC20 transfer ${type.toUpperCase()}:\n${JSON.stringify( @@ -292,17 +293,28 @@ export class EthereumService { } private async saveHistory( - transaction: EventHistory, + event: EventHistory, delivery: DispatchWebhookResponse, ) { - // @todo handle when dispatch message to webhook service - if (!transaction.confirm) { - transaction.deliveryIds = [delivery.id]; - await this.eventHistoryRepository.saveEventHistory(transaction); + let deliveryId: string; + if (!delivery) { + this.logger.error( + `Save event ${event.confirm ? 'CONFIRMED' : 'DETECT'} ${ + event.eventId + } with error can not dispatch this event`, + ); + deliveryId = 'ERROR'; + } else { + deliveryId = delivery.id; + } + + if (!event.confirm) { + event.deliveryIds = [deliveryId]; + await this.eventHistoryRepository.saveEventHistory(event); } else { - this.eventHistoryRepository.pushDeliveryId( - transaction.eventId, - delivery.id, + await this.eventHistoryRepository.pushConfirmDeliveryId( + event.eventId, + deliveryId, ); } } @@ -353,7 +365,7 @@ export class EthereumService { this.logger.debug( `Dispatch webhook successfully response: ${JSON.stringify(respone)}`, ); - this.projectQuotaService.increaseUsed(monitor.projectId); + await this.projectQuotaService.increaseUsed(monitor.projectId); return respone; } catch (error) { this.logger.error( diff --git a/app/libs/shared_modules/src/event_history/repositories/event_history.repository.ts b/app/libs/shared_modules/src/event_history/repositories/event_history.repository.ts index c65fe0b..c595713 100644 --- a/app/libs/shared_modules/src/event_history/repositories/event_history.repository.ts +++ b/app/libs/shared_modules/src/event_history/repositories/event_history.repository.ts @@ -54,13 +54,16 @@ export class EventHistoryRepository { return this.model.find({ monitorId: monitorId, hash: hash }); } - async pushDeliveryId(eventId: string, deliveryId: string) { + async pushConfirmDeliveryId(eventId: string, deliveryId: string) { return this.model.updateOne( { eventId: eventId }, { $push: { deliveryIds: deliveryId, }, + $set: { + confirm: true, + }, }, ); } From 98a7ff77b2a9fffab6728170d7abe165bc15f92b Mon Sep 17 00:00:00 2001 From: cauta Date: Mon, 22 Apr 2024 13:04:56 +0700 Subject: [PATCH 15/18] remove unused --- .../event_history.service.spec.ts | 18 ------------------ .../src/event_history/event_history.service.ts | 4 ---- 2 files changed, 22 deletions(-) delete mode 100644 app/libs/shared_modules/src/event_history/event_history.service.spec.ts delete mode 100644 app/libs/shared_modules/src/event_history/event_history.service.ts diff --git a/app/libs/shared_modules/src/event_history/event_history.service.spec.ts b/app/libs/shared_modules/src/event_history/event_history.service.spec.ts deleted file mode 100644 index e88e27a..0000000 --- a/app/libs/shared_modules/src/event_history/event_history.service.spec.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { EventHistoryService } from './event_history.service'; - -describe('EventHistoryService', () => { - let service: EventHistoryService; - - beforeEach(async () => { - const module: TestingModule = await Test.createTestingModule({ - providers: [EventHistoryService], - }).compile(); - - service = module.get(EventHistoryService); - }); - - it('should be defined', () => { - expect(service).toBeDefined(); - }); -}); diff --git a/app/libs/shared_modules/src/event_history/event_history.service.ts b/app/libs/shared_modules/src/event_history/event_history.service.ts deleted file mode 100644 index 5807c23..0000000 --- a/app/libs/shared_modules/src/event_history/event_history.service.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class EventHistoryService {} From 6e937af336925cc4a160d750c97a11f32d73d769 Mon Sep 17 00:00:00 2001 From: cauta Date: Mon, 22 Apr 2024 13:05:28 +0700 Subject: [PATCH 16/18] fix event history module name --- .../src/ethereum/ethereum.module.ts | 4 ++-- .../src/event_history/event_history.module.ts | 2 +- .../shared_modules/src/shared_modules.module.ts | 17 ++++++++++++++--- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/app/apps/monitor-service/src/ethereum/ethereum.module.ts b/app/apps/monitor-service/src/ethereum/ethereum.module.ts index e3c6341..1fae74b 100644 --- a/app/apps/monitor-service/src/ethereum/ethereum.module.ts +++ b/app/apps/monitor-service/src/ethereum/ethereum.module.ts @@ -1,4 +1,4 @@ -import { EventHistoryModule } from '@app/shared_modules/event_history/event_history.module'; +import { EventHistoryModelModule } from '@app/shared_modules/event_history/event_history.module'; import { MonitorModule } from '@app/shared_modules/monitor/monitor.module'; import { ProjectModule } from '@app/shared_modules/project/project.module'; import { WebhookModule } from '@app/shared_modules/webhook/webhook.module'; @@ -32,7 +32,7 @@ import { EthereumService } from './ethereum.service'; WebhookModule, MonitorModule, ProjectModule, - EventHistoryModule, + EventHistoryModelModule, ], }) export class EthereumModule {} diff --git a/app/libs/shared_modules/src/event_history/event_history.module.ts b/app/libs/shared_modules/src/event_history/event_history.module.ts index 405b7fe..6a17d20 100644 --- a/app/libs/shared_modules/src/event_history/event_history.module.ts +++ b/app/libs/shared_modules/src/event_history/event_history.module.ts @@ -19,4 +19,4 @@ import { EventHistoryProviders } from './event_history.provider'; BscEventHistoryRepository, ], }) -export class EventHistoryModule {} +export class EventHistoryModelModule {} diff --git a/app/libs/shared_modules/src/shared_modules.module.ts b/app/libs/shared_modules/src/shared_modules.module.ts index c83988d..769f6e7 100644 --- a/app/libs/shared_modules/src/shared_modules.module.ts +++ b/app/libs/shared_modules/src/shared_modules.module.ts @@ -3,11 +3,22 @@ import { SharedModulesService } from './shared_modules.service'; import { MonitorModule } from './monitor/monitor.module'; import { ProjectModule } from './project/project.module'; import { WebhookModule } from './webhook/webhook.module'; -import { EventHistoryModule } from './event_history/event_history.module'; +import { EventHistoryModelModule } from './event_history/event_history.module'; @Module({ - imports: [MonitorModule, ProjectModule, WebhookModule, EventHistoryModule], + imports: [ + MonitorModule, + ProjectModule, + WebhookModule, + EventHistoryModelModule, + ], providers: [SharedModulesService], - exports: [SharedModulesService, MonitorModule, ProjectModule, WebhookModule], + exports: [ + SharedModulesService, + MonitorModule, + ProjectModule, + WebhookModule, + EventHistoryModelModule, + ], }) export class SharedModulesModule {} From 78c4d9604a6622284e0367e49ef13d3db17ec050 Mon Sep 17 00:00:00 2001 From: cauta Date: Mon, 22 Apr 2024 13:05:50 +0700 Subject: [PATCH 17/18] Add event history api --- app/apps/onebox/src/main.module.ts | 2 + .../event_history/dto/event_history.dto.ts | 127 ++++++++++++++++++ .../event_history/event_history.controller.ts | 36 +++++ .../event_history/event_history.module.ts | 12 ++ .../event_history/event_history.service.ts | 42 ++++++ 5 files changed, 219 insertions(+) create mode 100644 app/apps/onebox/src/modules/event_history/dto/event_history.dto.ts create mode 100644 app/apps/onebox/src/modules/event_history/event_history.controller.ts create mode 100644 app/apps/onebox/src/modules/event_history/event_history.module.ts create mode 100644 app/apps/onebox/src/modules/event_history/event_history.service.ts diff --git a/app/apps/onebox/src/main.module.ts b/app/apps/onebox/src/main.module.ts index 62e20ba..072234c 100644 --- a/app/apps/onebox/src/main.module.ts +++ b/app/apps/onebox/src/main.module.ts @@ -12,6 +12,7 @@ import { ProjectModule } from './modules/project/project.module'; import { UsersModule } from './modules/users/users.module'; import { PollingBlockService } from './polling.block/polling.block.service'; import { DeliveryModule } from './modules/delivery/delivery.module'; +import { EventHistoryModule } from './modules/event_history/event_history.module'; @Module({ imports: [ @@ -46,6 +47,7 @@ import { DeliveryModule } from './modules/delivery/delivery.module'; MonitorModule, MonitorAddressModule, DeliveryModule, + EventHistoryModule, ], providers: [GlobalService, PollingBlockService], }) diff --git a/app/apps/onebox/src/modules/event_history/dto/event_history.dto.ts b/app/apps/onebox/src/modules/event_history/dto/event_history.dto.ts new file mode 100644 index 0000000..e2109ce --- /dev/null +++ b/app/apps/onebox/src/modules/event_history/dto/event_history.dto.ts @@ -0,0 +1,127 @@ +import { + EventHistory, + WebhookCategory, + WebhookType, +} from '@app/shared_modules/event_history/schemas/event_history.schema'; +import { ApiProperty, ApiResponseProperty } from '@nestjs/swagger'; +import { Builder } from 'builder-pattern'; +import { Transform } from 'class-transformer'; +import { IsNotEmpty, Max, Min } from 'class-validator'; + +export class GetMonitorEventHistoryDto { + @ApiProperty() + @IsNotEmpty() + monitorId: string; + + // @ApiProperty({ required: false }) + // status?: 'succeeded' | 'pending' | 'failed'; + + @ApiProperty({ default: 10 }) + @Max(10) + @Min(1) + @Transform(({ value }) => parseInt(value)) + limit: number; + + @ApiProperty({ default: 0 }) + @Min(0) + @Transform(({ value }) => parseInt(value)) + offset: number; +} + +export class MonitorEventHistoryResponseDto { + @ApiResponseProperty() + eventId: string; // md5 of message exclude timestamp and confirm + + @ApiResponseProperty() + chain: string; + + @ApiResponseProperty() + monitorId: string; + + @ApiResponseProperty() + associatedAddress: string; + + @ApiResponseProperty() + hash: string; + + @ApiResponseProperty() + blockNum: number; // decimal string + + @ApiResponseProperty() + contract: { + address: string; + name: string; + symbol: string; + }; + + @ApiResponseProperty() + fromAddress: string; + + @ApiResponseProperty() + toAddress: string; + + @ApiResponseProperty() + tokenId: string; // decimal string + + @ApiResponseProperty() + tokenValue: string; // decimal string + + @ApiResponseProperty() + nativeAmount: string; // decimal string + + @ApiResponseProperty() + type: WebhookType; + + @ApiResponseProperty() + confirm: boolean; + + @ApiResponseProperty() + category: WebhookCategory; + + @ApiResponseProperty() + rawLog: { + topics: string[]; + data: string; + }; + + @ApiResponseProperty() + logIndex: number; + + @ApiResponseProperty() + txnIndex: number; + + @ApiResponseProperty() + tags: string[]; + + @ApiResponseProperty() + dateCreated: Date; + + @ApiResponseProperty() + deliveryIds: string[]; + + static from(dto: EventHistory): MonitorEventHistoryResponseDto { + return Builder() + .eventId(dto.eventId) + .chain(dto.chain) + .monitorId(dto.monitorId) + .associatedAddress(dto.associatedAddress) + .hash(dto.hash) + .blockNum(dto.blockNum) + .contract(dto.contract) + .fromAddress(dto.fromAddress) + .toAddress(dto.toAddress) + .tokenId(dto.tokenId) + .tokenValue(dto.tokenValue) + .nativeAmount(dto.nativeAmount) + .type(dto.type) + .confirm(dto.confirm) + .category(dto.category) + .rawLog(dto.rawLog) + .logIndex(dto.logIndex) + .txnIndex(dto.txnIndex) + .tags(dto.tags) + .dateCreated(dto.dateCreated) + .deliveryIds(dto.deliveryIds) + .build(); + } +} diff --git a/app/apps/onebox/src/modules/event_history/event_history.controller.ts b/app/apps/onebox/src/modules/event_history/event_history.controller.ts new file mode 100644 index 0000000..d57f9c5 --- /dev/null +++ b/app/apps/onebox/src/modules/event_history/event_history.controller.ts @@ -0,0 +1,36 @@ +import { Controller, Get, Query, Req, UseGuards } from '@nestjs/common'; +import { + ApiBearerAuth, + ApiOkResponse, + ApiOperation, + ApiTags, +} from '@nestjs/swagger'; +import { Request } from 'express'; +import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; +import { User } from '../users/schemas/user.schema'; +import { + GetMonitorEventHistoryDto, + MonitorEventHistoryResponseDto, +} from './dto/event_history.dto'; +import { EventHistoryService } from './event_history.service'; + +@ApiTags('Monitor Event History') +@Controller('/event') +export class EventHistoryController { + constructor(private readonly eventHistoryService: EventHistoryService) {} + + @ApiOperation({ summary: 'Get Monitor Event' }) + @ApiBearerAuth('JWT') + @UseGuards(JwtAuthGuard) + @Get('') + @ApiOkResponse({ type: [MonitorEventHistoryResponseDto] }) + async getMonitorEvent( + @Req() req: Request, + @Query() body: GetMonitorEventHistoryDto, + ): Promise { + return await this.eventHistoryService.getMonitorEventHistory( + req.user as User, + body, + ); + } +} diff --git a/app/apps/onebox/src/modules/event_history/event_history.module.ts b/app/apps/onebox/src/modules/event_history/event_history.module.ts new file mode 100644 index 0000000..316b943 --- /dev/null +++ b/app/apps/onebox/src/modules/event_history/event_history.module.ts @@ -0,0 +1,12 @@ +import { EventHistoryModelModule } from '@app/shared_modules/event_history/event_history.module'; +import { Module } from '@nestjs/common'; +import { MonitorModule } from '../monitor/monitor.module'; +import { EventHistoryController } from './event_history.controller'; +import { EventHistoryService } from './event_history.service'; +@Module({ + controllers: [EventHistoryController], + providers: [EventHistoryService], + exports: [EventHistoryService], + imports: [EventHistoryModelModule, MonitorModule], +}) +export class EventHistoryModule {} diff --git a/app/apps/onebox/src/modules/event_history/event_history.service.ts b/app/apps/onebox/src/modules/event_history/event_history.service.ts new file mode 100644 index 0000000..9a66c42 --- /dev/null +++ b/app/apps/onebox/src/modules/event_history/event_history.service.ts @@ -0,0 +1,42 @@ +import { EthEventHistoryRepository } from '@app/shared_modules/event_history/repositories/event_history.repository'; +import { Inject, Injectable, Logger } from '@nestjs/common'; +import { MonitorService } from '../monitor/monitor.service'; +import { User } from '../users/schemas/user.schema'; +import { + GetMonitorEventHistoryDto, + MonitorEventHistoryResponseDto, +} from './dto/event_history.dto'; +import { MonitorNetwork } from '@app/shared_modules/monitor/schemas/monitor.schema'; +import { ErrorCode } from '@app/global/global.error'; + +@Injectable() +export class EventHistoryService { + private readonly logger = new Logger(EventHistoryService.name); + constructor( + private readonly ethEventHistoryRepository: EthEventHistoryRepository, + private readonly monitorService: MonitorService, + ) {} + + async getMonitorEventHistory( + user: User, + request: GetMonitorEventHistoryDto, + ): Promise { + const monitor = await this.monitorService.findAndAuthMonitor( + user, + request.monitorId, + ); + + if (monitor.network === MonitorNetwork.Ethereum) { + return this.ethEventHistoryRepository + .getEventHistory(monitor.monitorId, request.limit, request.offset) + .then((response) => { + return response.map((event) => + MonitorEventHistoryResponseDto.from(event), + ); + }); + } + + this.logger.error(`network ${monitor.network} not supported`); + throw ErrorCode.INTERNAL_SERVER_ERROR.asException(); + } +} From 3e5b061b96c17f33c22dc1902b7448431a3afc0c Mon Sep 17 00:00:00 2001 From: cauta Date: Mon, 22 Apr 2024 12:27:08 +0700 Subject: [PATCH 18/18] disable webhook on delete monitor update monitor method also update webhook --- .../src/modules/monitor/monitor.service.ts | 33 +++++++++- .../src/webhook/webhook.service.ts | 62 +++++++++---------- 2 files changed, 62 insertions(+), 33 deletions(-) diff --git a/app/apps/onebox/src/modules/monitor/monitor.service.ts b/app/apps/onebox/src/modules/monitor/monitor.service.ts index f215910..c41c4b1 100644 --- a/app/apps/onebox/src/modules/monitor/monitor.service.ts +++ b/app/apps/onebox/src/modules/monitor/monitor.service.ts @@ -100,6 +100,17 @@ export class MonitorService { ]); }); + if (monitor.notification.method === MonitorNotificationMethod.Webhook) { + const method = monitor.notification as WebhookNotification; + await this.webhookService.updateWebhook(monitor.webhookId, { + name: monitor.monitorId, + webhookUrl: method.url, + secret_token: method.secret_token, + authorization: method.authorization, + active: false, + }); + } + return Builder().success(true).build(); } @@ -147,8 +158,26 @@ export class MonitorService { if (request.disabled != undefined) { updateMonitor['disabled'] = request.disabled; } - return this.monitorRepository + + return await this.monitorRepository .updateMonitor(monitor.monitorId, updateMonitor) - .then((monitor) => MonitorResponseDto.from(monitor)); + .then(async (monitor) => { + // @todo handle error on update webhook service + if (monitor.notification) { + if ( + request.notification.method === MonitorNotificationMethod.Webhook + ) { + const method = monitor.notification as WebhookNotification; + await this.webhookService.updateWebhook(monitor.webhookId, { + name: monitor.monitorId, + webhookUrl: method.url, + secret_token: method.secret_token, + authorization: method.authorization, + active: true, + }); + } + } + return MonitorResponseDto.from(monitor); + }); } } diff --git a/app/libs/shared_modules/src/webhook/webhook.service.ts b/app/libs/shared_modules/src/webhook/webhook.service.ts index 391ce44..a4abec0 100644 --- a/app/libs/shared_modules/src/webhook/webhook.service.ts +++ b/app/libs/shared_modules/src/webhook/webhook.service.ts @@ -119,17 +119,21 @@ export class WebhookService { async updateWebhook( webhookId: string, - webhookUrl?: string, - authorization?: string, - secret_token?: string, - active?: boolean, + options: { + name: string; + webhookUrl: string; + authorization: string; + secret_token: string; + active: boolean; + }, ) { try { const request = this.buildUpdateWebhookRequest( - webhookUrl, - authorization, - secret_token, - active, + options.name, + options.webhookUrl, + options.authorization, + options.secret_token, + options.active, ); const response = await sendPut( `${this.webhookUrl}/v1/webhooks/${webhookId}`, @@ -271,31 +275,27 @@ export class WebhookService { } private buildUpdateWebhookRequest( - webhookUrl?: string, - authorization?: string, - secret_token?: string, - active?: boolean, + name: string, + webhookUrl: string, + authorization: string, + secret_token: string, + active: boolean, ): UpdateWebhookRequestDto { - const options: UpdateWebhookRequestDto = {}; - - // Check each input and add it to the options object only if it's defined - if (webhookUrl !== undefined) { - options.url = webhookUrl; - } - - if (authorization !== undefined) { - options.authorization_token = authorization; - } - - if (secret_token !== undefined) { - options.secret_token = secret_token; - } - - if (active !== undefined) { - options.active = active; - } + const updateWebhookDto = { + name: name, + url: webhookUrl, + content_type: 'application/json', + valid_status_codes: [200, 201], + secret_token: secret_token, + authorization_token: authorization, + active: active, + max_delivery_attempts: 5, + delivery_attempt_timeout: 1, + retry_min_backoff: 10, + retry_max_backoff: 60, + }; - return options; + return updateWebhookDto; } }