Skip to content

Commit

Permalink
Exclude market cap from low liquidity tokens when sorting (#1218)
Browse files Browse the repository at this point in the history
* apply total liquidity field, calculate whether it's low, and use that info in sorting

* apply low liquidity criteria also for default sorting

* exclude low liquidity tokens from ecosystem market cap

* moved attributes to token list entity

* added attributes to token entity

* provide total volume 24h in the token info
  • Loading branch information
tanghel authored Mar 21, 2024
1 parent 4c3f712 commit c438977
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 8 deletions.
5 changes: 0 additions & 5 deletions src/endpoints/tokens/entities/token.detailed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Field, ObjectType } from "@nestjs/graphql";
import { ApiProperty } from "@nestjs/swagger";
import { Token } from "./token";
import { TokenRoles } from "./token.roles";
import { MexPairType } from "src/endpoints/mex/entities/mex.pair.type";

@ObjectType("TokenDetailed", { description: "TokenDetailed object type." })
export class TokenDetailed extends Token {
Expand Down Expand Up @@ -39,8 +38,4 @@ export class TokenDetailed extends Token {
@Field(() => Boolean, { description: 'If the given NFT collection can transfer the underlying tokens by default.', nullable: true })
@ApiProperty({ type: Boolean, nullable: true })
canTransfer: boolean | undefined = undefined;

@Field(() => MexPairType, { description: "Mex pair type details." })
@ApiProperty({ enum: MexPairType })
mexPairType: MexPairType = MexPairType.experimental;
}
17 changes: 17 additions & 0 deletions src/endpoints/tokens/entities/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Field, Float, ObjectType } from "@nestjs/graphql";
import { ApiProperty } from "@nestjs/swagger";
import { TokenType } from "src/common/indexer/entities";
import { TokenAssets } from "../../../common/assets/entities/token.assets";
import { MexPairType } from "src/endpoints/mex/entities/mex.pair.type";

