diff --git a/src/modules/pair/mocks/pair.constants.ts b/src/modules/pair/mocks/pair.constants.ts index aebdaa04c..51d61f9b7 100644 --- a/src/modules/pair/mocks/pair.constants.ts +++ b/src/modules/pair/mocks/pair.constants.ts @@ -94,6 +94,35 @@ export const Tokens = (tokenID: string): EsdtToken => { price: '1', roles: new RolesModel(), }); + case 'USDT-123456': + return new EsdtToken({ + identifier: 'USDT-123456', + name: 'TetherUSD', + ticker: 'USDT', + owner: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000001', + ).bech32(), + supply: '1000000000000', + decimals: 6, + isPaused: false, + canUpgrade: true, + canMint: true, + canBurn: true, + canChangeOwner: true, + canPause: true, + canFreeze: true, + canWipe: true, + type: 'Core', + minted: '1', + burnt: '1', + circulatingSupply: '1', + accounts: 1, + transactions: 1, + assets: new AssetsModel(), + initialMinted: '1', + price: '1', + roles: new RolesModel(), + }); case 'TOK4-123456': return new EsdtToken({ identifier: 'TOK4-123456', @@ -120,6 +149,58 @@ export const Tokens = (tokenID: string): EsdtToken => { transactions: 1, assets: new AssetsModel(), }); + case 'TOK5-123456': + return new EsdtToken({ + identifier: 'TOK5-123456', + name: 'Token5', + owner: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000001', + ).bech32(), + ticker: 'TOK5', + supply: '1000000000000000000', + decimals: 18, + isPaused: false, + canUpgrade: true, + canMint: true, + canBurn: true, + canChangeOwner: true, + canPause: true, + canFreeze: true, + canWipe: true, + type: 'Experimental', + minted: '1', + burnt: '1', + circulatingSupply: '1', + accounts: 1, + transactions: 1, + assets: new AssetsModel(), + }); + case 'TOK6-123456': + return new EsdtToken({ + identifier: 'TOK6-123456', + name: 'Token6', + owner: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000001', + ).bech32(), + ticker: 'TOK6', + supply: '1000000000000000000', + decimals: 18, + isPaused: false, + canUpgrade: true, + canMint: true, + canBurn: true, + canChangeOwner: true, + canPause: true, + canFreeze: true, + canWipe: true, + type: 'Experimental', + minted: '1', + burnt: '1', + circulatingSupply: '1', + accounts: 1, + transactions: 1, + assets: new AssetsModel(), + }); case 'EGLDUSDCLP-abcdef': return new EsdtToken({ identifier: 'EGLDUSDCLP-abcdef', @@ -198,6 +279,141 @@ export const Tokens = (tokenID: string): EsdtToken => { price: '10', roles: new RolesModel(), }); + case 'EGLDTOK5LP-abcdef': + return new EsdtToken({ + identifier: 'EGLDTOK5LP-abcdef', + name: 'EGLDTOK5LP', + ticker: 'EGLDTOK5LP', + type: 'FungibleESDT', + owner: scAddress.routerAddress, + supply: '1000000000000000000000000', + decimals: 18, + isPaused: false, + canUpgrade: true, + canMint: true, + canBurn: true, + canChangeOwner: true, + canPause: true, + canFreeze: true, + canWipe: true, + minted: '900000000000000000000000', + burnt: '1', + circulatingSupply: '1', + accounts: 1, + transactions: 1, + assets: new AssetsModel(), + initialMinted: '1', + price: '10', + roles: new RolesModel(), + }); + case 'TOK5TOK6LP-abcdef': + return new EsdtToken({ + identifier: 'TOK5TOK6LP-abcdef', + name: 'TOK5TOK6LP', + ticker: 'TOK5TOK6LP', + type: 'FungibleESDT', + owner: scAddress.routerAddress, + supply: '1000000000000000000000000', + decimals: 18, + isPaused: false, + canUpgrade: true, + canMint: true, + canBurn: true, + canChangeOwner: true, + canPause: true, + canFreeze: true, + canWipe: true, + minted: '900000000000000000000000', + burnt: '1', + circulatingSupply: '1', + accounts: 1, + transactions: 1, + assets: new AssetsModel(), + initialMinted: '1', + price: '10', + roles: new RolesModel(), + }); + case 'TOK5USDCLP-abcdef': + return new EsdtToken({ + identifier: 'TOK5USDCLP-abcdef', + name: 'TOK5USDCLP', + ticker: 'TOK5USDCLP', + type: 'FungibleESDT', + owner: scAddress.routerAddress, + supply: '1000000000000000000000000', + decimals: 18, + isPaused: false, + canUpgrade: true, + canMint: true, + canBurn: true, + canChangeOwner: true, + canPause: true, + canFreeze: true, + canWipe: true, + minted: '900000000000000000000000', + burnt: '1', + circulatingSupply: '1', + accounts: 1, + transactions: 1, + assets: new AssetsModel(), + initialMinted: '1', + price: '10', + roles: new RolesModel(), + }); + case 'TOK5USDTLP-abcdef': + return new EsdtToken({ + identifier: 'TOK5USDTLP-abcdef', + name: 'TOK5USDTLP', + ticker: 'TOK5USDTLP', + type: 'FungibleESDT', + owner: scAddress.routerAddress, + supply: '1000000000000000000000000', + decimals: 18, + isPaused: false, + canUpgrade: true, + canMint: true, + canBurn: true, + canChangeOwner: true, + canPause: true, + canFreeze: true, + canWipe: true, + minted: '900000000000000000000000', + burnt: '1', + circulatingSupply: '1', + accounts: 1, + transactions: 1, + assets: new AssetsModel(), + initialMinted: '1', + price: '10', + roles: new RolesModel(), + }); + case 'EGLDUSDTLP-abcdef': + return new EsdtToken({ + identifier: 'EGLDUSDTLP-abcdef', + name: 'EGLDUSDTLP', + ticker: 'EGLDUSDTLP', + type: 'FungibleESDT', + owner: scAddress.routerAddress, + supply: '1000000000000000000000000', + decimals: 18, + isPaused: false, + canUpgrade: true, + canMint: true, + canBurn: true, + canChangeOwner: true, + canPause: true, + canFreeze: true, + canWipe: true, + minted: '900000000000000000000000', + burnt: '1', + circulatingSupply: '1', + accounts: 1, + transactions: 1, + assets: new AssetsModel(), + initialMinted: '1', + price: '10', + roles: new RolesModel(), + }); case 'EGLDMEXFL-abcdef': return { identifier: 'EGLDMEXFL-abcdef', @@ -393,6 +609,121 @@ export const pairs = [ totalFeePercent: 0.003, state: 'Active', }, + { + address: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000015', + ).bech32(), + firstToken: Tokens('WEGLD-123456'), + secondToken: Tokens('TOK5-123456'), + liquidityPoolToken: Tokens('EGLDTOK5LP-abcdef'), + info: { + reserves0: '1000000000000000000000', + reserves1: '100000000000000000000000', + totalSupply: '1000000000000000000000', + }, + firstTokenPrice: '100', + firstTokenPriceUSD: '10', + secondTokenPrice: '0.01', + secondTokenPriceUSD: '0.1', + liquidityPoolTokenPriceUSD: '20', + firstTokenLockedValueUSD: '10000', + secondTokenLockedValueUSD: '10000', + lockedValueUSD: '20000', + totalFeePercent: 0.003, + state: 'Active', + }, + { + address: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000016', + ).bech32(), + firstToken: Tokens('TOK6-123456'), + secondToken: Tokens('TOK5-123456'), + liquidityPoolToken: Tokens('TOK5TOK6LP-abcdef'), + info: { + reserves0: '1000000000000000000000', + reserves1: '1000000000000000000000', + totalSupply: '1000000000000000000000', + }, + firstTokenPrice: '1', + firstTokenPriceUSD: '0.1', + secondTokenPrice: '1', + secondTokenPriceUSD: '0.1', + liquidityPoolTokenPriceUSD: '0.2', + firstTokenLockedValueUSD: '100', + secondTokenLockedValueUSD: '100', + lockedValueUSD: '200', + totalFeePercent: 0.003, + state: 'Active', + }, + { + address: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000017', + ).bech32(), + firstToken: Tokens('TOK5-123456'), + secondToken: Tokens('USDC-123456'), + liquidityPoolToken: Tokens('TOK5USDCLP-abcdef'), + info: { + reserves0: '10000000000000000000', + reserves1: '1000000', + totalSupply: '1000000000000000000000', + }, + firstTokenPrice: '0.1', + firstTokenPriceUSD: '0.1', + secondTokenPrice: '10', + secondTokenPriceUSD: '1', + liquidityPoolTokenPriceUSD: '20', + firstTokenLockedValueUSD: '10000', + secondTokenLockedValueUSD: '10000', + lockedValueUSD: '20000', + totalFeePercent: 0.003, + state: 'Active', + }, + { + address: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000018', + ).bech32(), + firstToken: Tokens('TOK5-123456'), + secondToken: Tokens('USDT-123456'), + liquidityPoolToken: Tokens('TOK5USDTLP-abcdef'), + info: { + reserves0: '990000000000000000000000', + reserves1: '100000000000', + totalSupply: '1000000000000000000000', + }, + firstTokenPrice: '0.1010101010101010101010101', + firstTokenPriceUSD: '0.101', + secondTokenPrice: '9.9', + secondTokenPriceUSD: '1', + liquidityPoolTokenPriceUSD: '20', + firstTokenLockedValueUSD: '10000', + secondTokenLockedValueUSD: '10000', + lockedValueUSD: '20000', + totalFeePercent: 0.003, + state: 'Active', + }, + { + address: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000019', + ).bech32(), + firstToken: Tokens('WEGLD-123456'), + secondToken: Tokens('USDT-123456'), + liquidityPoolToken: Tokens('EGLDUSDTLP-abcdef'), + info: { + reserves0: '1000000000000000000000', + reserves1: '10000000000', + totalSupply: '10000000000', + }, + firstTokenPrice: '10', + firstTokenPriceUSD: '10', + secondTokenPrice: '0.1', + secondTokenPriceUSD: '1', + liquidityPoolTokenPriceUSD: '20', + firstTokenLockedValueUSD: '10000', + secondTokenLockedValueUSD: '10000', + lockedValueUSD: '20000', + totalFeePercent: 0.003, + state: 'Active', + }, ]; export async function PairsMap(): Promise> { diff --git a/src/modules/rabbitmq/handlers/pair.swap.handler.service.ts b/src/modules/rabbitmq/handlers/pair.swap.handler.service.ts index 529da88ac..aaf8b5526 100644 --- a/src/modules/rabbitmq/handlers/pair.swap.handler.service.ts +++ b/src/modules/rabbitmq/handlers/pair.swap.handler.service.ts @@ -256,7 +256,7 @@ export class SwapEventHandler { private async updateTokenPrices(tokenID: string): Promise { const [tokenPriceDerivedEGLD, tokenPriceDerivedUSD] = await Promise.all( [ - this.tokenCompute.computeTokenPriceDerivedEGLD(tokenID), + this.tokenCompute.computeTokenPriceDerivedEGLD(tokenID, []), this.tokenCompute.computeTokenPriceDerivedUSD(tokenID), ], ); diff --git a/src/modules/router/specs/router.service.spec.ts b/src/modules/router/specs/router.service.spec.ts index 33129312b..0d59bfa8d 100644 --- a/src/modules/router/specs/router.service.spec.ts +++ b/src/modules/router/specs/router.service.spec.ts @@ -61,6 +61,31 @@ describe('RouterService', () => { '0000000000000000000000000000000000000000000000000000000000000014', ).bech32(), }), + new PairModel({ + address: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000015', + ).bech32(), + }), + new PairModel({ + address: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000016', + ).bech32(), + }), + new PairModel({ + address: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000017', + ).bech32(), + }), + new PairModel({ + address: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000018', + ).bech32(), + }), + new PairModel({ + address: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000019', + ).bech32(), + }), ]); }); @@ -85,6 +110,16 @@ describe('RouterService', () => { '0000000000000000000000000000000000000000000000000000000000000013', ).bech32(), }), + new PairModel({ + address: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000015', + ).bech32(), + }), + new PairModel({ + address: Address.fromHex( + '0000000000000000000000000000000000000000000000000000000000000019', + ).bech32(), + }), ]); }); }); diff --git a/src/modules/tokens/interfaces.ts b/src/modules/tokens/interfaces.ts index fafd08d5f..b26cfede9 100644 --- a/src/modules/tokens/interfaces.ts +++ b/src/modules/tokens/interfaces.ts @@ -1,5 +1,8 @@ export interface ITokenComputeService { getEgldPriceInUSD(): Promise; - computeTokenPriceDerivedEGLD(tokenID: string): Promise; + computeTokenPriceDerivedEGLD( + tokenID: string, + pairsNotToVisit: [], + ): Promise; computeTokenPriceDerivedUSD(tokenID: string): Promise; } diff --git a/src/modules/tokens/services/token.compute.service.ts b/src/modules/tokens/services/token.compute.service.ts index 691f58835..6a5bca6ea 100644 --- a/src/modules/tokens/services/token.compute.service.ts +++ b/src/modules/tokens/services/token.compute.service.ts @@ -42,10 +42,13 @@ export class TokenComputeService implements ITokenComputeService { localTtl: CacheTtlInfo.Price.localTtl, }) async tokenPriceDerivedEGLD(tokenID: string): Promise { - return await this.computeTokenPriceDerivedEGLD(tokenID); + return await this.computeTokenPriceDerivedEGLD(tokenID, []); } - async computeTokenPriceDerivedEGLD(tokenID: string): Promise { + async computeTokenPriceDerivedEGLD( + tokenID: string, + pairsNotToVisit: PairMetadata[], + ): Promise { if (tokenID === tokenProviderUSD) { return new BigNumber('1').toFixed(); } @@ -72,6 +75,15 @@ export class TokenComputeService implements ITokenComputeService { } } + tokenPairs = tokenPairs.filter( + (pair) => + pairsNotToVisit.find( + (pairNotToVisit) => pairNotToVisit.address === pair.address, + ) === undefined, + ); + + pairsNotToVisit.push(...tokenPairs); + let largestLiquidityEGLD = new BigNumber(0); let priceSoFar = '0'; @@ -91,6 +103,7 @@ export class TokenComputeService implements ITokenComputeService { ] = await Promise.all([ this.computeTokenPriceDerivedEGLD( pair.secondTokenID, + pairsNotToVisit, ), this.pairAbi.secondTokenReserve(pair.address), this.pairCompute.firstTokenPrice(pair.address), @@ -118,6 +131,7 @@ export class TokenComputeService implements ITokenComputeService { ] = await Promise.all([ this.computeTokenPriceDerivedEGLD( pair.firstTokenID, + pairsNotToVisit, ), this.pairAbi.firstTokenReserve(pair.address), this.pairCompute.secondTokenPrice(pair.address), @@ -156,7 +170,7 @@ export class TokenComputeService implements ITokenComputeService { async computeTokenPriceDerivedUSD(tokenID: string): Promise { const [egldPriceUSD, derivedEGLD, usdcPrice] = await Promise.all([ this.getEgldPriceInUSD(), - this.computeTokenPriceDerivedEGLD(tokenID), + this.computeTokenPriceDerivedEGLD(tokenID, []), this.dataApi.getTokenPrice('USDC'), ]); diff --git a/src/modules/tokens/specs/token.compute.service.spec.ts b/src/modules/tokens/specs/token.compute.service.spec.ts index 27bec68ff..e01a07e61 100644 --- a/src/modules/tokens/specs/token.compute.service.spec.ts +++ b/src/modules/tokens/specs/token.compute.service.spec.ts @@ -53,6 +53,7 @@ describe('TokenComputeService', () => { module.get(TokenComputeService); const price = await service.computeTokenPriceDerivedEGLD( tokenProviderUSD, + [], ); expect(price).toEqual('1'); }); @@ -60,14 +61,40 @@ describe('TokenComputeService', () => { it('should compute token price derived EGLD for MEX-123456', async () => { const service: TokenComputeService = module.get(TokenComputeService); - const price = await service.computeTokenPriceDerivedEGLD('MEX-123456'); + const price = await service.computeTokenPriceDerivedEGLD( + 'MEX-123456', + [], + ); expect(price).toEqual('0.001'); }); it('should compute token price derived EGLD for TOK4-123456', async () => { const service: TokenComputeService = module.get(TokenComputeService); - const price = await service.computeTokenPriceDerivedEGLD('TOK4-123456'); + const price = await service.computeTokenPriceDerivedEGLD( + 'TOK4-123456', + [], + ); expect(price).toEqual('0.01'); }); + + it('should compute token price derived EGLD for TOK5-123456', async () => { + const service: TokenComputeService = + module.get(TokenComputeService); + const price = await service.computeTokenPriceDerivedEGLD( + 'TOK5-123456', + [], + ); + expect(price).toEqual('0.01010101010101010101010101'); + }); + + it('should compute token price derived EGLD for TOK6-123456', async () => { + const service: TokenComputeService = + module.get(TokenComputeService); + const price = await service.computeTokenPriceDerivedEGLD( + 'TOK6-123456', + [], + ); + expect(price).toEqual('0.01010101010101010101010101'); + }); });