From efb5f6747d92fd7ab52806a077a87694bbb247bc Mon Sep 17 00:00:00 2001 From: naturexie <786281870@qq.com> Date: Thu, 16 Jan 2025 02:05:27 +0800 Subject: [PATCH] feat: add estimateLoading for open/close position --- api/get-pool.ts | 40 ++++++++++- components/Header/WalletButton.tsx | 4 +- hooks/useDclEstimateSwap.ts | 9 ++- hooks/useEstimateSwap.ts | 24 +++---- hooks/useGetPoolsData.ts | 15 ++-- hooks/useV1EstimateSwap.ts | 52 +++++++------- interfaces/contract-methods.ts | 1 + .../components/ClosePositionMobile.tsx | 15 +--- screens/Trading/components/TradingOperate.tsx | 69 ++++++++----------- 9 files changed, 123 insertions(+), 106 deletions(-) diff --git a/api/get-pool.ts b/api/get-pool.ts index 37aa7838..0a1d77d2 100644 --- a/api/get-pool.ts +++ b/api/get-pool.ts @@ -1,7 +1,9 @@ -import { ViewMethodsDcl, ChangeMethodsDcl } from "../interfaces/index"; +import { fetchAllPools, getStablePools } from "@ref-finance/ref-sdk"; +import { ViewMethodsDcl, ViewMethodsREFV1 } from "../interfaces/index"; import { getBurrow } from "../utils"; import { IPoolDcl, IQuoteResult, IPool } from "../interfaces/pool"; import getConfig from "../utils/config"; +import { expandToken } from "../store/helper"; export async function getDclPools() { const { view, dclContract } = await getBurrow(); @@ -53,3 +55,39 @@ export async function get_pool_list(poolType: "classic" | "stable" | "degen" | " }); return data?.data?.list || []; } +async function get_stable_pool_details(pool_ids: string[]) { + const { view, refv1Contract } = await getBurrow(); + const allStablePools: IPoolDcl[] = (await view( + refv1Contract, + ViewMethodsREFV1[ViewMethodsREFV1.get_pool_detail_info_by_ids], + { + pool_ids, + }, + )) as IPoolDcl[]; + const poolKindMap = { + RatedPoolInfo: "RATED_SWAP", + StablePoolInfo: "STABLE_SWAP", + DegenPoolInfo: "DEGEN_SWAP", + }; + const stablePools = allStablePools.map((poolDetail, index) => { + const [key, pool_info] = Object.entries(poolDetail)[0] as any[]; + return { + ...pool_info, + pool_kind: poolKindMap[key], + id: pool_ids[index], + rates: pool_info.rates || pool_info.c_amounts.map(() => expandToken(1, 18)), + }; + }); + return stablePools; +} +export async function get_pools_from_sdk() { + const { ratedPools, unRatedPools, simplePools } = await fetchAllPools(); + const stablePools = unRatedPools.concat(ratedPools); + const pool_ids = stablePools.map((p) => p.id); + const stablePoolsDetail = await get_stable_pool_details(pool_ids); + return { + simplePools, + stablePools, + stablePoolsDetail, + }; +} diff --git a/components/Header/WalletButton.tsx b/components/Header/WalletButton.tsx index d4fd8a1c..6ee276a7 100644 --- a/components/Header/WalletButton.tsx +++ b/components/Header/WalletButton.tsx @@ -379,10 +379,12 @@ export const ConnectWalletButton = ({ accountId, className, isShort, + loading, }: { accountId; className?: string; isShort?: boolean; + loading?: boolean; }) => { const [isDisclaimerOpen, setDisclaimer] = useState(false); const { getDisclaimer: hasAgreedDisclaimer } = useDisclaimer(); @@ -422,7 +424,7 @@ export const ConnectWalletButton = ({ onClick={onWalletButtonClick} disableRipple={!!accountId} > - Connect Wallet + {loading ? : <>Connect Wallet} setDisclaimer(false)} /> diff --git a/hooks/useDclEstimateSwap.ts b/hooks/useDclEstimateSwap.ts index d785ba15..15560b63 100644 --- a/hooks/useDclEstimateSwap.ts +++ b/hooks/useDclEstimateSwap.ts @@ -25,6 +25,7 @@ export const useDclEstimateSwap = ({ forceUpdate?: number; }) => { const [estimateData, setEstimateData] = useState(); + const [loading, setLoading] = useState(false); const combinedAssetsData = useAppSelector(getAllAssetsData); const allDclPools = useAppSelector(getDclPools); useEffect(() => { @@ -72,6 +73,7 @@ export const useDclEstimateSwap = ({ tag: `${pool_id}@${expandAmount}`, }), ); + setLoading(true); const estimatesResult = await Promise.allSettled(quotePending); const fulfilledEstimates = estimatesResult.filter((res) => res.status == "fulfilled"); const estimates = fulfilledEstimates.map((r) => r.value); @@ -89,6 +91,7 @@ export const useDclEstimateSwap = ({ tag: `${tokenIn_id}@${tokenOut_id}@${tokenIn_amount}`, from: "dcl", }); + setLoading(false); return; } const dexMap = get_registered_dexes(); @@ -120,6 +123,10 @@ export const useDclEstimateSwap = ({ tag: `${tokenIn_id}@${tokenOut_id}@${tokenIn_amount}`, from: "dcl", }); + setLoading(false); } - return estimateData; + return { + estimateData, + loading, + }; }; diff --git a/hooks/useEstimateSwap.ts b/hooks/useEstimateSwap.ts index 15b96b82..ab2bf1cc 100644 --- a/hooks/useEstimateSwap.ts +++ b/hooks/useEstimateSwap.ts @@ -1,6 +1,5 @@ import { useEffect, useState } from "react"; import Decimal from "decimal.js"; -import { init_env } from "@ref-finance/ref-sdk"; import { useV1EstimateSwap } from "./useV1EstimateSwap"; import { useDclEstimateSwap } from "./useDclEstimateSwap"; import { IEstimateResult } from "../interfaces"; @@ -11,9 +10,6 @@ export const useEstimateSwap = ({ tokenIn_amount, slippageTolerance, account_id, - simplePools, - stablePools, - stablePoolsDetail, forceUpdate, }: { tokenIn_id: string; @@ -21,33 +17,29 @@ export const useEstimateSwap = ({ tokenIn_amount: string; slippageTolerance: number; account_id?: string; - simplePools: any[]; - stablePools: any[]; - stablePoolsDetail: any[]; forceUpdate?: number; }) => { const [estimateResult, setEstimateResult] = useState(); - const dclEstimateResult: any = useDclEstimateSwap({ + const [estimateLoading, setEstimateLoading] = useState(false); + const { estimateData: dclEstimateResult, loading: dclLoading }: any = useDclEstimateSwap({ tokenIn_id, tokenOut_id, tokenIn_amount, slippageTolerance, forceUpdate, }); - const v1EstimateResult: any = useV1EstimateSwap({ + const { estimateData: v1EstimateResult, loading: v1Loading }: any = useV1EstimateSwap({ tokenIn_id, tokenOut_id, tokenIn_amount, slippageTolerance, account_id, - simplePools, - stablePools, - stablePoolsDetail, forceUpdate, }); useEffect(() => { if (dclEstimateResult?.tag && v1EstimateResult?.tag && validator()) { getBestEstimateResult(); + setEstimateLoading(false); } if (tokenIn_amount == "0" || !tokenIn_amount) { setEstimateResult((prev: any) => { @@ -64,6 +56,9 @@ export const useEstimateSwap = ({ v1EstimateResult?.amount_out, tokenIn_amount, ]); + useEffect(() => { + setEstimateLoading(v1Loading || dclLoading); + }, [v1Loading, dclLoading]); function getBestEstimateResult() { const { amount_out: dcl_amount_out } = dclEstimateResult!; const { amount_out: v1_amount_out } = v1EstimateResult!; @@ -93,5 +88,8 @@ export const useEstimateSwap = ({ } return false; } - return estimateResult; + return { + estimateResult, + estimateLoading, + }; }; diff --git a/hooks/useGetPoolsData.ts b/hooks/useGetPoolsData.ts index 8b680556..7c2b79c3 100644 --- a/hooks/useGetPoolsData.ts +++ b/hooks/useGetPoolsData.ts @@ -1,25 +1,20 @@ import { useState, useEffect } from "react"; -import { fetchAllPools, getStablePools, init_env } from "@ref-finance/ref-sdk"; +import { get_pools_from_sdk } from "../api/get-pool"; export function usePoolsData() { const [simplePools, setSimplePools] = useState([]); const [stablePools, setStablePools] = useState([]); const [stablePoolsDetail, setStablePoolsDetail] = useState([]); - useEffect(() => { getPoolsData(); }, []); async function getPoolsData() { try { - // - const { ratedPools, unRatedPools, simplePools: simplePoolsFromSdk } = await fetchAllPools(); - const stablePoolsFromSdk = unRatedPools.concat(ratedPools); - const stablePoolsDetailFromSdk = await getStablePools(stablePoolsFromSdk); - - setSimplePools(simplePoolsFromSdk); - setStablePools(stablePoolsFromSdk); - setStablePoolsDetail(stablePoolsDetailFromSdk); + const { simplePools, stablePools, stablePoolsDetail } = await get_pools_from_sdk(); + setSimplePools(simplePools); + setStablePools(stablePools); + setStablePoolsDetail(stablePoolsDetail); } catch (error) { console.error("Error fetching pools data:", error); } diff --git a/hooks/useV1EstimateSwap.ts b/hooks/useV1EstimateSwap.ts index a2736ae4..da974931 100644 --- a/hooks/useV1EstimateSwap.ts +++ b/hooks/useV1EstimateSwap.ts @@ -4,7 +4,6 @@ import { getExpectedOutputFromSwapTodos, instantSwap, Transaction, - init_env, getAvgFee, } from "@ref-finance/ref-sdk"; import { isEmpty } from "lodash"; @@ -23,17 +22,18 @@ import { get_amount_from_msg, get_registered_dexes, } from "../utils/margin"; +import { get_pools_from_sdk } from "../api/get-pool"; const SHUTDOWN_SERVER = false; +let simplePools; +let stablePools; +let stablePoolsDetail; export const useV1EstimateSwap = ({ tokenIn_id, tokenOut_id, tokenIn_amount, slippageTolerance, account_id, - simplePools, - stablePools, - stablePoolsDetail, forceUpdate, }: { tokenIn_id: string; @@ -41,15 +41,13 @@ export const useV1EstimateSwap = ({ tokenIn_amount: string; slippageTolerance: number; account_id?: string; - simplePools: any[]; - stablePools: any[]; - stablePoolsDetail: any[]; forceUpdate?: number; }) => { const combinedAssetsData = useAppSelector(getAllAssetsData); const marginConfig = useAppSelector(getMarginConfig); const allPools = useAppSelector(getAllPools); const [estimateData, setEstimateData] = useState(); + const [loading, setLoading] = useState(false); const [tokenIn_metadata, tokenOut_metadata] = useMemo(() => { if (tokenIn_id && tokenOut_id) { const [tokenIn_metadata, tokenOut_metadata] = getMetadatas([ @@ -61,27 +59,12 @@ export const useV1EstimateSwap = ({ return []; }, [tokenIn_id, tokenOut_id]); useEffect(() => { - if ( - !isEmpty(combinedAssetsData) && - !isEmpty(simplePools) && - !isEmpty(stablePools) && - !isEmpty(stablePoolsDetail) && - Number(tokenIn_amount) > 0 - ) { + if (!isEmpty(combinedAssetsData) && Number(tokenIn_amount) > 0) { getEstimateSwapData(); } - }, [ - combinedAssetsData, - tokenIn_id, - tokenOut_id, - tokenIn_amount, - slippageTolerance, - simplePools?.length, - stablePools?.length, - stablePoolsDetail?.length, - forceUpdate, - ]); + }, [combinedAssetsData, tokenIn_id, tokenOut_id, tokenIn_amount, slippageTolerance, forceUpdate]); async function getEstimateSwapData() { + setLoading(true); if (SHUTDOWN_SERVER) { getEstimateSwapFromScript(); } else { @@ -95,7 +78,11 @@ export const useV1EstimateSwap = ({ tokenIn: tokenIn_id, tokenOut: tokenOut_id, slippage: slippageTolerance, - }).catch(() => ({})); + }) + .catch(() => ({})) + .finally(() => { + setLoading(false); + }); if (!(resultFromServer?.result_code !== 0 || !resultFromServer?.result_data?.routes?.length)) { const result: IFindPathResult = resultFromServer.result_data; let min_output_amount = new Decimal(0); @@ -138,6 +125,12 @@ export const useV1EstimateSwap = ({ } } async function getEstimateSwapFromScript() { + if (!simplePools) { + const poolsMap = await get_pools_from_sdk(); + simplePools = poolsMap.simplePools; + stablePools = poolsMap.stablePools; + stablePoolsDetail = poolsMap.stablePoolsDetail; + } const [tokenIn_metadata, tokenOut_metadata] = getMetadatas([ combinedAssetsData[tokenIn_id], combinedAssetsData[tokenOut_id], @@ -173,6 +166,8 @@ export const useV1EstimateSwap = ({ slippageTolerance, AccountId: account_id || "test_account_id", referralId: "app.burrow.finance", + }).finally(() => { + setLoading(false); }); const swapTransaction = transactionsRef.pop() as any; const [dex_id, msg] = get_swap_indication_info(swapTransaction, marginConfig.registered_dexes); @@ -247,5 +242,8 @@ export const useV1EstimateSwap = ({ }); return avgFee; } - return estimateData; + return { + estimateData, + loading, + }; }; diff --git a/interfaces/contract-methods.ts b/interfaces/contract-methods.ts index d85244ae..9df4dcc6 100644 --- a/interfaces/contract-methods.ts +++ b/interfaces/contract-methods.ts @@ -81,6 +81,7 @@ export enum ViewMethodsREFV1 { get_shadow_records, get_pool_volumes_by_ids, list_pool_volumes, + get_pool_detail_info_by_ids, } export enum ChangeMethodsREFV1 { shadow_action, diff --git a/screens/Trading/components/ClosePositionMobile.tsx b/screens/Trading/components/ClosePositionMobile.tsx index 0ac9ecf7..fb29befa 100644 --- a/screens/Trading/components/ClosePositionMobile.tsx +++ b/screens/Trading/components/ClosePositionMobile.tsx @@ -11,13 +11,7 @@ import { toInternationalCurrencySystem_number, toDecimal } from "../../../utils/ import { closePosition } from "../../../store/marginActions/closePosition"; import { useEstimateSwap } from "../../../hooks/useEstimateSwap"; import { useAccountId } from "../../../hooks/hooks"; -import { usePoolsData } from "../../../hooks/useGetPoolsData"; -import { - expandToken, - shrinkToken, - shrinkTokenDecimal, - expandTokenDecimal, -} from "../../../store/helper"; +import { expandToken, shrinkToken, shrinkTokenDecimal } from "../../../store/helper"; import { YellowSolidSubmitButton as YellowSolidButton, RedSolidSubmitButton as RedSolidButton, @@ -73,8 +67,6 @@ const ClosePositionMobile: React.FC = ({ (state) => state.category, ); const accountId = useAccountId(); - const { simplePools, stablePools, stablePoolsDetail } = usePoolsData(); - const assetD = getAssetById(item.token_d_info.token_id, item); const assetC = getAssetById(item.token_c_info.token_id, item); const assetP = getAssetById(item.token_p_id, item); @@ -114,14 +106,11 @@ const ClosePositionMobile: React.FC = ({ }, [positionType.label]); // estimate - const estimateData = useEstimateSwap({ + const { estimateResult: estimateData } = useEstimateSwap({ tokenIn_id: item.token_p_id, tokenOut_id: item.token_d_info.token_id, tokenIn_amount: shrinkToken(tokenInAmount || "0", assetP.metadata.decimals), account_id: accountId, - simplePools, - stablePools, - stablePoolsDetail, slippageTolerance: ReduxSlippageTolerance / 100, forceUpdate, }); diff --git a/screens/Trading/components/TradingOperate.tsx b/screens/Trading/components/TradingOperate.tsx index 371426d7..d8ec813f 100644 --- a/screens/Trading/components/TradingOperate.tsx +++ b/screens/Trading/components/TradingOperate.tsx @@ -11,7 +11,6 @@ import ConfirmMobile from "./ConfirmMobile"; import { getAccountId } from "../../../redux/accountSelectors"; import { getAssets, getAssetsMEME } from "../../../redux/assetsSelectors"; import { useMarginConfigToken } from "../../../hooks/useMarginConfig"; -import { usePoolsData } from "../../../hooks/useGetPoolsData"; import { getMarginConfigCategory } from "../../../redux/marginConfigSelectors"; import { toDecimal } from "../../../utils/uiNumber"; import { useEstimateSwap } from "../../../hooks/useEstimateSwap"; @@ -55,7 +54,6 @@ const TradingOperate: React.FC = ({ onMobileClose, id }) => const [forceUpdateLoading, setForceUpdateLoading] = useState(false); const dispatch = useAppDispatch(); const [activeTab, setActiveTab] = useState(ReduxActiveTab || "long"); - const [estimateLoading, setEstimateLoading] = useState(false); const [selectedSetUpOption, setSelectedSetUpOption] = useState("custom"); const [isLongConfirmModalOpen, setIsLongConfirmModalOpen] = useState(false); const [isShortConfirmModalOpen, setIsShortConfirmModalOpen] = useState(false); @@ -95,19 +93,14 @@ const TradingOperate: React.FC = ({ onMobileClose, id }) => ? marginConfigTokens : marginConfigTokensMEME; const marginAccountList = isMainStream ? marginAccountListMain : marginAccountListMEME; - // fetch all pools for script estimate TODOXX - const { simplePools, stablePools, stablePoolsDetail } = usePoolsData(); // estimate - const estimateData = useEstimateSwap({ + const { estimateResult: estimateData, estimateLoading } = useEstimateSwap({ tokenIn_id: activeTab === "long" ? ReduxcategoryAssets2?.token_id : ReduxcategoryAssets1?.token_id, tokenOut_id: activeTab === "long" ? ReduxcategoryAssets1?.token_id : ReduxcategoryAssets2?.token_id, tokenIn_amount: toDecimal(tokenInAmount), account_id: accountId, - simplePools, - stablePools, - stablePoolsDetail, slippageTolerance: slippageTolerance / 100, forceUpdate, }); @@ -173,7 +166,6 @@ const TradingOperate: React.FC = ({ onMobileClose, id }) => .toFixed(); setLiqPrice(liqPriceX || "0"); } - setEstimateLoading(false); } }, 200, @@ -199,7 +191,6 @@ const TradingOperate: React.FC = ({ onMobileClose, id }) => .div(shortOutput); setLiqPrice(liqPriceX.toFixed()); } - setEstimateLoading(false); } setForceUpdateLoading(!estimateData?.loadingComplete); }, @@ -220,7 +211,7 @@ const TradingOperate: React.FC = ({ onMobileClose, id }) => return () => clearInterval(interval); }, [tokenInAmount, lastTokenInAmount]); - // for same input, estimateLoading or forceUpdateLoading is true + // for same input, forceUpdateLoading is true useEffect(() => { if (forceUpdateLoading) { const timer = setTimeout(() => { @@ -230,15 +221,6 @@ const TradingOperate: React.FC = ({ onMobileClose, id }) => return () => clearTimeout(timer); } }, [forceUpdateLoading]); - useEffect(() => { - if (estimateLoading) { - const timer = setTimeout(() => { - setEstimateLoading(false); - }, 4000); // 3 seconds - - return () => clearTimeout(timer); // Cleanup the timer on component unmount or when estimateLoading changes - } - }, [estimateLoading]); useEffect(() => { if (selectedSetUpOption === "custom" && customInputRef.current) { customInputRef.current.focus(); @@ -456,7 +438,6 @@ const TradingOperate: React.FC = ({ onMobileClose, id }) => setLiqPrice(""); return; } - setEstimateLoading(true); if (!isValidInput(value)) return; if (value.includes(".") && !lastValue.includes(".")) { inputPriceChange.cancel(); @@ -715,13 +696,7 @@ const TradingOperate: React.FC = ({ onMobileClose, id }) =>
Liq. Price
-
- {estimateLoading ? ( - - ) : ( - ${beautifyPrice(LiqPrice)} - )} -
+ ${beautifyPrice(LiqPrice)}
Fee
@@ -754,17 +729,26 @@ const TradingOperate: React.FC = ({ onMobileClose, id }) => {warnTip}
) : null} - {accountId ? ( - Long {cateSymbol} {rangeMount}x + {estimateLoading ? ( + + ) : ( + <> + Long {cateSymbol} {rangeMount}x + + )} ) : ( - + )} {isLongConfirmModalOpen && ( = ({ onMobileClose, id }) =>
Liq. Price
-
- {estimateLoading ? ( - - ) : ( - ${beautifyPrice(LiqPrice)} - )} -
+ ${beautifyPrice(LiqPrice)}
Fee
@@ -893,10 +871,21 @@ const TradingOperate: React.FC = ({ onMobileClose, id }) => disabled={isDisabled || !!warnTip} onClick={handleConfirmButtonClick} > - Short {cateSymbol} {rangeMount}x + {estimateLoading ? ( + + ) : ( + <> + Short {cateSymbol} {rangeMount}x + + )} ) : ( - + )} {isShortConfirmModalOpen && (