@ObjectType("Token", { description: "Token object type." })
export class Token {
Expand Down Expand Up @@ -129,4 +130,20 @@ export class Token {
@Field(() => Number, { description: "Creation timestamp." })
@ApiProperty({ type: Number, description: 'Creation timestamp' })
timestamp: number | undefined = undefined;

@Field(() => MexPairType, { description: "Mex pair type details." })
@ApiProperty({ enum: MexPairType })
mexPairType: MexPairType = MexPairType.experimental;

@Field(() => Number, { description: "Total value captured in liquidity pools." })
@ApiProperty({ type: Number, nullable: true })
totalLiquidity: number | undefined = undefined;

@Field(() => Number, { description: "Total traded value in the last 24h within the liquidity pools." })
@ApiProperty({ type: Number, nullable: true })
totalVolume24h: number | undefined = undefined;

@Field(() => Boolean, { description: 'If the liquidity to market cap ratio is less than 1%, we consider it as low liquidity.', nullable: true })
@ApiProperty({ type: Boolean, nullable: true })
isLowLiquidity: boolean | undefined = undefined;
}
34 changes: 31 additions & 3 deletions src/endpoints/tokens/token.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { TrieOperationsTimeoutError } from "../esdt/exceptions/trie.operations.t
import { TokenSupplyOptions } from "./entities/token.supply.options";
import { TransferService } from "../transfers/transfer.service";
import { MexPairService } from "../mex/mex.pair.service";
import { MexPairState } from "../mex/entities/mex.pair.state";

@Injectable()
export class TokenService {
Expand Down Expand Up @@ -181,7 +182,7 @@ export class TokenService {
criteria = token => token.price ?? 0;
break;
case TokenSort.marketCap:
criteria = token => token.marketCap ?? 0;
criteria = token => token.isLowLiquidity ? 0 : (token.marketCap ?? 0);
break;
default:
throw new Error(`Unsupported sorting criteria '${sort}'`);
Expand Down Expand Up @@ -700,7 +701,7 @@ export class TokenService {

const tokens = await this.getAllTokens();
for (const token of tokens) {
if (token.price && token.marketCap) {
if (token.price && token.marketCap && !token.isLowLiquidity) {
totalMarketCap += token.marketCap;
}
}
Expand Down Expand Up @@ -752,6 +753,7 @@ export class TokenService {

await this.batchProcessTokens(tokens);

await this.applyMexLiquidity(tokens.filter(x => x.type !== TokenType.MetaESDT));
await this.applyMexPrices(tokens.filter(x => x.type !== TokenType.MetaESDT));
await this.applyMexPairType(tokens.filter(x => x.type !== TokenType.MetaESDT));

Expand All @@ -777,7 +779,11 @@ export class TokenService {
}
}

tokens = tokens.sortedDescending(token => token.assets ? 1 : 0, token => token.marketCap ?? 0, token => token.transactions ?? 0);
tokens = tokens.sortedDescending(
token => token.assets ? 1 : 0,
token => token.isLowLiquidity ? 0 : (token.marketCap ?? 0),
token => token.transactions ?? 0,
);

return tokens;
}
Expand Down Expand Up @@ -868,6 +874,24 @@ export class TokenService {
}
}

private async applyMexLiquidity(tokens: TokenDetailed[]): Promise<void> {
try {
const pairs = await this.mexPairService.getAllMexPairs();
const filteredPairs = pairs.filter(x => x.state === MexPairState.active);

for (const token of tokens) {
const pairs = filteredPairs.filter(x => x.baseId === token.identifier || x.quoteId === token.identifier);
if (pairs.length > 0) {
token.totalLiquidity = pairs.sum(x => x.totalValue / 2);
token.totalVolume24h = pairs.sum(x => x.volume24h ?? 0);
}
}
} catch (error) {
this.logger.error('Could not apply mex liquidity');
this.logger.error(error);
}
}

private async applyMexPrices(tokens: TokenDetailed[]): Promise<void> {
try {
const indexedTokens = await this.mexTokenService.getMexPricesRaw();
Expand All @@ -883,6 +907,10 @@ export class TokenService {
if (price.isToken) {
token.price = price.price;
token.marketCap = price.price * NumberUtils.denominateString(supply.circulatingSupply, token.decimals);

if (token.totalLiquidity && token.marketCap && token.totalLiquidity / token.marketCap < 0.01) {
token.isLowLiquidity = true;
}
}

token.supply = supply.totalSupply;
Expand Down
16 changes: 16 additions & 0 deletions src/graphql/schema/schema.gql
Original file line number Diff line number Diff line change
Expand Up @@ -3607,6 +3607,11 @@ type TokenDetailed {
"""Token initial minted amount details."""
initialMinted: String!

"""
If the liquidity to market cap ratio is less than 1%, we consider it as low liquidity.
"""
isLowLiquidity: Boolean

"""Token isPause property."""
isPaused: Boolean!

Expand Down Expand Up @@ -3643,6 +3648,9 @@ type TokenDetailed {
"""Creation timestamp."""
timestamp: Float!

"""Total value captured in liquidity pools."""
totalLiquidity: Float!

"""Tokens transactions."""
transactions: Float

Expand Down Expand Up @@ -3792,6 +3800,11 @@ type TokenWithBalanceAccountFlat {
"""Token initial minting details."""
initialMinted: String!

"""
If the liquidity to market cap ratio is less than 1%, we consider it as low liquidity.
"""
isLowLiquidity: Boolean

"""Token isPause property."""
isPaused: Boolean!

Expand Down Expand Up @@ -3822,6 +3835,9 @@ type TokenWithBalanceAccountFlat {
"""Creation timestamp."""
timestamp: Float!

"""Total value captured in liquidity pools."""
totalLiquidity: Float!

"""Tokens transactions."""
transactions: Float

Expand Down

0 comments on commit c438977

Please sign in to comment.