From 637d23ef6255b1de81664bef8290b58701492c46 Mon Sep 17 00:00:00 2001 From: hschiau Date: Wed, 11 Dec 2024 17:52:58 +0200 Subject: [PATCH 1/2] MEX-527: refactor pair filtering service - update PairFilteringService to work with pair models with the fields already populated (functional service) - update PairMetadataBuilder to use the functional filtering service - update pair methods (regular and filtered) in router service to use the builder - remove duplicate code in router service --- src/modules/pair/mocks/pair.service.mock.ts | 3 + src/modules/pair/pair.module.ts | 4 - .../pair/services/pair.filtering.service.ts | 395 +++++++----------- .../pair/services/pair.metadata.builder.ts | 259 +++++++++--- src/modules/router/services/router.service.ts | 208 +-------- 5 files changed, 383 insertions(+), 486 deletions(-) diff --git a/src/modules/pair/mocks/pair.service.mock.ts b/src/modules/pair/mocks/pair.service.mock.ts index 5ee2562be..75281acbc 100644 --- a/src/modules/pair/mocks/pair.service.mock.ts +++ b/src/modules/pair/mocks/pair.service.mock.ts @@ -7,6 +7,9 @@ export class PairServiceMock { (address) => PairsData(address).liquidityPoolToken.identifier, ); } + async getAllStates(pairAddresses: string[]): Promise { + return pairAddresses.map((address) => PairsData(address).state); + } async getAllFeeStates(pairAddresses: string[]): Promise { return pairAddresses.map((address) => PairsData(address).feeState); } diff --git a/src/modules/pair/pair.module.ts b/src/modules/pair/pair.module.ts index 219aba335..e454a8212 100644 --- a/src/modules/pair/pair.module.ts +++ b/src/modules/pair/pair.module.ts @@ -21,7 +21,6 @@ import { ComposableTasksModule } from '../composable-tasks/composable.tasks.modu import { RemoteConfigModule } from '../remote-config/remote-config.module'; import { StakingProxyModule } from '../staking-proxy/staking.proxy.module'; import { FarmModuleV2 } from '../farm/v2/farm.v2.module'; -import { PairFilteringService } from './services/pair.filtering.service'; import { StakingModule } from '../staking/staking.module'; import { EnergyModule } from '../energy/energy.module'; import { PairAbiLoader } from './services/pair.abi.loader'; @@ -51,11 +50,9 @@ import { ElasticSearchModule } from 'src/services/elastic-search/elastic.search. PairComputeService, PairAbiService, PairTransactionService, - PairFilteringService, PairAbiLoader, PairComputeLoader, PairResolver, - PairFilteringService, PairCompoundedAPRResolver, PairRewardTokensResolver, ], @@ -64,7 +61,6 @@ import { ElasticSearchModule } from 'src/services/elastic-search/elastic.search. PairSetterService, PairComputeService, PairAbiService, - PairFilteringService, ], }) export class PairModule {} diff --git a/src/modules/pair/services/pair.filtering.service.ts b/src/modules/pair/services/pair.filtering.service.ts index 5471f84aa..0af161d90 100644 --- a/src/modules/pair/services/pair.filtering.service.ts +++ b/src/modules/pair/services/pair.filtering.service.ts @@ -1,334 +1,247 @@ -import { Injectable } from '@nestjs/common'; -import { PairAbiService } from './pair.abi.service'; -import { PairComputeService } from './pair.compute.service'; -import { PairMetadata } from 'src/modules/router/models/pair.metadata.model'; import { PairFilterArgs, PairsFilter, } from 'src/modules/router/models/filter.args'; import BigNumber from 'bignumber.js'; -import { PairService } from './pair.service'; +import { PairModel } from '../models/pair.model'; -@Injectable() export class PairFilteringService { - constructor( - private readonly pairAbi: PairAbiService, - private readonly pairCompute: PairComputeService, - private readonly pairService: PairService, - ) {} - - async pairsByIssuedLpToken( - pairFilter: PairFilterArgs | PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { - if (!pairFilter.issuedLpToken) { - return pairsMetadata; + static pairsByIssuedLpToken( + filters: PairFilterArgs | PairsFilter, + pairs: PairModel[], + ): PairModel[] { + if (!filters.issuedLpToken) { + return pairs; } - const lpTokensIDs = await this.pairService.getAllLpTokensIds( - pairsMetadata.map((pairMetadata) => pairMetadata.address), - ); + return pairs.filter((pair) => pair.liquidityPoolToken !== undefined); + } - const filteredPairsMetadata = []; - for (let index = 0; index < lpTokensIDs.length; index++) { - if ( - lpTokensIDs[index] === undefined || - lpTokensIDs[index] === 'undefined' || - lpTokensIDs[index] === '' - ) { - continue; - } - filteredPairsMetadata.push(pairsMetadata[index]); + static pairsByAddress( + filters: PairFilterArgs | PairsFilter, + pairs: PairModel[], + ): PairModel[] { + if (!filters.addresses || filters.addresses.length === 0) { + return pairs; } - return filteredPairsMetadata; + return pairs.filter((pair) => filters.addresses.includes(pair.address)); } - async pairsByAddress( - pairFilter: PairFilterArgs | PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { - if (pairFilter.addresses) { - pairsMetadata = pairsMetadata.filter((pair) => - pairFilter.addresses.includes(pair.address), - ); + static pairsByTokens( + filters: PairFilterArgs | PairsFilter, + pairs: PairModel[], + ): PairModel[] { + if (filters instanceof PairsFilter) { + pairs = PairFilteringService.pairsByWildcardToken(filters, pairs); } - return await Promise.resolve(pairsMetadata); - } - async pairsByTokens( - pairFilter: PairFilterArgs | PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { - if (pairFilter.firstTokenID) { - if (pairFilter.secondTokenID) { - pairsMetadata = pairsMetadata.filter( + if (filters.firstTokenID) { + if (filters.secondTokenID) { + pairs = pairs.filter( (pair) => - (pairFilter.firstTokenID === pair.firstTokenID && - pairFilter.secondTokenID === pair.secondTokenID) || - (pairFilter.firstTokenID === pair.secondTokenID && - pairFilter.secondTokenID === pair.firstTokenID), + (pair.firstToken.identifier === filters.firstTokenID && + pair.secondToken.identifier === + filters.secondTokenID) || + (pair.firstToken.identifier === filters.secondTokenID && + pair.secondToken.identifier === + filters.firstTokenID), ); } else { - pairsMetadata = pairsMetadata.filter( - (pair) => pairFilter.firstTokenID === pair.firstTokenID, + pairs = pairs.filter( + (pair) => + pair.firstToken.identifier === filters.firstTokenID, ); } - } else if (pairFilter.secondTokenID) { - pairsMetadata = pairsMetadata.filter( - (pair) => pairFilter.secondTokenID === pair.secondTokenID, + } else if (filters.secondTokenID) { + pairs = pairs.filter( + (pair) => pair.secondToken.identifier === filters.secondTokenID, ); } - return await Promise.resolve(pairsMetadata); + + return pairs; } - async pairsByWildcardToken( - pairFilter: PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { - if ( - !pairFilter.searchToken || - pairFilter.searchToken.trim().length < 3 - ) { - return pairsMetadata; + static pairsByWildcardToken( + filters: PairsFilter, + pairs: PairModel[], + ): PairModel[] { + if (!filters.searchToken || filters.searchToken.trim().length < 3) { + return pairs; } - const searchTerm = pairFilter.searchToken.toUpperCase().trim(); - const pairsAddresses = pairsMetadata.map( - (pairMetadata) => pairMetadata.address, - ); + const searchTerm = filters.searchToken.toUpperCase().trim(); - const pairsFirstToken = await this.pairService.getAllFirstTokens( - pairsAddresses, - ); - const pairsSecondToken = await this.pairService.getAllSecondTokens( - pairsAddresses, + return pairs.filter( + (pair) => + pair.firstToken.name.toUpperCase().includes(searchTerm) || + pair.firstToken.identifier.toUpperCase().includes(searchTerm) || + pair.firstToken.ticker.toUpperCase().includes(searchTerm) || + pair.secondToken.name.toUpperCase().includes(searchTerm) || + pair.secondToken.identifier + .toUpperCase() + .includes(searchTerm) || + pair.secondToken.ticker.toUpperCase().includes(searchTerm), ); - - 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 pairsByLpTokenIds( - pairFilter: PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { - if (!pairFilter.lpTokenIds || pairFilter.lpTokenIds.length === 0) { - return pairsMetadata; + static pairsByLpTokenIds( + filters: PairsFilter, + pairs: PairModel[], + ): PairModel[] { + if (!filters.lpTokenIds || filters.lpTokenIds.length === 0) { + return pairs; } - const lpTokensIDs = await this.pairService.getAllLpTokensIds( - pairsMetadata.map((pairMetadata) => pairMetadata.address), - ); - - return pairsMetadata.filter((_, index) => - pairFilter.lpTokenIds.includes(lpTokensIDs[index]), + return pairs.filter( + (pair) => + pair.liquidityPoolToken !== undefined && + filters.lpTokenIds.includes(pair.liquidityPoolToken.identifier), ); } - async pairsByFarmTokens( - pairFilter: PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { - if (!pairFilter.farmTokens || pairFilter.farmTokens.length === 0) { - return pairsMetadata; + static pairsByFarmTokens( + filters: PairsFilter, + pairs: PairModel[], + farmTokens: string[], + ): PairModel[] { + if (!filters.farmTokens || filters.farmTokens.length === 0) { + return pairs; } - const farmTokens = await Promise.all( - pairsMetadata.map((pairMetadata) => - this.pairCompute.getPairFarmToken(pairMetadata.address), - ), - ); - - return pairsMetadata.filter( + return pairs.filter( (_, index) => farmTokens[index] && - pairFilter.farmTokens.includes(farmTokens[index]), + filters.farmTokens.includes(farmTokens[index]), ); } - async pairsByState( - pairFilter: PairFilterArgs | PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { - if (!pairFilter.state || pairFilter.state.length === 0) { - return pairsMetadata; + static pairsByState( + filters: PairFilterArgs | PairsFilter, + pairs: PairModel[], + ): PairModel[] { + if ( + !filters.state || + (Array.isArray(filters.state) && filters.state.length === 0) + ) { + return pairs; } - const pairsStates = await this.pairService.getAllStates( - pairsMetadata.map((pair) => pair.address), - ); - - return pairsMetadata.filter((_, index) => { - if (!Array.isArray(pairFilter.state)) { - return pairsStates[index] === pairFilter.state; + return pairs.filter((pair) => { + if (!Array.isArray(filters.state)) { + return pair.state === filters.state; } - return pairFilter.state.includes(pairsStates[index]); + return filters.state.includes(pair.state); }); } - async pairsByFeeState( - pairFilter: PairFilterArgs | PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { + static pairsByFeeState( + filters: PairFilterArgs | PairsFilter, + pairs: PairModel[], + ): PairModel[] { if ( - typeof pairFilter.feeState === 'undefined' || - pairFilter.feeState === null + typeof filters.feeState === 'undefined' || + filters.feeState === null ) { - return pairsMetadata; + return pairs; } - const pairsFeeStates = await this.pairService.getAllFeeStates( - pairsMetadata.map((pair) => pair.address), - ); - - return pairsMetadata.filter( - (_, index) => pairsFeeStates[index] === pairFilter.feeState, - ); + return pairs.filter((pair) => pair.feeState === filters.feeState); } - async pairsByVolume( - pairFilter: PairFilterArgs | PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { - if (!pairFilter.minVolume) { - return pairsMetadata; + static pairsByVolume( + filters: PairFilterArgs | PairsFilter, + pairs: PairModel[], + ): PairModel[] { + if (!filters.minVolume) { + return pairs; } - const pairsVolumes = await this.pairCompute.getAllVolumeUSD( - pairsMetadata.map((pair) => pair.address), - ); - - return pairsMetadata.filter((_, index) => { - const volume = new BigNumber(pairsVolumes[index]); - return volume.gte(pairFilter.minVolume); + return pairs.filter((pair) => { + return new BigNumber(pair.volumeUSD24h).gte(filters.minVolume); }); } - async pairsByLockedValueUSD( - pairFilter: PairFilterArgs | PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { - if (!pairFilter.minLockedValueUSD) { - return pairsMetadata; + static pairsByLockedValueUSD( + filters: PairFilterArgs | PairsFilter, + pairs: PairModel[], + ): PairModel[] { + if (!filters.minLockedValueUSD) { + return pairs; } - const pairsLiquidityUSD = await this.pairService.getAllLockedValueUSD( - pairsMetadata.map((pair) => pair.address), - ); - - return pairsMetadata.filter((_, index) => { - const lockedValueUSD = new BigNumber(pairsLiquidityUSD[index]); - return lockedValueUSD.gte(pairFilter.minLockedValueUSD); + return pairs.filter((pair) => { + return new BigNumber(pair.lockedValueUSD).gte( + filters.minLockedValueUSD, + ); }); } - async pairsByTradesCount( - pairFilter: PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { - if (!pairFilter.minTradesCount) { - return pairsMetadata; + static pairsByTradesCount( + filters: PairsFilter, + pairs: PairModel[], + ): PairModel[] { + if (!filters.minTradesCount) { + return pairs; } - const pairsTradesCount = await this.pairService.getAllTradesCount( - pairsMetadata.map((pair) => pair.address), - ); - - return pairsMetadata.filter( - (_, index) => pairsTradesCount[index] >= pairFilter.minTradesCount, + return pairs.filter( + (pair) => pair.tradesCount >= filters.minTradesCount, ); } - async pairsByTradesCount24h( - pairFilter: PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { - if (!pairFilter.minTradesCount24h) { - return pairsMetadata; + static pairsByTradesCount24h( + filters: PairsFilter, + pairs: PairModel[], + ): PairModel[] { + if (!filters.minTradesCount24h) { + return pairs; } - const pairsTradesCount24h = await this.pairCompute.getAllTradesCount24h( - pairsMetadata.map((pair) => pair.address), - ); - - return pairsMetadata.filter( - (_, index) => - pairsTradesCount24h[index] >= pairFilter.minTradesCount24h, + return pairs.filter( + (pair) => pair.tradesCount24h >= filters.minTradesCount24h, ); } - async pairsByHasFarms( - pairFilter: PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { + static pairsByHasFarms( + filters: PairsFilter, + pairs: PairModel[], + ): PairModel[] { if ( - typeof pairFilter.hasFarms === 'undefined' || - pairFilter.hasFarms === null + typeof filters.hasFarms === 'undefined' || + filters.hasFarms === null ) { - return pairsMetadata; + return pairs; } - const pairsHasFarms = await this.pairService.getAllHasFarms( - pairsMetadata.map((pair) => pair.address), - ); - - return pairsMetadata.filter( - (_, index) => pairsHasFarms[index] === pairFilter.hasFarms, - ); + return pairs.filter((pair) => pair.hasFarms === filters.hasFarms); } - async pairsByHasDualFarms( - pairFilter: PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { + static pairsByHasDualFarms( + filters: PairsFilter, + pairs: PairModel[], + ): PairModel[] { if ( - typeof pairFilter.hasDualFarms === 'undefined' || - pairFilter.hasDualFarms === null + typeof filters.hasDualFarms === 'undefined' || + filters.hasDualFarms === null ) { - return pairsMetadata; + return pairs; } - const pairsHasDualFarms = await this.pairService.getAllHasDualFarms( - pairsMetadata.map((pair) => pair.address), - ); - - return pairsMetadata.filter( - (_, index) => pairsHasDualFarms[index] === pairFilter.hasDualFarms, + return pairs.filter( + (pair) => pair.hasDualFarms === filters.hasDualFarms, ); } - async pairsByDeployedAt( - pairFilter: PairsFilter, - pairsMetadata: PairMetadata[], - ): Promise { - if (!pairFilter.minDeployedAt) { - return pairsMetadata; + static pairsByDeployedAt( + filters: PairsFilter, + pairs: PairModel[], + ): PairModel[] { + if (!filters.minDeployedAt) { + return pairs; } - const pairsDeployedAt = await this.pairService.getAllDeployedAt( - pairsMetadata.map((pair) => pair.address), - ); - - return pairsMetadata.filter( - (_, index) => pairsDeployedAt[index] >= pairFilter.minDeployedAt, - ); + return pairs.filter((pair) => pair.deployedAt >= filters.minDeployedAt); } } diff --git a/src/modules/pair/services/pair.metadata.builder.ts b/src/modules/pair/services/pair.metadata.builder.ts index 026d24e2a..1ea94c0d2 100644 --- a/src/modules/pair/services/pair.metadata.builder.ts +++ b/src/modules/pair/services/pair.metadata.builder.ts @@ -1,20 +1,25 @@ -import { PairsFilter } from 'src/modules/router/models/filter.args'; +import { + PairFilterArgs, + PairsFilter, +} from 'src/modules/router/models/filter.args'; import { PairMetadata } from 'src/modules/router/models/pair.metadata.model'; +import { PairModel } from '../models/pair.model'; +import { PairService } from './pair.service'; +import { PairComputeService } from './pair.compute.service'; +import { EsdtToken } from 'src/modules/tokens/models/esdtToken.model'; import { PairFilteringService } from './pair.filtering.service'; export class PairsMetadataBuilder { - private pairsMetadata: PairMetadata[]; - private filters: PairsFilter; - private filteringService: PairFilteringService; + private pairs: PairModel[]; + private filters: PairsFilter | PairFilterArgs; + private pairService: PairService; + private pairCompute: PairComputeService; + private lpTokensIndexed: boolean; - constructor( - pairsMetadata: PairMetadata[], - filters: PairsFilter, - filteringService: PairFilteringService, - ) { - this.pairsMetadata = pairsMetadata; - this.filters = filters; - this.filteringService = filteringService; + constructor(pairService: PairService, pairCompute: PairComputeService) { + this.pairService = pairService; + this.pairCompute = pairCompute; + this.lpTokensIndexed = false; } static get availableFilters() { @@ -27,7 +32,23 @@ export class PairsMetadataBuilder { ); } - async applyAllFilters(): Promise { + async applyAllFilters( + pairsMetadata: PairMetadata[], + filters: PairsFilter | PairFilterArgs, + ): Promise { + this.pairs = pairsMetadata.map( + (pairMetadata) => + new PairModel({ + address: pairMetadata.address, + firstToken: new EsdtToken({ + identifier: pairMetadata.firstTokenID, + }), + secondToken: new EsdtToken({ + identifier: pairMetadata.secondTokenID, + }), + }), + ); + this.filters = filters; for (const filterFunction of PairsMetadataBuilder.availableFilters) { await this[filterFunction](); } @@ -36,126 +57,266 @@ export class PairsMetadataBuilder { } async filterByIssuedLpToken(): Promise { - this.pairsMetadata = await this.filteringService.pairsByIssuedLpToken( + await this.indexLpTokens(); + + this.pairs = PairFilteringService.pairsByIssuedLpToken( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } async filterByAddress(): Promise { - this.pairsMetadata = await this.filteringService.pairsByAddress( + this.pairs = PairFilteringService.pairsByAddress( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } async filterByTokens(): Promise { - if (this.filters.searchToken) { - this.pairsMetadata = - await this.filteringService.pairsByWildcardToken( - this.filters, - this.pairsMetadata, - ); + if (this.filters instanceof PairsFilter) { + const pairsFirstToken = await this.pairService.getAllFirstTokens( + this.pairs.map((pair) => pair.address), + ); + const pairsSecondToken = await this.pairService.getAllSecondTokens( + this.pairs.map((pair) => pair.address), + ); + + this.pairs.forEach((pair, index) => { + pair.firstToken = pairsFirstToken[index]; + pair.secondToken = pairsSecondToken[index]; + }); } - this.pairsMetadata = await this.filteringService.pairsByTokens( + this.pairs = PairFilteringService.pairsByTokens( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } async filterByLpTokens(): Promise { - this.pairsMetadata = await this.filteringService.pairsByLpTokenIds( + if (!(this.filters instanceof PairsFilter)) { + return this; + } + + await this.indexLpTokens(); + + this.pairs = PairFilteringService.pairsByLpTokenIds( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } async filterByFarmTokens(): Promise { - this.pairsMetadata = await this.filteringService.pairsByFarmTokens( + if ( + !(this.filters instanceof PairsFilter) || + !this.filters.farmTokens || + this.filters.farmTokens.length === 0 + ) { + return this; + } + + const farmTokens = await Promise.all( + this.pairs.map((pairMetadata) => + this.pairCompute.getPairFarmToken(pairMetadata.address), + ), + ); + + this.pairs = PairFilteringService.pairsByFarmTokens( this.filters, - this.pairsMetadata, + this.pairs, + farmTokens, ); return this; } async filterByState(): Promise { - this.pairsMetadata = await this.filteringService.pairsByState( + const pairsStates = await this.pairService.getAllStates( + this.pairs.map((pair) => pair.address), + ); + + this.pairs.forEach((pair, index) => (pair.state = pairsStates[index])); + + this.pairs = PairFilteringService.pairsByState( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } async filterByFeeState(): Promise { - this.pairsMetadata = await this.filteringService.pairsByFeeState( + const pairsFeeStates = await this.pairService.getAllFeeStates( + this.pairs.map((pair) => pair.address), + ); + + this.pairs.forEach( + (pair, index) => (pair.feeState = pairsFeeStates[index]), + ); + + this.pairs = PairFilteringService.pairsByFeeState( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } async filterByVolume(): Promise { - this.pairsMetadata = await this.filteringService.pairsByVolume( + const pairsVolumes = await this.pairCompute.getAllVolumeUSD( + this.pairs.map((pair) => pair.address), + ); + + this.pairs.forEach( + (pair, index) => (pair.volumeUSD24h = pairsVolumes[index]), + ); + + this.pairs = PairFilteringService.pairsByVolume( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } async filterByLockedValueUSD(): Promise { - this.pairsMetadata = await this.filteringService.pairsByLockedValueUSD( + const pairsLiquidityUSD = await this.pairService.getAllLockedValueUSD( + this.pairs.map((pair) => pair.address), + ); + + this.pairs.forEach( + (pair, index) => (pair.lockedValueUSD = pairsLiquidityUSD[index]), + ); + + this.pairs = PairFilteringService.pairsByLockedValueUSD( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } async filterByTradesCount(): Promise { - this.pairsMetadata = await this.filteringService.pairsByTradesCount( + if (!(this.filters instanceof PairsFilter)) { + return this; + } + + const pairsTradesCount = await this.pairService.getAllTradesCount( + this.pairs.map((pair) => pair.address), + ); + + this.pairs.forEach( + (pair, index) => (pair.tradesCount = pairsTradesCount[index]), + ); + this.pairs = PairFilteringService.pairsByTradesCount( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } async filterByTradesCount24h(): Promise { - this.pairsMetadata = await this.filteringService.pairsByTradesCount24h( + if (!(this.filters instanceof PairsFilter)) { + return this; + } + + const pairsTradesCount24h = await this.pairCompute.getAllTradesCount24h( + this.pairs.map((pair) => pair.address), + ); + + this.pairs.forEach( + (pair, index) => (pair.tradesCount24h = pairsTradesCount24h[index]), + ); + + this.pairs = PairFilteringService.pairsByTradesCount24h( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } async filterByHasFarms(): Promise { - this.pairsMetadata = await this.filteringService.pairsByHasFarms( + if (!(this.filters instanceof PairsFilter)) { + return this; + } + + const pairsHasFarms = await this.pairService.getAllHasFarms( + this.pairs.map((pair) => pair.address), + ); + + this.pairs.forEach( + (pair, index) => (pair.hasFarms = pairsHasFarms[index]), + ); + + this.pairs = PairFilteringService.pairsByHasFarms( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } async filterByHasDualFarms(): Promise { - this.pairsMetadata = await this.filteringService.pairsByHasDualFarms( + if (!(this.filters instanceof PairsFilter)) { + return this; + } + + const pairsHasDualFarms = await this.pairService.getAllHasDualFarms( + this.pairs.map((pair) => pair.address), + ); + + this.pairs.forEach( + (pair, index) => (pair.hasDualFarms = pairsHasDualFarms[index]), + ); + + this.pairs = PairFilteringService.pairsByHasDualFarms( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } async filterByDeployedAt(): Promise { - this.pairsMetadata = await this.filteringService.pairsByDeployedAt( + if (!(this.filters instanceof PairsFilter)) { + return this; + } + + const pairsDeployedAt = await this.pairService.getAllDeployedAt( + this.pairs.map((pair) => pair.address), + ); + + this.pairs.forEach( + (pair, index) => (pair.deployedAt = pairsDeployedAt[index]), + ); + + this.pairs = PairFilteringService.pairsByDeployedAt( this.filters, - this.pairsMetadata, + this.pairs, ); return this; } - async build(): Promise { - return this.pairsMetadata; + build(): PairModel[] { + return this.pairs.map( + (pair) => new PairModel({ address: pair.address }), + ); + } + + private async indexLpTokens(): Promise { + if (this.lpTokensIndexed || this.pairs.length === 0) { + return; + } + + const lpTokensIDs = await this.pairService.getAllLpTokensIds( + this.pairs.map((pair) => pair.address), + ); + + this.pairs.forEach( + (pair, index) => + (pair.liquidityPoolToken = + lpTokensIDs[index] !== undefined + ? new EsdtToken({ + identifier: lpTokensIDs[index], + }) + : undefined), + ); } } diff --git a/src/modules/router/services/router.service.ts b/src/modules/router/services/router.service.ts index 0ce7ce4b0..745b53df9 100644 --- a/src/modules/router/services/router.service.ts +++ b/src/modules/router/services/router.service.ts @@ -9,13 +9,11 @@ import { PairSortingArgs, PairsFilter, } from '../models/filter.args'; -import { PairAbiService } from 'src/modules/pair/services/pair.abi.service'; import { RouterAbiService } from './router.abi.service'; import { PairComputeService } from 'src/modules/pair/services/pair.compute.service'; import BigNumber from 'bignumber.js'; import { CollectionType } from 'src/modules/common/collection.type'; import { PairsMetadataBuilder } from 'src/modules/pair/services/pair.metadata.builder'; -import { PairFilteringService } from 'src/modules/pair/services/pair.filtering.service'; import { SortingOrder } from 'src/modules/common/page.data'; import { CacheService } from '@multiversx/sdk-nestjs-cache'; import { PairService } from 'src/modules/pair/services/pair.service'; @@ -23,10 +21,8 @@ import { PairService } from 'src/modules/pair/services/pair.service'; @Injectable() export class RouterService { constructor( - private readonly pairAbi: PairAbiService, private readonly routerAbi: RouterAbiService, private readonly pairCompute: PairComputeService, - private readonly pairFilteringService: PairFilteringService, private readonly cacheService: CacheService, private readonly pairService: PairService, ) {} @@ -48,33 +44,25 @@ export class RouterService { filters: PairsFilter, sorting: PairSortingArgs, ): Promise> { - let pairsMetadata = await this.routerAbi.pairsMetadata(); + const pairsMetadata = await this.routerAbi.pairsMetadata(); const builder = new PairsMetadataBuilder( - pairsMetadata, - filters, - this.pairFilteringService, + this.pairService, + this.pairCompute, ); - await builder.applyAllFilters(); + await builder.applyAllFilters(pairsMetadata, filters); - pairsMetadata = await builder.build(); + let pairs = builder.build(); if (sorting) { - pairsMetadata = await this.sortPairs( - pairsMetadata, + pairs = await this.sortPairs( + pairs, sorting.sortField, sorting.sortOrder, ); } - const pairs = pairsMetadata.map( - (pairMetadata) => - new PairModel({ - address: pairMetadata.address, - }), - ); - return new CollectionType({ count: pairs.length, items: pairs.slice(offset, offset + limit), @@ -86,182 +74,18 @@ export class RouterService { limit: number, pairFilter: PairFilterArgs, ): Promise { - let pairsMetadata = await this.routerAbi.pairsMetadata(); - if (pairFilter.issuedLpToken) { - pairsMetadata = await this.pairsByIssuedLpToken(pairsMetadata); - } - - pairsMetadata = this.filterPairsByAddress(pairFilter, pairsMetadata); - pairsMetadata = this.filterPairsByTokens(pairFilter, pairsMetadata); - pairsMetadata = await this.filterPairsByState( - pairFilter, - pairsMetadata, - ); - pairsMetadata = await this.filterPairsByFeeState( - pairFilter, - pairsMetadata, - ); - pairsMetadata = await this.filterPairsByVolume( - pairFilter, - pairsMetadata, - ); - pairsMetadata = await this.filterPairsByLockedValueUSD( - pairFilter, - pairsMetadata, - ); - - return pairsMetadata - .map( - (pairMetadata) => - new PairModel({ - address: pairMetadata.address, - }), - ) - .slice(offset, offset + limit); - } - - private filterPairsByAddress( - pairFilter: PairFilterArgs, - pairsMetadata: PairMetadata[], - ): PairMetadata[] { - if (pairFilter.addresses) { - pairsMetadata = pairsMetadata.filter((pair) => - pairFilter.addresses.includes(pair.address), - ); - } - return pairsMetadata; - } - - private filterPairsByTokens( - pairFilter: PairFilterArgs, - pairsMetadata: PairMetadata[], - ): PairMetadata[] { - if (pairFilter.firstTokenID) { - if (pairFilter.secondTokenID) { - pairsMetadata = pairsMetadata.filter( - (pair) => - (pairFilter.firstTokenID === pair.firstTokenID && - pairFilter.secondTokenID === pair.secondTokenID) || - (pairFilter.firstTokenID === pair.secondTokenID && - pairFilter.secondTokenID === pair.firstTokenID), - ); - } else { - pairsMetadata = pairsMetadata.filter( - (pair) => pairFilter.firstTokenID === pair.firstTokenID, - ); - } - } else if (pairFilter.secondTokenID) { - pairsMetadata = pairsMetadata.filter( - (pair) => pairFilter.secondTokenID === pair.secondTokenID, - ); - } - return pairsMetadata; - } - - private async pairsByIssuedLpToken( - pairsMetadata: PairMetadata[], - ): Promise { - return await this.filterPairsByIssuedLpTokenRaw(pairsMetadata); - } - - private async filterPairsByIssuedLpTokenRaw( - pairsMetadata: PairMetadata[], - ): Promise { - const lpTokensIDs = await this.pairService.getAllLpTokensIds( - pairsMetadata.map((pair) => pair.address), - ); - - const filteredPairsMetadata = []; - for (let index = 0; index < lpTokensIDs.length; index++) { - if ( - lpTokensIDs[index] === undefined || - lpTokensIDs[index] === 'undefined' || - lpTokensIDs[index] === '' - ) { - continue; - } - filteredPairsMetadata.push(pairsMetadata[index]); - } - - return filteredPairsMetadata; - } - - private async filterPairsByState( - pairFilter: PairFilterArgs, - pairsMetadata: PairMetadata[], - ): Promise { - if (!pairFilter.state) { - return pairsMetadata; - } - - const pairsStates = await this.pairService.getAllStates( - pairsMetadata.map((pair) => pair.address), - ); + const pairsMetadata = await this.routerAbi.pairsMetadata(); - const filteredPairsMetadata = []; - for (let index = 0; index < pairsStates.length; index++) { - if (pairsStates[index] === pairFilter.state) { - filteredPairsMetadata.push(pairsMetadata[index]); - } - } - - return filteredPairsMetadata; - } - - private async filterPairsByFeeState( - pairFilter: PairFilterArgs, - pairsMetadata: PairMetadata[], - ): Promise { - if ( - typeof pairFilter.feeState === 'undefined' || - pairFilter.feeState === null - ) { - return pairsMetadata; - } - - const pairsFeeStates = await this.pairService.getAllFeeStates( - pairsMetadata.map((pair) => pair.address), - ); - - return pairsMetadata.filter( - (_, index) => pairsFeeStates[index] === pairFilter.feeState, - ); - } - - private async filterPairsByVolume( - pairFilter: PairFilterArgs, - pairsMetadata: PairMetadata[], - ): Promise { - if (!pairFilter.minVolume) { - return pairsMetadata; - } - - const pairsVolumes = await this.pairCompute.getAllVolumeUSD( - pairsMetadata.map((pair) => pair.address), + const builder = new PairsMetadataBuilder( + this.pairService, + this.pairCompute, ); - return pairsMetadata.filter((_, index) => { - const volume = new BigNumber(pairsVolumes[index]); - return volume.gte(pairFilter.minVolume); - }); - } - - private async filterPairsByLockedValueUSD( - pairFilter: PairFilterArgs, - pairsMetadata: PairMetadata[], - ): Promise { - if (!pairFilter.minLockedValueUSD) { - return pairsMetadata; - } + await builder.applyAllFilters(pairsMetadata, pairFilter); - const pairsLiquidityUSD = await this.pairService.getAllLockedValueUSD( - pairsMetadata.map((pair) => pair.address), - ); + const pairs = builder.build(); - return pairsMetadata.filter((_, index) => { - const lockedValueUSD = new BigNumber(pairsLiquidityUSD[index]); - return lockedValueUSD.gte(pairFilter.minLockedValueUSD); - }); + return pairs.slice(offset, offset + limit); } async requireOwner(sender: string) { @@ -270,10 +94,10 @@ export class RouterService { } private async sortPairs( - pairsMetadata: PairMetadata[], + pairsMetadata: PairModel[], sortField: string, sortOrder: string, - ): Promise { + ): Promise { let sortFieldData = []; if (!sortField) { From 42a9f7b6f1da879f701f9611a7ea1896e3438cc3 Mon Sep 17 00:00:00 2001 From: hschiau Date: Wed, 11 Dec 2024 17:56:22 +0200 Subject: [PATCH 2/2] MEX-527: fix unit tests after refactoring pair filtering --- src/modules/auto-router/specs/auto-router.service.spec.ts | 2 -- .../position-creator/specs/position.creator.transaction.spec.ts | 2 -- src/modules/router/specs/router.service.spec.ts | 2 -- src/modules/router/specs/router.transactions.service.spec.ts | 2 -- 4 files changed, 8 deletions(-) diff --git a/src/modules/auto-router/specs/auto-router.service.spec.ts b/src/modules/auto-router/specs/auto-router.service.spec.ts index db1c9463f..9b961d945 100644 --- a/src/modules/auto-router/specs/auto-router.service.spec.ts +++ b/src/modules/auto-router/specs/auto-router.service.spec.ts @@ -31,7 +31,6 @@ import winston from 'winston'; import { DynamicModuleUtils } from 'src/utils/dynamic.module.utils'; import { ComposableTasksTransactionService } from 'src/modules/composable-tasks/services/composable.tasks.transaction'; import { MXApiServiceProvider } from 'src/services/multiversx-communication/mx.api.service.mock'; -import { PairFilteringService } from 'src/modules/pair/services/pair.filtering.service'; import { gasConfig, scAddress } from 'src/config'; describe('AutoRouterService', () => { @@ -85,7 +84,6 @@ describe('AutoRouterService', () => { ComposableTasksTransactionService, ApiConfigService, MXApiServiceProvider, - PairFilteringService, ], exports: [], }).compile(); diff --git a/src/modules/position-creator/specs/position.creator.transaction.spec.ts b/src/modules/position-creator/specs/position.creator.transaction.spec.ts index 1d5fa17b7..d94044000 100644 --- a/src/modules/position-creator/specs/position.creator.transaction.spec.ts +++ b/src/modules/position-creator/specs/position.creator.transaction.spec.ts @@ -36,7 +36,6 @@ import { constantsConfig, gasConfig, scAddress } from 'src/config'; import { StakingAbiService } from 'src/modules/staking/services/staking.abi.service'; import { MXApiServiceProvider } from 'src/services/multiversx-communication/mx.api.service.mock'; import { SwapRouteModel } from 'src/modules/auto-router/models/auto-route.model'; -import { PairFilteringService } from 'src/modules/pair/services/pair.filtering.service'; import { FarmVersion } from 'src/modules/farm/models/farm.model'; describe('PositionCreatorTransaction', () => { @@ -61,7 +60,6 @@ describe('PositionCreatorTransaction', () => { PairService, PairComputeServiceProvider, PairTransactionService, - PairFilteringService, WrapService, WrapAbiServiceProvider, WrapTransactionsService, diff --git a/src/modules/router/specs/router.service.spec.ts b/src/modules/router/specs/router.service.spec.ts index a40ac1309..e1af6c635 100644 --- a/src/modules/router/specs/router.service.spec.ts +++ b/src/modules/router/specs/router.service.spec.ts @@ -11,7 +11,6 @@ import { ApiConfigService } from 'src/helpers/api.config.service'; 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 { WrapAbiServiceProvider } from 'src/modules/wrapping/mocks/wrap.abi.service.mock'; import { TokenServiceProvider } from 'src/modules/tokens/mocks/token.service.mock'; @@ -36,7 +35,6 @@ describe('RouterService', () => { PairComputeServiceProvider, RouterService, ApiConfigService, - PairFilteringService, PairServiceProvider, WrapAbiServiceProvider, TokenServiceProvider, diff --git a/src/modules/router/specs/router.transactions.service.spec.ts b/src/modules/router/specs/router.transactions.service.spec.ts index b2cac88d8..2790b9378 100644 --- a/src/modules/router/specs/router.transactions.service.spec.ts +++ b/src/modules/router/specs/router.transactions.service.spec.ts @@ -23,7 +23,6 @@ import { ConfigModule } from '@nestjs/config'; import winston from 'winston'; import { DynamicModuleUtils } from 'src/utils/dynamic.module.utils'; import { MXApiServiceProvider } from 'src/services/multiversx-communication/mx.api.service.mock'; -import { PairFilteringService } from 'src/modules/pair/services/pair.filtering.service'; describe('RouterService', () => { let module: TestingModule; @@ -60,7 +59,6 @@ describe('RouterService', () => { TokenServiceProvider, RouterService, MXApiServiceProvider, - PairFilteringService, ], }).compile(); });