-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add tests for providers, managers & utils
- Loading branch information
Showing
15 changed files
with
1,367 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { SuiClient } from "@mysten/sui.js/client"; | ||
import { CacheOptions } from "../src/providers/types"; | ||
|
||
export const SUI_COIN_TYPE = "0x0000000000000000000000000000000000000000000000000000000000000002::sui::SUI"; | ||
export const USDC_COIN_TYPE = "0x5d4b302506645c37ff133b98c4b50a5ae14841659738d6d733d59d0d217a93bf::coin::COIN"; | ||
export const suiProviderUrl = "https://sui-rpc.publicnode.com"; | ||
export const cacheOptions: CacheOptions = { | ||
updateIntervalInMs: 60_000 * 30, // 30 min | ||
}; | ||
// Public key for tests, nothing special | ||
export const publicKey = "0x046f718ca3fdd519f6d21ad5b18a7fafaafeb85fd311ef8b99db22df7ec15d5d"; | ||
export const provider = new SuiClient({ url: suiProviderUrl }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import { cacheOptions, suiProviderUrl } from "../constants"; | ||
import { CoinManagerSingleton } from "../../src/managers/CoinManager"; | ||
import { Provider, Providers } from "../../src/managers/types"; | ||
import { AftermathSingleton } from "../../src/providers/aftermath/aftermath"; | ||
import { CetusSingleton } from "../../src/providers/cetus/cetus"; | ||
import { clmmMainnet } from "../../src/providers/cetus/config"; | ||
import { FlowxSingleton } from "../../src/providers/flowx/flowx"; | ||
import { TurbosSingleton } from "../../src/providers/turbos/turbos"; | ||
|
||
jest.setTimeout(60000); | ||
|
||
describe("CoinManager & Event Emitter & lazy loading", () => { | ||
it("should fill coin manager cache asynchronously", async () => { | ||
const turbos: TurbosSingleton = await TurbosSingleton.getInstance({ suiProviderUrl, cacheOptions }); | ||
const cetus: CetusSingleton = await CetusSingleton.getInstance({ | ||
sdkOptions: clmmMainnet, | ||
cacheOptions, | ||
suiProviderUrl, | ||
}); | ||
const aftermath: AftermathSingleton = await AftermathSingleton.getInstance({ cacheOptions }); | ||
const flowx: FlowxSingleton = await FlowxSingleton.getInstance({ cacheOptions }); | ||
const providers: Providers = [turbos, cetus, aftermath, flowx]; | ||
const coinManager: CoinManagerSingleton = CoinManagerSingleton.getInstance(providers); | ||
|
||
providers.forEach((provider: Provider) => { | ||
const events = provider.getEvents(); | ||
const buffer = provider.getBuffer(); | ||
|
||
expect(buffer.length).toStrictEqual(0); | ||
expect(Object.keys(events).length).toStrictEqual(1); | ||
}); | ||
|
||
const allCoinsCacheBefore = coinManager.getAllCoins(); | ||
const coinsByProviderNameCacheBefore = coinManager.getCoinsByProviderMap(); | ||
|
||
expect(allCoinsCacheBefore.size).toStrictEqual(0); | ||
expect(coinsByProviderNameCacheBefore.size).toStrictEqual(0); | ||
|
||
const maxWaitingAttemps = 10; | ||
let currentAttemp = 0; | ||
|
||
while (currentAttemp < maxWaitingAttemps) { | ||
const allProvidersAreInited: boolean = providers.every((provider) => provider.getCoins().data.length !== 0); | ||
|
||
if (!allProvidersAreInited) { | ||
await new Promise((r) => setTimeout(r, 5000)); | ||
currentAttemp++; | ||
} else { | ||
break; | ||
} | ||
} | ||
|
||
if (currentAttemp === 10) { | ||
throw new Error( | ||
"Not all providers were inited. Find out the reason " + | ||
"or try to increase maxWaitingAttemps or waiting time in setTimeout", | ||
); | ||
} | ||
|
||
providers.forEach((provider: Provider) => { | ||
const events = provider.getEvents(); | ||
const buffer = provider.getBuffer(); | ||
|
||
expect(buffer.length).toStrictEqual(1); | ||
expect(Object.keys(events).length).toStrictEqual(1); | ||
}); | ||
|
||
const allCoinsCacheAfter = coinManager.getAllCoins(); | ||
const coinsByProviderNameCacheAfter = coinManager.getCoinsByProviderMap(); | ||
|
||
expect(allCoinsCacheAfter.size).toBeGreaterThan(0); | ||
expect(coinsByProviderNameCacheAfter.size).toStrictEqual(providers.length); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { cacheOptions, suiProviderUrl } from "../constants"; | ||
import { CoinManagerSingleton } from "../../src/managers/CoinManager"; | ||
import { Provider, Providers } from "../../src/managers/types"; | ||
import { AftermathSingleton } from "../../src/providers/aftermath/aftermath"; | ||
import { CetusSingleton } from "../../src/providers/cetus/cetus"; | ||
import { clmmMainnet } from "../../src/providers/cetus/config"; | ||
import { FlowxSingleton } from "../../src/providers/flowx/flowx"; | ||
import { TurbosSingleton } from "../../src/providers/turbos/turbos"; | ||
|
||
jest.setTimeout(60000); | ||
|
||
describe("CoinManager & Event Emitter & no lazy loading", () => { | ||
it("should fill coin manager cache synchronously from buffer", async () => { | ||
const turbos: TurbosSingleton = await TurbosSingleton.getInstance({ | ||
suiProviderUrl, | ||
cacheOptions, | ||
lazyLoading: false, | ||
}); | ||
const cetus: CetusSingleton = await CetusSingleton.getInstance({ | ||
sdkOptions: clmmMainnet, | ||
cacheOptions, | ||
suiProviderUrl, | ||
lazyLoading: false, | ||
}); | ||
const aftermath: AftermathSingleton = await AftermathSingleton.getInstance({ cacheOptions, lazyLoading: false }); | ||
const flowx: FlowxSingleton = await FlowxSingleton.getInstance({ cacheOptions, lazyLoading: false }); | ||
const providers: Providers = [turbos, cetus, aftermath, flowx]; | ||
|
||
providers.forEach((provider: Provider) => { | ||
const events = provider.getEvents(); | ||
const buffer = provider.getBuffer(); | ||
|
||
expect(buffer.length).toBeGreaterThan(0); | ||
expect(Object.keys(events).length).toStrictEqual(0); | ||
}); | ||
|
||
const coinManager: CoinManagerSingleton = CoinManagerSingleton.getInstance(providers); | ||
|
||
const allCoinsCache = coinManager.getAllCoins(); | ||
const coinsByProviderNameCache = coinManager.getCoinsByProviderMap(); | ||
|
||
expect(allCoinsCache.size).toBeGreaterThan(0); | ||
expect(coinsByProviderNameCache.size).toStrictEqual(providers.length); | ||
|
||
providers.forEach((provider: Provider) => { | ||
const events = provider.getEvents(); | ||
const buffer = provider.getBuffer(); | ||
|
||
expect(buffer.length).toStrictEqual(0); | ||
expect(Object.keys(events).length).toStrictEqual(1); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { CommonCoinData } from "../../../src/managers/types"; | ||
import { LONG_SUI_COIN_TYPE, SHORT_SUI_COIN_TYPE } from "../../../src/providers/common"; | ||
import { CommonPoolData } from "../../../src/providers/types"; | ||
import { hasPath } from "../../../src/providers/utils/hasPath"; | ||
|
||
type MockedPoolProvider = { | ||
providerName: string; | ||
isSmartRoutingAvailable: boolean; | ||
getPaths: () => Map<string, CommonPoolData>; | ||
}; | ||
|
||
export const getFiltredProviders = ({ | ||
poolProviders, | ||
coinsByProviderMap, | ||
tokenFrom, | ||
tokenTo, | ||
}: { | ||
poolProviders: MockedPoolProvider[]; | ||
coinsByProviderMap: Map<string, Map<string, CommonCoinData>>; | ||
tokenFrom: string; | ||
tokenTo: string; | ||
}) => { | ||
const tokenFromIsSui: boolean = tokenFrom === SHORT_SUI_COIN_TYPE || tokenFrom === LONG_SUI_COIN_TYPE; | ||
const tokenToIsSui: boolean = tokenTo === SHORT_SUI_COIN_TYPE || tokenTo === LONG_SUI_COIN_TYPE; | ||
|
||
const filtredProviders = poolProviders.filter((poolProvider) => { | ||
const providerCoins = coinsByProviderMap.get(poolProvider.providerName); | ||
|
||
if (!providerCoins) { | ||
console.warn(`[getFiltredProviders] No coins found for such provider ${poolProvider.providerName}`); | ||
return false; | ||
} | ||
|
||
// Check that provider has one of the variants of SUI token | ||
const providerCoinsHaveSui = providerCoins.has(SHORT_SUI_COIN_TYPE) || providerCoins.has(LONG_SUI_COIN_TYPE); | ||
// Check if input tokenFrom/tokenTo is SUI | ||
const tokenFromOrTokenToIsSui = tokenFromIsSui || tokenToIsSui; | ||
// If SUI token is tokenTo, we return tokenFrom, and vice versa | ||
const notSuiTokenInInputTokens: string = tokenFromIsSui ? tokenTo : tokenFrom; | ||
|
||
if (tokenFromOrTokenToIsSui) { | ||
// Provider tokens doesn't have SUI and doesn't have the second token in pair (tokenFrom/tokenTo) | ||
const providerDoesntHaveAnyToken = !providerCoinsHaveSui || !providerCoins.has(notSuiTokenInInputTokens); | ||
|
||
if (providerDoesntHaveAnyToken) { | ||
return false; | ||
} | ||
} else { | ||
// If no SUI token present in tokenFrom/tokenTo, just check that provider has both tokens | ||
if (!providerCoins.has(tokenFrom) || !providerCoins.has(tokenTo)) { | ||
return false; | ||
} | ||
} | ||
|
||
// If provider doesn't support smart-routing, than we have to check that provider has direct path with both tokens | ||
if (!poolProvider.isSmartRoutingAvailable) { | ||
const paths: Map<string, CommonPoolData> = poolProvider.getPaths(); | ||
|
||
if (tokenFromOrTokenToIsSui) { | ||
const providerHasNoPathWithShortSui = !hasPath(SHORT_SUI_COIN_TYPE, notSuiTokenInInputTokens, paths); | ||
const providerHasNoPathWithLongSui = !hasPath(LONG_SUI_COIN_TYPE, notSuiTokenInInputTokens, paths); | ||
|
||
if (providerHasNoPathWithShortSui && providerHasNoPathWithLongSui) { | ||
return false; | ||
} | ||
} else { | ||
const providerHasNoPathWithRegularCoins = !hasPath(tokenFrom, tokenTo, paths); | ||
|
||
if (providerHasNoPathWithRegularCoins) { | ||
return false; | ||
} | ||
} | ||
} | ||
|
||
return true; | ||
}); | ||
|
||
return filtredProviders; | ||
}; |
Oops, something went wrong.