diff --git a/.gitignore b/.gitignore index 54036a75b..c91f73360 100644 --- a/.gitignore +++ b/.gitignore @@ -400,3 +400,4 @@ build.yaml # PEM file(s) *.pem +/src/plugins diff --git a/package.json b/package.json index 78510518e..85ddcf00f 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,8 @@ "description": "Nest TypeScript starter repository", "license": "MIT", "scripts": { + "init": "run-script-os", + "init:nix": "rimraf src/plugins && mkdir src/plugins && cp src/plugins.template/plugin.module.ts.template src/plugins/plugin.module.ts", "prebuild": "rimraf dist", "build": "nest build && npm run copy-pem", "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", diff --git a/schema.gql b/schema.gql index 34f2aa008..d2c86fcf4 100644 --- a/schema.gql +++ b/schema.gql @@ -1201,6 +1201,7 @@ type ScamInfo { } enum ScamInfoTypeEnum { + none potentialScam scam } diff --git a/src/common/pluggins/plugin.service.ts b/src/common/pluggins/plugin.service.ts new file mode 100644 index 000000000..12b7126c6 --- /dev/null +++ b/src/common/pluggins/plugin.service.ts @@ -0,0 +1,7 @@ +import { Injectable } from '@nestjs/common'; +import { Asset } from 'src/modules/assets/models/Asset.dto'; + +@Injectable() +export class PluginService { + async computeScamInfo(_nft: Asset[]): Promise {} +} diff --git a/src/common/services/mx-communication/models/account.info.ts b/src/common/services/mx-communication/models/account.info.ts new file mode 100644 index 000000000..4c471bc8b --- /dev/null +++ b/src/common/services/mx-communication/models/account.info.ts @@ -0,0 +1,19 @@ +import { ScamInfo } from 'src/modules/assets/models/ScamInfo.dto'; + +export class AccountInfo { + address: string = ''; + nonce: number = 0; + balance: string = ''; + username: string = ''; + code: string = ''; + codeHash: string | undefined; + rootHash: string = ''; + codeMetadata: string = ''; + developerReward: string = ''; + ownerAddress: string = ''; + scamInfo: ScamInfo | undefined = undefined; + + constructor(init?: Partial) { + Object.assign(this, init); + } +} diff --git a/src/common/services/mx-communication/models/nft.dto.ts b/src/common/services/mx-communication/models/nft.dto.ts index 1006918e0..681ed64c5 100644 --- a/src/common/services/mx-communication/models/nft.dto.ts +++ b/src/common/services/mx-communication/models/nft.dto.ts @@ -31,6 +31,7 @@ export interface Nft { nonce: number; royalties: string; timestamp: number; + url: string; uris: string[]; tags: string[]; metadata: NftMetadata; diff --git a/src/common/services/mx-communication/mx-communication.module.ts b/src/common/services/mx-communication/mx-communication.module.ts index 6c899468a..066e4051b 100644 --- a/src/common/services/mx-communication/mx-communication.module.ts +++ b/src/common/services/mx-communication/mx-communication.module.ts @@ -10,7 +10,6 @@ import { MxProxyService } from './mx-proxy.service'; import { MxStatsService } from './mx-stats.service'; import { SlackReportService } from './slack-report.service'; import { ConfigService } from '@nestjs/config'; -import { MxExtrasApiService } from './mx-extras-api.service'; import { ApiConfigService } from 'src/modules/common/api-config/api.config.service'; @Module({ @@ -27,7 +26,6 @@ import { ApiConfigService } from 'src/modules/common/api-config/api.config.servi MxIdentityService, MxToolsService, MxFeedService, - MxExtrasApiService, SlackReportService, ], exports: [ @@ -40,7 +38,6 @@ import { ApiConfigService } from 'src/modules/common/api-config/api.config.servi MxIdentityService, MxToolsService, MxFeedService, - MxExtrasApiService, SlackReportService, ], }) diff --git a/src/common/services/mx-communication/mx-extras-api.service.ts b/src/common/services/mx-communication/mx-extras-api.service.ts deleted file mode 100644 index 44eff7c83..000000000 --- a/src/common/services/mx-communication/mx-extras-api.service.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { Injectable, Logger } from '@nestjs/common'; -import { mxConfig } from 'src/config'; -import { NativeAuthSigner } from '@multiversx/sdk-nestjs/lib/src/utils/native.auth.signer'; -import { ApiService } from './api.service'; -import { ApiSettings } from './models/api-settings'; -import { getFilePathFromDist } from 'src/utils/helpers'; -import { ApiConfigService } from 'src/modules/common/api-config/api.config.service'; - -@Injectable() -export class MxExtrasApiService { - private url: string; - private nativeAuthSigner: NativeAuthSigner; - - constructor( - private readonly logger: Logger, - private readonly apiConfigService: ApiConfigService, - private readonly apiService: ApiService, - ) { - this.url = this.apiConfigService.getExtrasApiUrl(); - this.nativeAuthSigner = new NativeAuthSigner({ - origin: 'NftService', - apiUrl: this.apiConfigService.getApiUrl(), - signerPrivateKeyPath: getFilePathFromDist(mxConfig.pemFileName), - }); - } - - async setCollectionScam(collection: string): Promise { - await this.doPost( - this.setCollectionScam.name, - 'permissions/deny/collections', - { - name: collection, - description: 'Scam report', - }, - ); - } - - async clearCollectionScam(collection: string): Promise { - await this.doDelete( - this.clearCollectionScam.name, - `permissions/deny/collections/${collection}`, - ); - } - - private async getConfig(): Promise { - const accessTokenInfo = await this.nativeAuthSigner.getToken(); - return { - authorization: `Bearer ${accessTokenInfo.token}`, - timeout: 500, - }; - } - - private async doPost( - name: string, - resourceUrl: string, - body: any, - ): Promise { - try { - const config = await this.getConfig(); - const response = await this.apiService.post( - `${this.url}/${resourceUrl}`, - body, - config, - ); - return response.data; - } catch (error) { - this.logger.error(`Error when trying to get run ${name}`, { - error: error.message, - path: `${MxExtrasApiService.name}.${this.doPost.name}`, - }); - } - } - - private async doDelete(name: string, resourceUrl: string): Promise { - try { - const config = await this.getConfig(); - const response = await this.apiService.delete( - `${this.url}/${resourceUrl}`, - config, - {}, - ); - return response.data; - } catch (error) { - this.logger.error(`Error when trying to get run ${name}`, { - error: error.message, - path: `${MxExtrasApiService.name}.${this.doDelete.name}`, - }); - } - } -} diff --git a/src/document-db/document-db.service.ts b/src/document-db/document-db.service.ts index c39394c98..8fae753a2 100644 --- a/src/document-db/document-db.service.ts +++ b/src/document-db/document-db.service.ts @@ -1,12 +1,12 @@ import { PerformanceProfiler } from '@multiversx/sdk-nestjs'; import { Injectable } from '@nestjs/common'; -import { Nft } from 'src/common'; import { ScamInfo } from 'src/modules/assets/models/ScamInfo.dto'; import { MetricsCollector } from 'src/modules/metrics/metrics.collector'; import { NftScamInfoModel } from 'src/modules/scam/models/nft-scam-info.model'; import { CollectionTraitSummary } from 'src/modules/nft-traits/models/collection-traits.model'; import { NftScamInfoRepositoryService } from './repositories/nft-scam.repository'; import { TraitRepositoryService } from './repositories/traits.repository'; +import { Asset } from 'src/modules/assets/models'; @Injectable() export class DocumentDbService { @@ -73,7 +73,7 @@ export class DocumentDbService { } async saveOrUpdateBulkNftScamInfo( - nfts: Nft[], + nfts: Asset[], version: string, ): Promise { return await this.execute( diff --git a/src/document-db/repositories/nft-scam.repository.ts b/src/document-db/repositories/nft-scam.repository.ts index 2483a593f..3b6ae3b24 100644 --- a/src/document-db/repositories/nft-scam.repository.ts +++ b/src/document-db/repositories/nft-scam.repository.ts @@ -6,8 +6,8 @@ import { NftScamInfoModel, NftScamInfoDocument, } from 'src/modules/scam/models/nft-scam-info.model'; -import { Nft } from 'src/common'; import { ScamInfo } from 'src/modules/assets/models/ScamInfo.dto'; +import { Asset } from 'src/modules/assets/models'; @Injectable() export class NftScamInfoRepositoryService extends EntityRepository { @@ -42,7 +42,7 @@ export class NftScamInfoRepositoryService extends EntityRepository { if (!nfts || nfts.length === 0) { @@ -70,7 +70,7 @@ export class NftScamInfoRepositoryService extends EntityRepository { const updates: any = nfts.map((nft) => { diff --git a/src/modules/assets/models/NftTypes.enum.ts b/src/modules/assets/models/NftTypes.enum.ts index 88d62ef0e..35397412c 100644 --- a/src/modules/assets/models/NftTypes.enum.ts +++ b/src/modules/assets/models/NftTypes.enum.ts @@ -10,6 +10,7 @@ registerEnumType(NftTypeEnum, { }); export enum ScamInfoTypeEnum { + none = 'none', potentialScam = 'potentialScam', scam = 'scam', } diff --git a/src/modules/assets/models/ScamInfo.dto.ts b/src/modules/assets/models/ScamInfo.dto.ts index 182e4ee09..e9f7a9c6b 100644 --- a/src/modules/assets/models/ScamInfo.dto.ts +++ b/src/modules/assets/models/ScamInfo.dto.ts @@ -1,9 +1,8 @@ import { ObjectType, Field } from '@nestjs/graphql'; -import { Nft } from 'src/common'; import { ScamInfoApi } from 'src/common/services/mx-communication/models/scam-info.dto'; import { elasticDictionary } from 'src/config'; import { NftScamInfoModel } from 'src/modules/scam/models/nft-scam-info.model'; -import { ScamInfoTypeEnum } from '.'; +import { Asset, ScamInfoTypeEnum } from '.'; @ObjectType() export class ScamInfo { @Field(() => ScamInfoTypeEnum, { nullable: true }) @@ -25,7 +24,7 @@ export class ScamInfo { } static areApiAndElasticScamInfoDifferent( - nftFromApi: Nft, + nftFromApi: Asset, nftFromElastic: any, ): boolean { return ( @@ -37,7 +36,7 @@ export class ScamInfo { } static areApiAndDbScamInfoDifferent( - nftFromApi: Nft, + nftFromApi: Asset, nftFromDb: NftScamInfoModel, version: string, ): boolean { @@ -59,4 +58,14 @@ export class ScamInfo { (!nftFromDb.type && nftFromElastic?.[elasticDictionary.scamInfo.typeKey]) ); } + + static isScam(scamInfo: ScamInfo): boolean { + return scamInfo.type !== ScamInfoTypeEnum.none; + } + + static none(): ScamInfo { + return new ScamInfo({ + type: ScamInfoTypeEnum.none, + }); + } } diff --git a/src/modules/rabbitmq/blockchain-events/nft-events.module.ts b/src/modules/rabbitmq/blockchain-events/nft-events.module.ts index 654d0591a..6e25c9d57 100644 --- a/src/modules/rabbitmq/blockchain-events/nft-events.module.ts +++ b/src/modules/rabbitmq/blockchain-events/nft-events.module.ts @@ -6,7 +6,6 @@ import { RevertEventsService } from './revert.events.service'; import { MxCommunicationModule } from 'src/common'; import { MinterEventsService } from './minter-events.service'; import { CommonModule } from 'src/common.module'; -import { CacheModule } from 'src/common/services/caching/caching.module'; import { RarityUpdaterService } from 'src/crons/elastic.updater/rarity.updater.service'; import { NsfwUpdaterService } from 'src/crons/elastic.updater/nsfw.updater.service'; import { FlagNftService } from 'src/modules/admins/flag-nft.service'; @@ -42,6 +41,7 @@ import { OffersModuleGraph } from 'src/modules/offers/offers.module'; import { AcceptOfferEventHandler } from './handlers/acceptOffer-event.handler'; import { WithdrawOfferEventHandler } from './handlers/withdrawOffer-event.handler'; import { UpdateListingEventHandler } from './handlers/updateListing-event.handler'; +import { PluginModule } from 'src/plugins/plugin.module'; @Module({ imports: [ @@ -54,6 +54,7 @@ import { UpdateListingEventHandler } from './handlers/updateListing-event.handle forwardRef(() => MarketplacesModuleGraph), forwardRef(() => MxCommunicationModule), forwardRef(() => OffersModuleGraph), + forwardRef(() => PluginModule), UsdPriceModuleGraph, NftRarityModuleGraph, ScamModule, diff --git a/src/modules/rabbitmq/elastic-updates/elastic-updates-events.service.ts b/src/modules/rabbitmq/elastic-updates/elastic-updates-events.service.ts index 679ec06f0..96c36683a 100644 --- a/src/modules/rabbitmq/elastic-updates/elastic-updates-events.service.ts +++ b/src/modules/rabbitmq/elastic-updates/elastic-updates-events.service.ts @@ -138,7 +138,7 @@ export class ElasticUpdatesEventsService { ): Promise { await new Promise((resolve) => setTimeout(resolve, 5000)); - let nftsToUpdate: string[] = []; + let nftsToUpdate: Asset[] = []; let nftsToDelete: string[] = []; let collectionTypes: { [key: string]: string } = {}; @@ -174,7 +174,7 @@ export class ElasticUpdatesEventsService { } collectionTypes[collection] = nft.type; - nftsToUpdate.push(identifier); + nftsToUpdate.push(nft); } nftsToUpdate = [...new Set(nftsToUpdate)]; @@ -183,10 +183,11 @@ export class ElasticUpdatesEventsService { return this.documentDbService.deleteNftScamInfo(n); }); - nftsToUpdate.map( - async (collection) => - await this.nftScamInfoService.validateOrUpdateNftScamInfo(collection), - ); + await this.nftScamInfoService.validateOrUpdateNftsScamInfo(nftsToUpdate); + // nftsToUpdate.map( + // async (collection) => + // await this.nftScamInfoService.validateOrUpdateNftScamInfo(collection), + // ); await Promise.all(deletes); } diff --git a/src/modules/scam/collection-scam.service.ts b/src/modules/scam/collection-scam.service.ts index fd0053052..295b7c242 100644 --- a/src/modules/scam/collection-scam.service.ts +++ b/src/modules/scam/collection-scam.service.ts @@ -1,6 +1,4 @@ import { Injectable } from '@nestjs/common'; -import { MxApiService } from 'src/common'; -import { MxExtrasApiService } from 'src/common/services/mx-communication/mx-extras-api.service'; import { CacheEventsPublisherService } from '../rabbitmq/cache-invalidation/cache-invalidation-publisher/change-events-publisher.service'; import { CacheEventTypeEnum, @@ -10,7 +8,6 @@ import { @Injectable() export class CollectionScamService { constructor( - private mxExtrasApiService: MxExtrasApiService, private readonly cacheEventsPublisher: CacheEventsPublisherService, ) {} diff --git a/src/modules/scam/nft-scam.elastic.service.ts b/src/modules/scam/nft-scam.elastic.service.ts index 1e54144ee..feee99cd4 100644 --- a/src/modules/scam/nft-scam.elastic.service.ts +++ b/src/modules/scam/nft-scam.elastic.service.ts @@ -1,7 +1,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { MxElasticService, Nft } from 'src/common'; import { elasticDictionary } from 'src/config'; -import { ScamInfoTypeEnum } from '../assets/models'; +import { Asset, ScamInfoTypeEnum } from '../assets/models'; import { NftScamInfoModel } from './models/nft-scam-info.model'; import { getAllCollectionsFromElasticQuery, @@ -40,7 +40,7 @@ export class NftScamElasticService { } async setBulkNftScamInfoInElastic( - nfts: Nft[], + nfts: Asset[], clearScamInfoIfEmpty?: boolean, ): Promise { if (nfts.length > 0) { @@ -119,7 +119,7 @@ export class NftScamElasticService { return collections; } - buildNftScamInfoBulkUpdate(nfts: Nft[], clearScamInfo?: boolean): string[] { + buildNftScamInfoBulkUpdate(nfts: Asset[], clearScamInfo?: boolean): string[] { let updates: string[] = []; for (const nft of nfts) { if (nft.scamInfo) { diff --git a/src/modules/scam/nft-scam.service.ts b/src/modules/scam/nft-scam.service.ts index 9954af829..5a896fc7e 100644 --- a/src/modules/scam/nft-scam.service.ts +++ b/src/modules/scam/nft-scam.service.ts @@ -1,7 +1,7 @@ import { Injectable, Logger } from '@nestjs/common'; import { MxApiService, MxElasticService, Nft } from 'src/common'; import { ScamInfo } from '../assets/models/ScamInfo.dto'; -import { ScamInfoTypeEnum } from '../assets/models'; +import { Asset, ScamInfoTypeEnum } from '../assets/models'; import { NftScamElasticService } from './nft-scam.elastic.service'; import { NftScamRelatedData } from './models/nft-scam-data.model'; import { elasticDictionary } from 'src/config'; @@ -16,6 +16,7 @@ import { import { getAllCollectionNftsFromElasticQuery } from './nft-scam.queries'; import { AssetByIdentifierService } from '../assets'; import { Locker } from '@multiversx/sdk-nestjs'; +import { PluginService } from 'src/common/pluggins/plugin.service'; @Injectable() export class NftScamService { @@ -25,6 +26,7 @@ export class NftScamService { private nftScamElasticService: NftScamElasticService, private mxElasticService: MxElasticService, private mxApiService: MxApiService, + private readonly pluginsService: PluginService, private readonly cacheEventsPublisher: CacheEventsPublisherService, private readonly logger: Logger, ) {} @@ -34,12 +36,15 @@ export class NftScamService { nftScamRelatedData?: NftScamRelatedData, clearManualScamInfo: boolean = false, ): Promise { + const nft = await this.assetByIdentifierService.getAsset(identifier); + await this.pluginsService.computeScamInfo([nft]); + const [nftFromApi, nftFromElastic, nftFromDb, mxApiAbout]: [ - Nft, + Asset, any, NftScamInfoModel, MxApiAbout, - ] = await this.getNftsAndMxAbout(identifier, nftScamRelatedData); + ] = await this.getNftsAndMxAbout(nft, nftScamRelatedData); const scamEngineVersion = mxApiAbout.scamEngineVersion; if ( @@ -68,17 +73,60 @@ export class NftScamService { return true; } + async validateOrUpdateNftsScamInfo( + nfts: Asset[], + nftScamRelatedData?: NftScamRelatedData, + clearManualScamInfo: boolean = false, + ): Promise { + await this.pluginsService.computeScamInfo(nfts); + for (const nft of nfts) { + const [nftFromApi, nftFromElastic, nftFromDb, mxApiAbout]: [ + Asset, + any, + NftScamInfoModel, + MxApiAbout, + ] = await this.getNftsAndMxAbout(nft, nftScamRelatedData); + const scamEngineVersion = mxApiAbout.scamEngineVersion; + + if ( + nftFromDb?.version === elasticDictionary.scamInfo.manualVersionValue && + !clearManualScamInfo + ) { + return true; + } + + if (!nftFromApi.scamInfo) { + await this.validateOrUpdateScamInfoDataForNoScamNft( + scamEngineVersion, + nftFromApi, + nftFromElastic, + nftFromDb, + ); + } else if (nftFromApi.scamInfo) { + await this.validateOrUpdateScamInfoDataForScamNft( + scamEngineVersion, + nftFromApi, + nftFromElastic, + nftFromDb, + ); + } + + return true; + } + } + async getNftsAndMxAbout( - identifier: string, + nft: Asset, nftScamRelatedData?: NftScamRelatedData, - ): Promise<[Nft, any, NftScamInfoModel, MxApiAbout]> { + ): Promise<[Asset, any, NftScamInfoModel, MxApiAbout]> { return await Promise.all([ - nftScamRelatedData?.nftFromApi ?? - this.mxApiService.getNftScamInfo(identifier, true), + nft, nftScamRelatedData?.nftFromElastic ?? - this.nftScamElasticService.getNftWithScamInfoFromElastic(identifier), + this.nftScamElasticService.getNftWithScamInfoFromElastic( + nft.identifier, + ), nftScamRelatedData?.nftFromDb ?? - this.documentDbService.getNftScamInfo(identifier), + this.documentDbService.getNftScamInfo(nft.identifier), nftScamRelatedData?.mxApiAbout ?? this.mxApiService.getMxApiAbout(), ]); } @@ -167,11 +215,7 @@ export class NftScamService { async manuallyClearNftScamInfo(identifier: string): Promise { const nft = await this.assetByIdentifierService.getAsset(identifier); - const cleared = await this.validateOrUpdateNftScamInfo( - identifier, - {}, - true, - ); + const cleared = await this.validateOrUpdateNftsScamInfo([nft], {}, true); this.triggerCacheInvalidation(identifier, nft?.ownerAddress); return cleared; } @@ -191,7 +235,7 @@ export class NftScamService { private async validateOrUpdateScamInfoDataForNoScamNft( scamEngineVersion: string, - nftFromApi: Nft, + nftFromApi: Asset, nftFromElastic: any, nftFromDb: NftScamInfoModel, ): Promise { @@ -225,7 +269,7 @@ export class NftScamService { private async validateOrUpdateScamInfoDataForScamNft( scamEngineVersion: string, - nftFromApi: Nft, + nftFromApi: Asset, nftFromElastic: any, nftFromDb: NftScamInfoModel, ): Promise { @@ -302,9 +346,9 @@ export class NftScamService { private async filterOutdatedNfts( nftsFromElastic: any, scamEngineVersion: string, - ): Promise<[Nft[], Nft[], Nft[], NftScamInfoModel[]]> { + ): Promise<[Asset[], Asset[], Asset[], NftScamInfoModel[]]> { const [nftsOutdatedOrMissingFromDb, nftsToMigrateFromDbToElastic]: [ - Nft[], + Asset[], NftScamInfoModel[], ] = await this.getMissingNftsFromDbOrOutdatedInElastic( nftsFromElastic, @@ -319,8 +363,8 @@ export class NftScamService { } const [nftsNoScamOutdatedInElastic, nftsScamOutdatedInElastic]: [ - Nft[], - Nft[], + Asset[], + Asset[], ] = await this.filterOutdatedNftsInElastic( nftsOutdatedOrMissingFromDb, nftsFromElastic, @@ -337,8 +381,8 @@ export class NftScamService { private async getMissingNftsFromDbOrOutdatedInElastic( nftsFromElastic: any, scamEngineVersion: string, - ): Promise<[Nft[], NftScamInfoModel[]]> { - let nftsOutdatedOrMissingFromDb: Nft[] = []; + ): Promise<[Asset[], NftScamInfoModel[]]> { + let nftsOutdatedOrMissingFromDb: Asset[] = []; let nftsToMigrateFromDbToElastic: NftScamInfoModel[] = []; const identifiers = nftsFromElastic.map((nft) => nft.identifier); @@ -377,20 +421,20 @@ export class NftScamService { return [[], nftsToMigrateFromDbToElastic]; } - nftsOutdatedOrMissingFromDb = await this.mxApiService.getBulkNftScamInfo( - identifiers, - true, - ); + // await this.mxApiService.getBulkNftScamInfo( + // identifiers, + // true, + // ); return [nftsOutdatedOrMissingFromDb, nftsToMigrateFromDbToElastic]; } private async filterOutdatedNftsInElastic( - nftsOutdatedOrMissingFromDb: Nft[], + nftsOutdatedOrMissingFromDb: Asset[], nftsFromElastic: any, - ): Promise<[Nft[], Nft[]]> { - let nftsNoScamOutdatedInElastic: Nft[] = []; - let nftsScamOutdatedInElastic: Nft[] = []; + ): Promise<[Asset[], Asset[]]> { + let nftsNoScamOutdatedInElastic: Asset[] = []; + let nftsScamOutdatedInElastic: Asset[] = []; for (let i = 0; i < nftsOutdatedOrMissingFromDb?.length; i++) { const nftFromApi = nftsOutdatedOrMissingFromDb[i]; let nftFromElastic = nftsFromElastic.find( diff --git a/src/modules/scam/scam.module.ts b/src/modules/scam/scam.module.ts index 23299a2e2..ad45a40e0 100644 --- a/src/modules/scam/scam.module.ts +++ b/src/modules/scam/scam.module.ts @@ -1,6 +1,7 @@ import { Logger, Module } from '@nestjs/common'; import { CommonModule } from 'src/common.module'; import { DocumentDbModule } from 'src/document-db/document-db.module'; +import { PluginModule } from 'src/plugins/plugin.module'; import { AssetByIdentifierService } from '../assets'; import { AuthModule } from '../auth/auth.module'; import { CacheEventsPublisherModule } from '../rabbitmq/cache-invalidation/cache-invalidation-publisher/change-events-publisher.module'; @@ -16,6 +17,7 @@ import { NftScamService } from './nft-scam.service'; DocumentDbModule, AuthModule, CacheEventsPublisherModule, + PluginModule, ], providers: [ Logger, diff --git a/src/plugins.template/plugins.module.ts.template b/src/plugins.template/plugins.module.ts.template new file mode 100644 index 000000000..c414b34bb --- /dev/null +++ b/src/plugins.template/plugins.module.ts.template @@ -0,0 +1,8 @@ +import { Module } from '@nestjs/common'; +import { PluginService } from 'src/common/pluggins/plugin.service'; + +@Module({ + providers: [PluginService], + exports: [PluginService], +}) +export class PluginModule {}