From 96baff90283814314c28e13910f460b91e56225f Mon Sep 17 00:00:00 2001 From: hschiau Date: Fri, 31 May 2024 17:22:54 +0300 Subject: [PATCH 1/5] SERVICES-2427: add wildcard filtering by token ID, name or ticker - add 'wildcardToken' field on PairsFilter --- .../pair/services/pair.filtering.service.ts | 46 +++++++++++++++++++ .../pair/services/pair.metadata.builder.ts | 8 ++++ src/modules/router/models/filter.args.ts | 2 + 3 files changed, 56 insertions(+) diff --git a/src/modules/pair/services/pair.filtering.service.ts b/src/modules/pair/services/pair.filtering.service.ts index dfc57d5b7..3da72ad61 100644 --- a/src/modules/pair/services/pair.filtering.service.ts +++ b/src/modules/pair/services/pair.filtering.service.ts @@ -7,12 +7,14 @@ import { PairsFilter, } from 'src/modules/router/models/filter.args'; import BigNumber from 'bignumber.js'; +import { PairService } from './pair.service'; @Injectable() export class PairFilteringService { constructor( private readonly pairAbi: PairAbiService, private readonly pairCompute: PairComputeService, + private readonly pairService: PairService, ) {} async pairsByIssuedLpToken( @@ -82,6 +84,50 @@ export class PairFilteringService { return await Promise.resolve(pairsMetadata); } + async pairsByWildcardToken( + pairFilter: PairsFilter, + pairsMetadata: PairMetadata[], + ): Promise { + if ( + !pairFilter.wildcardToken || + pairFilter.wildcardToken.trim() === '' + ) { + return pairsMetadata; + } + + const searchTerm = pairFilter.wildcardToken.toUpperCase().trim(); + + const pairsFirstToken = await Promise.all( + pairsMetadata.map((pairMetadata) => + this.pairService.getFirstToken(pairMetadata.address), + ), + ); + const pairsSecondToken = await Promise.all( + pairsMetadata.map((pairMetadata) => + this.pairService.getSecondToken(pairMetadata.address), + ), + ); + + const filteredPairs: PairMetadata[] = []; + for (const [index, pair] of pairsMetadata.entries()) { + const firstToken = pairsFirstToken[index]; + const secondToken = pairsSecondToken[index]; + + if ( + firstToken.name.toUpperCase().includes(searchTerm) || + firstToken.identifier.toUpperCase().includes(searchTerm) || + firstToken.ticker.toUpperCase().includes(searchTerm) || + secondToken.name.toUpperCase().includes(searchTerm) || + secondToken.identifier.toUpperCase().includes(searchTerm) || + secondToken.ticker.toUpperCase().includes(searchTerm) + ) { + filteredPairs.push(pair); + } + } + + return filteredPairs; + } + async pairsByState( pairFilter: PairFilterArgs | PairsFilter, pairsMetadata: PairMetadata[], diff --git a/src/modules/pair/services/pair.metadata.builder.ts b/src/modules/pair/services/pair.metadata.builder.ts index e08ab4b77..c092b26e4 100644 --- a/src/modules/pair/services/pair.metadata.builder.ts +++ b/src/modules/pair/services/pair.metadata.builder.ts @@ -52,6 +52,14 @@ export class PairsMetadataBuilder { } async filterByTokens(): Promise { + if (this.filters.wildcardToken) { + this.pairsMetadata = + await this.filteringService.pairsByWildcardToken( + this.filters, + this.pairsMetadata, + ); + } + this.pairsMetadata = await this.filteringService.pairsByTokens( this.filters, this.pairsMetadata, diff --git a/src/modules/router/models/filter.args.ts b/src/modules/router/models/filter.args.ts index f3b207382..6a6d21afb 100644 --- a/src/modules/router/models/filter.args.ts +++ b/src/modules/router/models/filter.args.ts @@ -57,6 +57,8 @@ export class PairsFilter { hasDualFarms: boolean; @Field({ nullable: true }) minDeployedAt: number; + @Field({ nullable: true }) + wildcardToken: string; } @InputType() From eb406f8e88a9ec39fb6fb3717f39f10d39cee1ab Mon Sep 17 00:00:00 2001 From: hschiau Date: Mon, 3 Jun 2024 10:48:13 +0300 Subject: [PATCH 2/5] SERVICES-2427: fix failing unit test --- src/modules/pair/mocks/pair.service.mock.ts | 17 +++++++++++++++++ src/modules/router/specs/router.service.spec.ts | 2 ++ 2 files changed, 19 insertions(+) create mode 100644 src/modules/pair/mocks/pair.service.mock.ts diff --git a/src/modules/pair/mocks/pair.service.mock.ts b/src/modules/pair/mocks/pair.service.mock.ts new file mode 100644 index 000000000..a2ccfde99 --- /dev/null +++ b/src/modules/pair/mocks/pair.service.mock.ts @@ -0,0 +1,17 @@ +import { EsdtToken } from 'src/modules/tokens/models/esdtToken.model'; +import { PairsData } from './pair.constants'; +import { PairService } from '../services/pair.service'; + +export class PairServiceMock { + async getFirstToken(pairAddress: string): Promise { + return PairsData(pairAddress).firstToken; + } + async getSecondToken(pairAddress: string): Promise { + return PairsData(pairAddress).secondToken; + } +} + +export const PairServiceProvider = { + provide: PairService, + useClass: PairServiceMock, +}; diff --git a/src/modules/router/specs/router.service.spec.ts b/src/modules/router/specs/router.service.spec.ts index 986962261..1f2403f61 100644 --- a/src/modules/router/specs/router.service.spec.ts +++ b/src/modules/router/specs/router.service.spec.ts @@ -12,6 +12,7 @@ import winston from 'winston'; import { DynamicModuleUtils } from 'src/utils/dynamic.module.utils'; import { PairComputeServiceProvider } from 'src/modules/pair/mocks/pair.compute.service.mock'; import { PairFilteringService } from 'src/modules/pair/services/pair.filtering.service'; +import { PairServiceProvider } from 'src/modules/pair/mocks/pair.service.mock'; describe('RouterService', () => { let module: TestingModule; @@ -32,6 +33,7 @@ describe('RouterService', () => { RouterService, ApiConfigService, PairFilteringService, + PairServiceProvider, ], }).compile(); }); From cf43c6a5c5c79ca5cdebdeaacb1c284ed7996ab4 Mon Sep 17 00:00:00 2001 From: hschiau Date: Mon, 3 Jun 2024 16:39:59 +0300 Subject: [PATCH 3/5] SERVICES-2427: add tokens query filtering by token ID, name or ticker --- .../tokens/models/tokens.filter.args.ts | 2 ++ .../services/token.filtering.service.ts | 28 +++++++++++++++++++ src/modules/tokens/services/token.service.ts | 13 ++++++--- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/modules/tokens/models/tokens.filter.args.ts b/src/modules/tokens/models/tokens.filter.args.ts index 6f7c57697..7df49034b 100644 --- a/src/modules/tokens/models/tokens.filter.args.ts +++ b/src/modules/tokens/models/tokens.filter.args.ts @@ -30,6 +30,8 @@ export class TokensFilter { type?: string; @Field(() => Boolean, { defaultValue: false }) enabledSwaps: boolean; + @Field({ nullable: true }) + searchToken?: string; } @InputType() diff --git a/src/modules/tokens/services/token.filtering.service.ts b/src/modules/tokens/services/token.filtering.service.ts index 6ca532415..9a441957d 100644 --- a/src/modules/tokens/services/token.filtering.service.ts +++ b/src/modules/tokens/services/token.filtering.service.ts @@ -1,6 +1,7 @@ import { Inject, Injectable, forwardRef } from '@nestjs/common'; import { TokenService } from './token.service'; import { TokensFilter } from '../models/tokens.filter.args'; +import { EsdtToken } from '../models/esdtToken.model'; @Injectable() export class TokenFilteringService { @@ -43,4 +44,31 @@ export class TokenFilteringService { } return filteredIDs; } + + async tokensBySearchTerm( + tokensFilter: TokensFilter, + tokens: EsdtToken[], + ): Promise { + if ( + !tokensFilter.searchToken || + tokensFilter.searchToken.trim() === '' + ) { + return tokens; + } + + const searchTerm = tokensFilter.searchToken.toUpperCase().trim(); + + const filteredTokens: EsdtToken[] = []; + for (const token of tokens) { + if ( + token.name.toUpperCase().includes(searchTerm) || + token.identifier.toUpperCase().includes(searchTerm) || + token.ticker.toUpperCase().includes(searchTerm) + ) { + filteredTokens.push(token); + } + } + + return filteredTokens; + } } diff --git a/src/modules/tokens/services/token.service.ts b/src/modules/tokens/services/token.service.ts index 9913735b8..dd6383b2d 100644 --- a/src/modules/tokens/services/token.service.ts +++ b/src/modules/tokens/services/token.service.ts @@ -76,14 +76,19 @@ export class TokenService { tokenIDs, ); + let tokens = await Promise.all( + tokenIDs.map((tokenID) => this.getTokenMetadata(tokenID)), + ); + + tokens = await this.tokenFilteringService.tokensBySearchTerm( + filters, + tokens, + ); + if (sorting) { tokenIDs = await this.sortTokens(tokenIDs, sorting); } - const tokens = await Promise.all( - tokenIDs.map((tokenID) => this.getTokenMetadata(tokenID)), - ); - return new CollectionType({ count: tokens.length, items: tokens.slice( From b38c2e915020aed48d67f8eb7ed57404887cd2c9 Mon Sep 17 00:00:00 2001 From: hschiau Date: Tue, 4 Jun 2024 08:32:12 +0300 Subject: [PATCH 4/5] SERVICES-2427: rename search field on pairs query --- src/modules/pair/services/pair.filtering.service.ts | 7 ++----- src/modules/pair/services/pair.metadata.builder.ts | 2 +- src/modules/router/models/filter.args.ts | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/modules/pair/services/pair.filtering.service.ts b/src/modules/pair/services/pair.filtering.service.ts index 3da72ad61..843c722e6 100644 --- a/src/modules/pair/services/pair.filtering.service.ts +++ b/src/modules/pair/services/pair.filtering.service.ts @@ -88,14 +88,11 @@ export class PairFilteringService { pairFilter: PairsFilter, pairsMetadata: PairMetadata[], ): Promise { - if ( - !pairFilter.wildcardToken || - pairFilter.wildcardToken.trim() === '' - ) { + if (!pairFilter.searchToken || pairFilter.searchToken.trim() === '') { return pairsMetadata; } - const searchTerm = pairFilter.wildcardToken.toUpperCase().trim(); + const searchTerm = pairFilter.searchToken.toUpperCase().trim(); const pairsFirstToken = await Promise.all( pairsMetadata.map((pairMetadata) => diff --git a/src/modules/pair/services/pair.metadata.builder.ts b/src/modules/pair/services/pair.metadata.builder.ts index c092b26e4..48175a05c 100644 --- a/src/modules/pair/services/pair.metadata.builder.ts +++ b/src/modules/pair/services/pair.metadata.builder.ts @@ -52,7 +52,7 @@ export class PairsMetadataBuilder { } async filterByTokens(): Promise { - if (this.filters.wildcardToken) { + if (this.filters.searchToken) { this.pairsMetadata = await this.filteringService.pairsByWildcardToken( this.filters, diff --git a/src/modules/router/models/filter.args.ts b/src/modules/router/models/filter.args.ts index 6a6d21afb..729ff2084 100644 --- a/src/modules/router/models/filter.args.ts +++ b/src/modules/router/models/filter.args.ts @@ -58,7 +58,7 @@ export class PairsFilter { @Field({ nullable: true }) minDeployedAt: number; @Field({ nullable: true }) - wildcardToken: string; + searchToken: string; } @InputType() From 4ff5a27bddb21e5a788fc478831542a29d54dccb Mon Sep 17 00:00:00 2001 From: hschiau Date: Tue, 4 Jun 2024 17:16:50 +0300 Subject: [PATCH 5/5] SERVICES-2427: fixes after review - add min 3 chars limit for performing search - update router service unit tests (remove pair service mock + use existing mocked providers as dependencies) --- src/modules/pair/mocks/pair.service.mock.ts | 17 ----------------- .../pair/services/pair.filtering.service.ts | 5 ++++- src/modules/router/specs/router.service.spec.ts | 12 ++++++++++-- .../tokens/services/token.filtering.service.ts | 2 +- 4 files changed, 15 insertions(+), 21 deletions(-) delete mode 100644 src/modules/pair/mocks/pair.service.mock.ts diff --git a/src/modules/pair/mocks/pair.service.mock.ts b/src/modules/pair/mocks/pair.service.mock.ts deleted file mode 100644 index a2ccfde99..000000000 --- a/src/modules/pair/mocks/pair.service.mock.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { EsdtToken } from 'src/modules/tokens/models/esdtToken.model'; -import { PairsData } from './pair.constants'; -import { PairService } from '../services/pair.service'; - -export class PairServiceMock { - async getFirstToken(pairAddress: string): Promise { - return PairsData(pairAddress).firstToken; - } - async getSecondToken(pairAddress: string): Promise { - return PairsData(pairAddress).secondToken; - } -} - -export const PairServiceProvider = { - provide: PairService, - useClass: PairServiceMock, -}; diff --git a/src/modules/pair/services/pair.filtering.service.ts b/src/modules/pair/services/pair.filtering.service.ts index 843c722e6..5e9d862cf 100644 --- a/src/modules/pair/services/pair.filtering.service.ts +++ b/src/modules/pair/services/pair.filtering.service.ts @@ -88,7 +88,10 @@ export class PairFilteringService { pairFilter: PairsFilter, pairsMetadata: PairMetadata[], ): Promise { - if (!pairFilter.searchToken || pairFilter.searchToken.trim() === '') { + if ( + !pairFilter.searchToken || + pairFilter.searchToken.trim().length < 3 + ) { return pairsMetadata; } diff --git a/src/modules/router/specs/router.service.spec.ts b/src/modules/router/specs/router.service.spec.ts index 1f2403f61..34d7e5a23 100644 --- a/src/modules/router/specs/router.service.spec.ts +++ b/src/modules/router/specs/router.service.spec.ts @@ -12,7 +12,11 @@ import winston from 'winston'; import { DynamicModuleUtils } from 'src/utils/dynamic.module.utils'; import { PairComputeServiceProvider } from 'src/modules/pair/mocks/pair.compute.service.mock'; import { PairFilteringService } from 'src/modules/pair/services/pair.filtering.service'; -import { PairServiceProvider } from 'src/modules/pair/mocks/pair.service.mock'; +import { PairService } from 'src/modules/pair/services/pair.service'; +import { WrapAbiServiceProvider } from 'src/modules/wrapping/mocks/wrap.abi.service.mock'; +import { TokenServiceProvider } from 'src/modules/tokens/mocks/token.service.mock'; +import { ContextGetterServiceProvider } from 'src/services/context/mocks/context.getter.service.mock'; +import { MXApiServiceProvider } from 'src/services/multiversx-communication/mx.api.service.mock'; describe('RouterService', () => { let module: TestingModule; @@ -33,7 +37,11 @@ describe('RouterService', () => { RouterService, ApiConfigService, PairFilteringService, - PairServiceProvider, + PairService, + WrapAbiServiceProvider, + TokenServiceProvider, + ContextGetterServiceProvider, + MXApiServiceProvider, ], }).compile(); }); diff --git a/src/modules/tokens/services/token.filtering.service.ts b/src/modules/tokens/services/token.filtering.service.ts index 9a441957d..b30917b29 100644 --- a/src/modules/tokens/services/token.filtering.service.ts +++ b/src/modules/tokens/services/token.filtering.service.ts @@ -51,7 +51,7 @@ export class TokenFilteringService { ): Promise { if ( !tokensFilter.searchToken || - tokensFilter.searchToken.trim() === '' + tokensFilter.searchToken.trim().length < 3 ) { return tokens; }