diff --git a/packages/api/src/token/token.controller.spec.ts b/packages/api/src/token/token.controller.spec.ts index 25a9e0979a..aca8783e78 100644 --- a/packages/api/src/token/token.controller.spec.ts +++ b/packages/api/src/token/token.controller.spec.ts @@ -50,9 +50,9 @@ describe("TokenController", () => { }); it("queries tokens with the specified options", async () => { - await controller.getTokens(pagingOptions); + await controller.getTokens(pagingOptions, 1000); expect(serviceMock.findAll).toHaveBeenCalledTimes(1); - expect(serviceMock.findAll).toHaveBeenCalledWith({ ...pagingOptions, route: "tokens" }); + expect(serviceMock.findAll).toHaveBeenCalledWith({ minLiquidity: 1000 }, { ...pagingOptions, route: "tokens" }); }); it("returns the tokens", async () => { diff --git a/packages/api/src/token/token.controller.ts b/packages/api/src/token/token.controller.ts index 501db99a84..4b45ebb218 100644 --- a/packages/api/src/token/token.controller.ts +++ b/packages/api/src/token/token.controller.ts @@ -6,6 +6,7 @@ import { ApiBadRequestResponse, ApiNotFoundResponse, ApiExcludeController, + ApiQuery, } from "@nestjs/swagger"; import { Pagination } from "nestjs-typeorm-paginate"; import { PagingOptionsDto, PagingOptionsWithMaxItemsLimitDto } from "../common/dtos"; @@ -14,6 +15,7 @@ import { TokenService } from "./token.service"; import { TransferService } from "../transfer/transfer.service"; import { TokenDto } from "./token.dto"; import { TransferDto } from "../transfer/transfer.dto"; +import { ParseLimitedIntPipe } from "../common/pipes/parseLimitedInt.pipe"; import { ParseAddressPipe, ADDRESS_REGEX_PATTERN } from "../common/pipes/parseAddress.pipe"; import { swagger } from "../config/featureFlags"; import { constants } from "../config/docs"; @@ -29,11 +31,26 @@ export class TokenController { @Get("") @ApiListPageOkResponse(TokenDto, { description: "Successfully returned token list" }) @ApiBadRequestResponse({ description: "Paging query params are not valid or out of range" }) - public async getTokens(@Query() pagingOptions: PagingOptionsDto): Promise> { - return await this.tokenService.findAll({ - ...pagingOptions, - route: entityName, - }); + @ApiQuery({ + name: "minLiquidity", + type: "integer", + description: "Min liquidity filter", + example: 1000000, + required: false, + }) + public async getTokens( + @Query() pagingOptions: PagingOptionsDto, + @Query("minLiquidity", new ParseLimitedIntPipe({ min: 0, isOptional: true })) minLiquidity?: number + ): Promise> { + return await this.tokenService.findAll( + { + minLiquidity, + }, + { + ...pagingOptions, + route: entityName, + } + ); } @Get(":address") diff --git a/packages/api/src/token/token.service.spec.ts b/packages/api/src/token/token.service.spec.ts index 1a57c06cf5..2b61764b4f 100644 --- a/packages/api/src/token/token.service.spec.ts +++ b/packages/api/src/token/token.service.spec.ts @@ -1,7 +1,7 @@ import { Test, TestingModule } from "@nestjs/testing"; import { mock } from "jest-mock-extended"; import { getRepositoryToken } from "@nestjs/typeorm"; -import { Repository, SelectQueryBuilder } from "typeorm"; +import { Repository, SelectQueryBuilder, MoreThanOrEqual } from "typeorm"; import { TokenService } from "./token.service"; import { Token, ETH_TOKEN } from "./token.entity"; import { Pagination, IPaginationMeta } from "nestjs-typeorm-paginate"; @@ -139,13 +139,26 @@ describe("TokenService", () => { }); it("creates query builder with proper params", async () => { - await service.findAll(pagingOptions); + await service.findAll({}, pagingOptions); expect(repositoryMock.createQueryBuilder).toHaveBeenCalledTimes(1); expect(repositoryMock.createQueryBuilder).toHaveBeenCalledWith("token"); }); + it("does not add liquidity filter when minLiquidity is not provided", async () => { + await service.findAll({}, pagingOptions); + expect(queryBuilderMock.where).not.toBeCalled(); + }); + + it("adds liquidity filter when minLiquidity is provided", async () => { + await service.findAll({ minLiquidity: 1000 }, pagingOptions); + expect(queryBuilderMock.where).toBeCalledTimes(1); + expect(queryBuilderMock.where).toHaveBeenCalledWith({ + liquidity: MoreThanOrEqual(1000), + }); + }); + it("returns tokens ordered by liquidity, blockNumber and logIndex DESC", async () => { - await service.findAll(pagingOptions); + await service.findAll({}, pagingOptions); expect(queryBuilderMock.orderBy).toBeCalledTimes(1); expect(queryBuilderMock.orderBy).toHaveBeenCalledWith("token.liquidity", "DESC", "NULLS LAST"); expect(queryBuilderMock.addOrderBy).toBeCalledTimes(2); @@ -156,7 +169,7 @@ describe("TokenService", () => { it("returns paginated result", async () => { const paginationResult = mock>(); (utils.paginate as jest.Mock).mockResolvedValue(paginationResult); - const result = await service.findAll(pagingOptions); + const result = await service.findAll({}, pagingOptions); expect(utils.paginate).toBeCalledTimes(1); expect(utils.paginate).toBeCalledWith(queryBuilderMock, pagingOptions); expect(result).toBe(paginationResult); diff --git a/packages/api/src/token/token.service.ts b/packages/api/src/token/token.service.ts index 8e4ff874a9..ef77a5f9ae 100644 --- a/packages/api/src/token/token.service.ts +++ b/packages/api/src/token/token.service.ts @@ -1,10 +1,14 @@ import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; -import { Repository, FindOptionsSelect } from "typeorm"; +import { Repository, FindOptionsSelect, MoreThanOrEqual } from "typeorm"; import { Pagination, IPaginationOptions } from "nestjs-typeorm-paginate"; import { paginate } from "../common/utils"; import { Token, ETH_TOKEN } from "./token.entity"; +export interface FilterTokensOptions { + minLiquidity?: number; +} + @Injectable() export class TokenService { constructor( @@ -34,8 +38,16 @@ export class TokenService { return tokenExists; } - public async findAll(paginationOptions: IPaginationOptions): Promise> { + public async findAll( + { minLiquidity }: FilterTokensOptions, + paginationOptions: IPaginationOptions + ): Promise> { const queryBuilder = this.tokenRepository.createQueryBuilder("token"); + if (minLiquidity > 0) { + queryBuilder.where({ + liquidity: MoreThanOrEqual(minLiquidity), + }); + } queryBuilder.orderBy("token.liquidity", "DESC", "NULLS LAST"); queryBuilder.addOrderBy("token.blockNumber", "DESC"); queryBuilder.addOrderBy("token.logIndex", "DESC");