Skip to content

Commit

Permalink
Merge pull request #1480 from multiversx/SERVICES-2600-add-pair-model…
Browse files Browse the repository at this point in the history
…-field-for-trades-count-in-the-past-24-hours

[SERVICES-2600] Add Pair field for trades count in the past 24 hours
  • Loading branch information
mad2sm0key authored Sep 19, 2024
2 parents 286e83b + f5950c8 commit 2c5beee
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 45 deletions.
5 changes: 4 additions & 1 deletion src/modules/pair/models/pair.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,12 @@ export class PairModel {
@Field()
hasDualFarms: boolean;

@Field()
@Field(() => Int)
tradesCount: number;

@Field(() => Int)
tradesCount24h: number;

@Field(() => Int, { nullable: true })
deployedAt: number;

Expand Down
5 changes: 2 additions & 3 deletions src/modules/pair/pair.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ import { CommonAppModule } from 'src/common.app.module';
import { ComposableTasksModule } from '../composable-tasks/composable.tasks.module';
import { RemoteConfigModule } from '../remote-config/remote-config.module';
import { StakingProxyModule } from '../staking-proxy/staking.proxy.module';
import { ElasticService } from 'src/helpers/elastic.service';
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';
import { PairComputeLoader } from './services/pair.compute.loader';
import { ElasticSearchModule } from 'src/services/elastic-search/elastic.search.module';
@Module({
imports: [
CommonAppModule,
Expand All @@ -43,6 +43,7 @@ import { PairComputeLoader } from './services/pair.compute.loader';
StakingProxyModule,
StakingModule,
EnergyModule,
ElasticSearchModule,
],
providers: [
PairService,
Expand All @@ -53,9 +54,7 @@ import { PairComputeLoader } from './services/pair.compute.loader';
PairFilteringService,
PairAbiLoader,
PairComputeLoader,
ElasticService,
PairResolver,
ElasticService,
PairFilteringService,
PairCompoundedAPRResolver,
PairRewardTokensResolver,
Expand Down
5 changes: 5 additions & 0 deletions src/modules/pair/pair.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,11 @@ export class PairResolver {
return this.pairComputeLoader.tradesCountLoader.load(parent.address);
}

@ResolveField()
async tradesCount24h(@Parent() parent: PairModel): Promise<number> {
return this.pairComputeLoader.tradesCount24hLoader.load(parent.address);
}

@ResolveField()
async deployedAt(@Parent() parent: PairModel): Promise<number> {
return this.pairComputeLoader.deployedAtLoader.load(parent.address);
Expand Down
6 changes: 6 additions & 0 deletions src/modules/pair/services/pair.compute.loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,12 @@ export class PairComputeLoader {
},
);

public readonly tradesCount24hLoader = new DataLoader<string, number>(
async (addresses: string[]) => {
return await this.pairCompute.getAllTradesCount24h(addresses);
},
);

public readonly deployedAtLoader = new DataLoader<string, number>(
async (addresses: string[]) => {
return await this.pairService.getAllDeployedAt(addresses);
Expand Down
59 changes: 41 additions & 18 deletions src/modules/pair/services/pair.compute.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ import { computeValueUSD, denominateAmount } from 'src/utils/token.converters';
import { farmsAddresses } from 'src/utils/farm.utils';
import { RemoteConfigGetterService } from 'src/modules/remote-config/remote-config.getter.service';
import { StakingProxyAbiService } from 'src/modules/staking-proxy/services/staking.proxy.abi.service';
import { ElasticService } from 'src/helpers/elastic.service';
import { ElasticQuery, QueryType } from '@multiversx/sdk-nestjs-elastic';
import { MXApiService } from 'src/services/multiversx-communication/mx.api.service';
import { FarmVersion } from 'src/modules/farm/models/farm.model';
import { FarmAbiServiceV2 } from 'src/modules/farm/v2/services/farm.v2.abi.service';
import { TransactionStatus } from 'src/utils/transaction.utils';
import { FarmComputeServiceV2 } from 'src/modules/farm/v2/services/farm.v2.compute.service';
import { StakingComputeService } from 'src/modules/staking/services/staking.compute.service';
import { CacheService } from '@multiversx/sdk-nestjs-cache';
import { getAllKeys } from 'src/utils/get.many.utils';
import { ESTransactionsService } from 'src/services/elastic-search/services/es.transactions.service';
import moment from 'moment';

@Injectable()
export class PairComputeService implements IPairComputeService {
Expand All @@ -42,10 +43,11 @@ export class PairComputeService implements IPairComputeService {
private readonly farmAbi: FarmAbiServiceV2,
private readonly remoteConfigGetterService: RemoteConfigGetterService,
private readonly stakingProxyAbiService: StakingProxyAbiService,
private readonly elasticService: ElasticService,
private readonly apiService: MXApiService,
private readonly farmCompute: FarmComputeServiceV2,
private readonly stakingCompute: StakingComputeService,
private readonly cachingService: CacheService,
private readonly elasticTransactionsService: ESTransactionsService,
) {}

async getTokenPrice(pairAddress: string, tokenID: string): Promise<string> {
Expand Down Expand Up @@ -688,20 +690,41 @@ export class PairComputeService implements IPairComputeService {
}

async computeTradesCount(pairAddress: string): Promise<number> {
const elasticQueryAdapter: ElasticQuery = new ElasticQuery();

elasticQueryAdapter.condition.must = [
QueryType.Match('receiver', pairAddress),
QueryType.Match('status', TransactionStatus.success),
QueryType.Should([
QueryType.Match('function', 'swapTokensFixedInput'),
QueryType.Match('function', 'swapTokensFixedOutput'),
]),
];

return await this.elasticService.getCount(
'transactions',
elasticQueryAdapter,
return await this.elasticTransactionsService.computePairSwapCount(
pairAddress,
);
}

@ErrorLoggerAsync({
logArgs: true,
})
@GetOrSetCache({
baseKey: 'pair',
remoteTtl: CacheTtlInfo.ContractState.remoteTtl,
localTtl: CacheTtlInfo.ContractState.localTtl,
})
async tradesCount24h(pairAddress: string): Promise<number> {
return await this.computeTradesCount24h(pairAddress);
}

async computeTradesCount24h(pairAddress: string): Promise<number> {
const end = moment.utc().unix();
const start = moment.unix(end).subtract(1, 'day').unix();

return await this.elasticTransactionsService.computePairSwapCount(
pairAddress,
start,
end,
);
}

async getAllTradesCount24h(pairAddresses: string[]): Promise<number[]> {
return await getAllKeys(
this.cachingService,
pairAddresses,
'pair.tradesCount24h',
this.tradesCount24h.bind(this),
CacheTtlInfo.ContractState,
);
}

Expand Down
18 changes: 18 additions & 0 deletions src/modules/pair/services/pair.filtering.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,24 @@ export class PairFilteringService {
);
}

async pairsByTradesCount24h(
pairFilter: PairsFilter,
pairsMetadata: PairMetadata[],
): Promise<PairMetadata[]> {
if (!pairFilter.minTradesCount24h) {
return pairsMetadata;
}

const pairsTradesCount24h = await this.pairCompute.getAllTradesCount24h(
pairsMetadata.map((pair) => pair.address),
);

return pairsMetadata.filter(
(_, index) =>
pairsTradesCount24h[index] >= pairFilter.minTradesCount24h,
);
}

async pairsByHasFarms(
pairFilter: PairsFilter,
pairsMetadata: PairMetadata[],
Expand Down
8 changes: 8 additions & 0 deletions src/modules/pair/services/pair.metadata.builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ export class PairsMetadataBuilder {
return this;
}

async filterByTradesCount24h(): Promise<PairsMetadataBuilder> {
this.pairsMetadata = await this.filteringService.pairsByTradesCount24h(
this.filters,
this.pairsMetadata,
);
return this;
}

async filterByHasFarms(): Promise<PairsMetadataBuilder> {
this.pairsMetadata = await this.filteringService.pairsByHasFarms(
this.filters,
Expand Down
12 changes: 12 additions & 0 deletions src/modules/pair/services/pair.setter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,18 @@ export class PairSetterService extends GenericSetterService {
);
}

async setTradesCount24h(
pairAddress: string,
value: number,
): Promise<string> {
return await this.setData(
this.getCacheKey('tradesCount24h', pairAddress),
value,
CacheTtlInfo.ContractState.remoteTtl,
CacheTtlInfo.ContractState.localTtl,
);
}

async setDeployedAt(pairAddress: string, value: number): Promise<string> {
return await this.setData(
this.getCacheKey('deployedAt', pairAddress),
Expand Down
3 changes: 3 additions & 0 deletions src/modules/router/models/filter.args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SortingOrder } from 'src/modules/common/page.data';

export enum PairSortableFields {
TRADES_COUNT = 'trades_count',
TRADES_COUNT_24 = 'trades_count_24h',
TVL = 'total_value_locked',
VOLUME_24 = 'volume_24h',
FEES_24 = 'fees_24h',
Expand Down Expand Up @@ -53,6 +54,8 @@ export class PairsFilter {
@Field({ nullable: true })
minTradesCount: number;
@Field({ nullable: true })
minTradesCount24h: number;
@Field({ nullable: true })
hasFarms: boolean;
@Field({ nullable: true })
hasDualFarms: boolean;
Expand Down
5 changes: 5 additions & 0 deletions src/modules/router/services/router.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,11 @@ export class RouterService {
pairsMetadata.map((pair) => pair.address),
);
break;
case PairSortableFields.TRADES_COUNT_24:
sortFieldData = await this.pairCompute.getAllTradesCount24h(
pairsMetadata.map((pair) => pair.address),
);
break;
case PairSortableFields.TVL:
sortFieldData = await this.pairService.getAllLockedValueUSD(
pairsMetadata.map((pair) => pair.address),
Expand Down
6 changes: 6 additions & 0 deletions src/services/crons/pair.cache.warmer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export class PairCacheWarmerService {
hasFarms,
hasDualFarms,
tradesCount,
tradesCount24h,
deployedAt,
whitelistedAddresses,
feeDestinations,
Expand All @@ -181,6 +182,7 @@ export class PairCacheWarmerService {
this.pairComputeService.computeHasFarms(pairAddress),
this.pairComputeService.computeHasDualFarms(pairAddress),
this.pairComputeService.computeTradesCount(pairAddress),
this.pairComputeService.computeTradesCount24h(pairAddress),
this.pairComputeService.computeDeployedAt(pairAddress),
this.pairAbi.getWhitelistedAddressesRaw(pairAddress),
this.pairAbi.getFeeDestinationsRaw(pairAddress),
Expand Down Expand Up @@ -224,6 +226,10 @@ export class PairCacheWarmerService {
hasDualFarms,
),
this.pairSetterService.setTradesCount(pairAddress, tradesCount),
this.pairSetterService.setTradesCount24h(
pairAddress,
tradesCount24h,
),
this.pairSetterService.setDeployedAt(pairAddress, deployedAt),
this.pairSetterService.setWhitelistedAddresses(
pairAddress,
Expand Down
50 changes: 27 additions & 23 deletions src/services/elastic-search/services/es.transactions.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { ElasticService, QueryType } from '@multiversx/sdk-nestjs-elastic';
import { ElasticQuery } from '@multiversx/sdk-nestjs-elastic';
import { TransactionStatus } from 'src/utils/transaction.utils';

@Injectable()
export class ESTransactionsService {
Expand All @@ -22,39 +23,42 @@ export class ESTransactionsService {
);
}

async computePairSwapCount(address: string): Promise<number> {
let swapTxCount = 0;
async computePairSwapCount(
address: string,
start?: number,
end?: number,
): Promise<number> {
const elasticQueryAdapter: ElasticQuery = new ElasticQuery();

elasticQueryAdapter.condition.must = [
QueryType.Match('receiver', address),
QueryType.Wildcard(
'data',
'*QDczNzc2MTcwNTQ2ZjZiNjU2ZTczNDY2OTc4NjU2NDQ5NmU3MDc1NzR*',
),
QueryType.Match('status', TransactionStatus.success),
QueryType.Should([
QueryType.Match('function', 'swapTokensFixedInput'),
QueryType.Match('function', 'swapTokensFixedOutput'),
]),
];

let txCount = await this.elasticService.getCount(
'transactions',
elasticQueryAdapter,
);
swapTxCount += txCount;

elasticQueryAdapter.condition.must = [
QueryType.Match('receiver', address),
QueryType.Wildcard(
'data',
'*QDczNzc2MTcwNTQ2ZjZiNjU2ZTczNDY2OTc4NjU2NDRmNzU3NDcwNzU3NE*',
),
];
if (start && end) {
elasticQueryAdapter.filter = [
QueryType.Range(
'timestamp',
{
key: 'gte',
value: start,
},
{
key: 'lte',
value: end,
},
),
];
}

txCount = await this.elasticService.getCount(
return await this.elasticService.getCount(
'transactions',
elasticQueryAdapter,
);
swapTxCount += txCount;

return swapTxCount;
}

async computePairAddLiquidityCount(address: string): Promise<number> {
Expand Down

0 comments on commit 2c5beee

Please sign in to comment.