Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smart router call #566

Merged
merged 4 commits into from
Jul 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion src/components/swap/SwapRateChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ import { OrderlyLoading } from '../../pages/Orderly/components/Common/Icons';
import { numberWithCommas } from '../../pages/Orderly/utiles';
import { useClientMobile } from '../../utils/device';
import { SwapProContext } from '../../pages/SwapPage';
import { scientificNotationToString, toPrecision } from '../../utils/numbers';
import {
scientificNotationToString,
toPrecision,
toInternationalCurrencySystemLongString,
} from '../../utils/numbers';
import Big from 'big.js';
import { toRealSymbol } from '../../utils/token';
import SwapProTab from './SwapProTab';
Expand All @@ -44,6 +48,9 @@ export interface SwapRateChartProps {
type Dimensions = '24H' | '7D' | '1M' | '1Y' | 'All';

const priceFormatter = (price: string | number) => {
if (Number(price) >= 1000000) {
return toInternationalCurrencySystemLongString(price.toString());
}
return numberWithCommas(
Number(price) === 0
? 0
Expand Down
8 changes: 8 additions & 0 deletions src/services/ft-contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ export const ftGetTokenMetadata = async (
id: string,
accountPage?: boolean
): Promise<TokenMetadata> => {
if (!id)
return {
id,
name: id,
symbol: id?.split('.')[0].slice(0, 8),
decimals: 6,
icon: null,
};
try {
let metadata = await db.allTokens().where({ id }).first();
if (!metadata) {
Expand Down
121 changes: 102 additions & 19 deletions src/services/pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,10 @@ export const getPoolsByTokens = async ({
});
return { filteredPools, pool_protocol };
};
export const getAllPoolsByTokens = async (): Promise<{
// for server
export const getAllPoolsByTokens = async (
needCheckExpiration?: boolean
): Promise<{
filteredPools: Pool[];
}> => {
let pools;
Expand All @@ -473,18 +476,36 @@ export const getAllPoolsByTokens = async (): Promise<{
);
};
try {
const cachedPoolProtocol = sessionStorage.getItem(REF_FI_POOL_PROTOCOL);

const cachedPoolProtocol =
sessionStorage.getItem(REF_FI_POOL_PROTOCOL) || 'indexer';
if (cachedPoolProtocol === 'rpc') {
pools = await db.getAllPoolsTokens();

if (!pools || pools.length === 0) {
const validCache = await db.checkPoolsTokens();
if (
!pools ||
pools.length === 0 ||
(needCheckExpiration && !validCache)
) {
pools = await fetchPoolsRPC();
await cachePools(pools);
}
} else {
const poolsRaw = await db.queryTopPools();
if (poolsRaw && poolsRaw?.length > 0) {
const validCache = await db.checkTopPools();
if (!poolsRaw?.length || (needCheckExpiration && !validCache)) {
const poolsRaw = await fetchPoolsIndexer();

await db.cacheTopPools(poolsRaw);

pools = poolsRaw.map((p: any) => {
return {
...parsePool(p),
Dex: 'ref',
};
});

await cachePools(pools);
} else {
pools = poolsRaw.map((p) => {
const parsedP = parsePool({
...p,
Expand All @@ -498,19 +519,6 @@ export const getAllPoolsByTokens = async (): Promise<{
Dex: 'ref',
};
});
} else {
const poolsRaw = await fetchPoolsIndexer();

await db.cacheTopPools(poolsRaw);

pools = poolsRaw.map((p: any) => {
return {
...parsePool(p),
Dex: 'ref',
};
});

await cachePools(pools);
}
}
} catch (error) {
Expand Down Expand Up @@ -1574,3 +1582,78 @@ export const getAllStablePoolsFromCache = async (loadingTriger?: boolean) => {
allStablePoolsInfo,
};
};

// for server router
export const getStablePoolFromCacheForServer = async (id: string) => {
const stable_pool_id = id;

const pool_key = getStablePoolKey(stable_pool_id);

const info = getStablePoolInfoKey(stable_pool_id);

const stablePoolCache = JSON.parse(localStorage.getItem(pool_key));

const stablePoolInfoCache = JSON.parse(localStorage.getItem(info));

const isStablePoolCached = !!stablePoolCache;

const isStablePoolInfoCached = !!stablePoolInfoCache;

const stablePool = isStablePoolCached
? stablePoolCache
: await getPool(Number(stable_pool_id));

const stablePoolInfo = isStablePoolInfoCached
? stablePoolInfoCache
: await getStablePool(Number(stable_pool_id));

if (!isStablePoolCached) {
localStorage.setItem(
pool_key,
JSON.stringify({ ...stablePool, update_time: moment().unix() })
);
}

if (!isStablePoolInfoCached) {
localStorage.setItem(
info,
JSON.stringify({ ...stablePoolInfo, update_time: moment().unix() })
);
}
stablePool.rates = stablePoolInfo.token_account_ids.reduce(
(acc: any, cur: any, i: number) => ({
...acc,
[cur]: toReadableNumber(
getStablePoolDecimal(stablePool.id),
stablePoolInfo.rates[i]
),
}),
{}
);

return [stablePool, stablePoolInfo];
};
export const getAllStablePoolsFromCacheForServer = async () => {
const res = await Promise.all(
ALL_STABLE_POOL_IDS.filter((id) => {
return !BLACKLIST_POOL_IDS.includes(id.toString());
}).map((id) => getStablePoolFromCacheForServer(id.toString()))
);

const allStablePoolsById = res.reduce((pre, cur, i) => {
return {
...pre,
[cur[0].id]: cur,
};
}, {}) as {
[id: string]: [Pool, StablePool];
};
const allStablePools = Object.values(allStablePoolsById).map((p) => p[0]);
const allStablePoolsInfo = Object.values(allStablePoolsById).map((p) => p[1]);

return {
allStablePoolsById,
allStablePools,
allStablePoolsInfo,
};
};
41 changes: 35 additions & 6 deletions src/services/smartRouterFromServer.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import Big from 'big.js';
import db from '../store/RefDatabase';
import {
toNonDivisibleNumber,
scientificNotationToString,
calculateMarketPrice,
} from '../utils/numbers';
import { TokenMetadata, ftGetTokenMetadata } from './ft-contract';
import { getAllPoolsByTokens, getAllStablePoolsFromCache, Pool } from './pool';
import {
getAllPoolsByTokens,
getAllStablePoolsFromCacheForServer,
Pool,
} from './pool';
import { isStablePool } from '../services/near';
import { getTokenPriceList } from '../services/indexer';
export interface IEstimateSwapServerView {
amount_in: string;
amount_out: string;
Expand Down Expand Up @@ -92,8 +98,13 @@ export async function getAvgFeeFromServer({
});
setAvgFee(avgFee);
}
export async function getUsedPools(routes: IServerRoute[]) {
const { topPools, stablePools } = await getAllPoolsFromCache();
export async function getUsedPools(
routes: IServerRoute[],
needCheckExpiration?: boolean
) {
const { topPools, stablePools } = await getAllPoolsFromCache(
needCheckExpiration
);
const pools: Record<string, Pool> = {};
routes.forEach((route) => {
route.pools.forEach((cur) => {
Expand Down Expand Up @@ -132,9 +143,11 @@ export async function getTokensOfRoute(route: IServerRoute) {
const tokens = await Promise.all(pending);
return tokens as TokenMetadata[];
}
export async function getAllPoolsFromCache() {
const { filteredPools: topPools } = await getAllPoolsByTokens();
const { allStablePools } = await getAllStablePoolsFromCache();
export async function getAllPoolsFromCache(needCheckExpiration?: boolean) {
const { filteredPools: topPools } = await getAllPoolsByTokens(
needCheckExpiration
);
const { allStablePools } = await getAllStablePoolsFromCacheForServer();
const topPoolsMap = topPools.reduce((acc, p) => {
acc[p.id] = p;
return acc;
Expand Down Expand Up @@ -224,3 +237,19 @@ export async function getPriceImpactFromServer({
setPriceImpactValue('0');
}
}
export const getTokenPriceListFromCacheForServer = async () => {
let prices;
prices = await db.queryTokenPrices();
const validCache = await db.checkTokenPrices();
if (!prices?.length || !validCache) {
prices = await getTokenPriceList();
db.cacheTokenPrices(prices);
}
const map = prices?.reduce((acc, cur) => {
return {
...acc,
[cur.id]: cur,
};
}, {});
return map || {};
};
6 changes: 5 additions & 1 deletion src/services/swap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import {
getUsedTokens,
} from './smartRouterFromServer';
import { REF_DCL_POOL_CACHE_KEY } from '../state/swap';
import { getTokenPriceListFromCacheForServer } from '../services/smartRouterFromServer';

export const REF_FI_SWAP_SIGNAL = 'REF_FI_SWAP_SIGNAL_KEY';
const { NO_REQUIRED_REGISTRATION_TOKEN_IDS } = getConfigV2();
Expand Down Expand Up @@ -368,7 +369,10 @@ export const estimateSwap = async ({
}
} catch (error) {}
try {
poolsMap = await getUsedPools(routes);
const prices = await getTokenPriceListFromCacheForServer();
const isLosePrice =
!prices?.[tokenIn.id]?.price || !prices?.[tokenOut.id]?.price;
poolsMap = await getUsedPools(routes, isLosePrice);
} catch (error) {}
try {
tokensMap = await getUsedTokens(routes);
Expand Down
5 changes: 4 additions & 1 deletion src/state/swap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import {
IEstimateSwapServerView,
getAvgFeeFromServer,
getPriceImpactFromServer,
getAllPoolsFromCache,
} from '../services/smartRouterFromServer';
const ONLY_ZEROS = /^0*\.?0*$/;

Expand Down Expand Up @@ -607,7 +608,9 @@ export const useSwap = ({
setTag(`${tokenIn?.id}|${tokenOut?.id}|${tokenInAmount}`);
});
};

useEffect(() => {
getAllPoolsFromCache(true);
}, []);
useEffect(() => {
if (
tokenIn?.id &&
Expand Down
12 changes: 12 additions & 0 deletions src/store/RefDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,18 @@ class RefDatabase extends Dexie {
)
);
}
public async checkPoolsTokens() {
const items = await this.poolsTokens.limit(10).toArray();
return (
items.length > 0 &&
items.every(
(item) =>
Number(item.update_time) >=
Number(moment().unix()) -
Number(getConfig().TOP_POOLS_TOKEN_REFRESH_INTERVAL)
)
);
}

public async queryTopPools() {
const pools = await this.topPools.toArray();
Expand Down