Skip to content

Commit 10f304b

Browse files
adjust tokens endpoints (#1488)
* adjust tokens endpoints * adjust sorting * update sorting
1 parent eb0234a commit 10f304b

2 files changed

Lines changed: 126 additions & 2 deletions

File tree

src/endpoints/tokens/token.service.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ export class TokenService {
733733

734734
const tokens = await this.getAllTokens();
735735
for (const token of tokens) {
736-
if (token.price && token.marketCap && !token.isLowLiquidity) {
736+
if (token.price && token.marketCap && !token.isLowLiquidity && token.assets?.priceSource?.type !== TokenAssetsPriceSourceType.customUrl) {
737737
totalMarketCap += token.marketCap;
738738
}
739739
}
@@ -837,7 +837,8 @@ export class TokenService {
837837

838838
tokens = tokens.sortedDescending(
839839
token => token.assets ? 1 : 0,
840-
token => token.isLowLiquidity ? 0 : (token.marketCap ?? 0),
840+
token => token.marketCap ? 1 : 0,
841+
token => token.isLowLiquidity || token.assets?.priceSource?.type === TokenAssetsPriceSourceType.customUrl ? 0 : (token.marketCap ?? 0),
841842
token => token.transactions ?? 0,
842843
);
843844

src/test/unit/services/tokens.spec.ts

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { NftCollection } from "src/endpoints/collections/entities/nft.collection
3131
import { EsdtSupply } from "src/endpoints/esdt/entities/esdt.supply";
3232
import { TokenDetailed } from "src/endpoints/tokens/entities/token.detailed";
3333
import { NumberUtils } from "@multiversx/sdk-nestjs-common";
34+
import { TokenAssetsPriceSourceType } from "../../../common/assets/entities/token.assets.price.source.type";
3435

3536
describe('Token Service', () => {
3637
let tokenService: TokenService;
@@ -592,6 +593,25 @@ describe('Token Service', () => {
592593
expect(result).toBeGreaterThanOrEqual(261151384.6163954);
593594
expect(getAllTokensMock).toHaveBeenCalledTimes(1);
594595
});
596+
597+
it('should not include custom priced tokens in market cap', async () => {
598+
const mockTokens = JSON.parse(fs.readFileSync(path.join(__dirname, '../../mocks/tokens.mock.json'), 'utf-8'));
599+
const getAllTokensMock = jest.spyOn(tokenService, 'getAllTokens').mockResolvedValue(mockTokens);
600+
601+
const result = await tokenService.getTokenMarketCapRaw();
602+
expect(result).toBeGreaterThanOrEqual(261151384.6163954);
603+
expect(getAllTokensMock).toHaveBeenCalledTimes(1);
604+
605+
const secondToken = mockTokens[1];
606+
secondToken.assets.priceSource = {type: 'customUrl'};
607+
const newExpectedMarketCap = result - secondToken.marketCap;
608+
mockTokens[1] = secondToken;
609+
610+
jest.spyOn(tokenService, 'getAllTokens').mockResolvedValue(mockTokens);
611+
612+
const newResult = await tokenService.getTokenMarketCapRaw();
613+
expect(newResult).toBe(newExpectedMarketCap);
614+
});
595615
});
596616

597617
describe('getAllTokens', () => {
@@ -787,6 +807,109 @@ describe('Token Service', () => {
787807
});
788808
});
789809

810+
it('adjusts the order depending on the price source and market cap', async () => {
811+
jest.spyOn(tokenService['apiConfigService'], 'isTokensFetchFeatureEnabled').mockReturnValue(false);
812+
jest.spyOn(tokenService['esdtService'], 'getAllFungibleTokenProperties').mockResolvedValue([
813+
new TokenProperties({ identifier: 'token1' }),
814+
new TokenProperties({ identifier: 'token2' }), // <- will have custom price source
815+
new TokenProperties({ identifier: 'token3' }),
816+
new TokenProperties({ identifier: 'token4' }),
817+
new TokenProperties({ identifier: 'token5' }),
818+
]);
819+
820+
// Only token2 has a custom price source
821+
// eslint-disable-next-line require-await
822+
jest.spyOn(tokenService['assetsService'], 'getTokenAssets').mockImplementation(async (identifier: string) => {
823+
if (identifier === 'token2') {
824+
return new TokenAssets({
825+
name: `Token ${identifier}`,
826+
priceSource: {
827+
type: TokenAssetsPriceSourceType.customUrl,
828+
path: '0.usdPrice',
829+
url: 'url',
830+
},
831+
});
832+
}
833+
return new TokenAssets({
834+
name: `Token ${identifier}`,
835+
// No priceSource
836+
});
837+
});
838+
839+
jest.spyOn(tokenService['collectionService'], 'getNftCollections').mockResolvedValue([]);
840+
841+
jest.spyOn(tokenService['dataApiService'], 'getEgldPrice').mockResolvedValue(0);
842+
jest.spyOn(tokenService['dataApiService'], 'getEsdtTokenPrice').mockResolvedValue(1);
843+
jest.spyOn(tokenService['esdtService'], 'getTokenSupply').mockResolvedValue({
844+
minted: '1000000',
845+
initialMinted: '1000000',
846+
burned: '0',
847+
totalSupply: '1000000',
848+
circulatingSupply: '1000000',
849+
lockedAccounts: undefined,
850+
});
851+
852+
// Fake other dependencies
853+
jest.spyOn(tokenService as any, 'applyMexLiquidity').mockResolvedValue(undefined);
854+
jest.spyOn(tokenService as any, 'applyMexPrices').mockResolvedValue(undefined);
855+
jest.spyOn(tokenService as any, 'applyMexPairType').mockResolvedValue(undefined);
856+
jest.spyOn(tokenService as any, 'applyMexPairTradesCount').mockResolvedValue(undefined);
857+
jest.spyOn(tokenService['apiService'] as any, 'get').mockResolvedValue({data: [{usdPrice: 1.0}]});
858+
jest.spyOn(tokenService['cachingService'], 'batchApplyAll').mockImplementation(
859+
// eslint-disable-next-line require-await
860+
async (...args: unknown[]) => {
861+
const tokens = args[0] as TokenDetailed[];
862+
const apply = args[3] as (token: TokenDetailed, assets: TokenAssets, fromGetter: boolean) => void;
863+
864+
for (const token of tokens) {
865+
if (token.identifier === 'token2') {
866+
apply(token, new TokenAssets({
867+
name: `Token ${token.identifier}`,
868+
priceSource: {
869+
type: TokenAssetsPriceSourceType.customUrl,
870+
path: '0.usdPrice',
871+
url: 'url',
872+
},
873+
}), true);
874+
} else {
875+
apply(token, new TokenAssets({
876+
name: `Token ${token.identifier}`,
877+
// No priceSource
878+
}), true);
879+
}
880+
}
881+
}
882+
);
883+
884+
// eslint-disable-next-line require-await
885+
jest.spyOn(tokenService as any, 'batchProcessTokens').mockImplementation(async (tokens: any) => {
886+
const marketCaps = {
887+
token1: 500,
888+
token2: 400,
889+
token3: 300,
890+
token4: 200,
891+
token5: 100,
892+
};
893+
for (const [index, token] of tokens.entries()) {
894+
token.decimals = 18;
895+
token.isLowLiquidity = false;
896+
token.transactions = 10;
897+
if (index === 3) {
898+
continue; // make one of the tokens (token4) not to have any price or market cap at all
899+
}
900+
// @ts-ignore
901+
token.marketCap = marketCaps[token.identifier];
902+
token.price = 1;
903+
}
904+
});
905+
906+
const result = await tokenService.getAllTokensRaw();
907+
const sortedIdentifiers = result.map(t => t.identifier);
908+
909+
// token2 has custom price source, token4 does not have price/market cap at all
910+
expect(sortedIdentifiers.slice(0, 5)).toEqual(['token5', 'token3', 'token1', 'token2', 'token4']);
911+
});
912+
790913
it('should return values from cache', async () => {
791914
const cachedValueMock = jest.spyOn(tokenService['cachingService'], 'getOrSet').mockResolvedValue(mockTokens);
792915

0 commit comments

Comments
 (0)