From c5f8ebe0541fb7d4df4edb38a3e53c9c9306e36e Mon Sep 17 00:00:00 2001 From: gerardhalo Date: Sat, 28 Feb 2026 21:14:11 +0800 Subject: [PATCH 1/4] fix: Handle potential undefined values in wallet and one-click services - Updated the Total component to safely access stablecoin data using optional chaining. - Enhanced the OneClickService to correctly calculate exchange rates, defaulting to "1" when tokens are the same, and adjusted the response structure accordingly. - Modified the ResultOneClick component to display exchange rates conditionally based on token comparisons, improving user feedback on transactions. --- src/sections/wallet/total.tsx | 2 +- src/services/oneclick/index.ts | 7 ++++ .../bridge/components/result/oneclick.tsx | 32 +++++++++++++++---- 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/sections/wallet/total.tsx b/src/sections/wallet/total.tsx index dccefcd8..c6d96d19 100644 --- a/src/sections/wallet/total.tsx +++ b/src/sections/wallet/total.tsx @@ -29,7 +29,7 @@ export default function Total() { if (!key.includes("Balances")) return; const chainType = key.split("Balances")[0]; const currentChain = chainTypes[chainType]; - const currentTokenWithChains = stablecoinWithChains[chainType][walletStore.selectedToken]; + const currentTokenWithChains = stablecoinWithChains[chainType]?.[walletStore.selectedToken]; _balanceSummaries[chainType] = { balance: Big(0), balanceString: "0.00", diff --git a/src/services/oneclick/index.ts b/src/services/oneclick/index.ts index 8b8624d8..979ab9ac 100644 --- a/src/services/oneclick/index.ts +++ b/src/services/oneclick/index.ts @@ -59,6 +59,13 @@ class OneClickService { } catch (error) { } res.data.priceImpact = numberRemoveEndZero(Big(priceImpact).toFixed(4)); + const fromTokenSymbol = params.fromToken.symbol === "USD₮0" ? "USDT" : params.fromToken.symbol; + const toTokenSymbol = params.toToken.symbol === "USD₮0" ? "USDT" : params.toToken.symbol; + res.data.exchangeRate = "1"; + if (fromTokenSymbol !== toTokenSymbol) { + res.data.exchangeRate = numberRemoveEndZero(Big(res.data.quote?.amountOutFormatted || 0).div(res.data.quote?.amountInFormatted || 1).toFixed(params.toToken.decimals, 0)); + } + try { // const bridgeFee = BridgeFee.reduce((acc, item) => { // return acc.plus(Big(item.fee).div(100)); diff --git a/src/views/bridge/components/result/oneclick.tsx b/src/views/bridge/components/result/oneclick.tsx index 0159b202..7019c642 100644 --- a/src/views/bridge/components/result/oneclick.tsx +++ b/src/views/bridge/components/result/oneclick.tsx @@ -41,6 +41,7 @@ const ResultOneClick = (props: any) => { bridgeFee: totalBridgeFeeLabel, bridgeFeeValue: 0, netFee: 0, + exchangeRate: 1, slippage, }); return; @@ -51,6 +52,7 @@ const ResultOneClick = (props: any) => { bridgeFee: totalBridgeFeeLabel, bridgeFeeValue: totalBridgeFeeValue, netFee: _quoteData?.fees?.destinationGasFeeUsd, + exchangeRate: _quoteData?.exchangeRate, slippage, }); }, { wait: 500 }); @@ -71,6 +73,12 @@ const ResultOneClick = (props: any) => { return Big(energySourceGasFee).minus(_quoteData?.quoteParam?.needsEnergyAmount || 0).toFixed(0); }, [isFromTron, _quoteData]); + const isExchangeToken = useMemo(() => { + const fromTokenSymbol = _quoteData?.quoteParam.fromToken.symbol === "USD₮0" ? "USDT" : _quoteData?.quoteParam.fromToken.symbol; + const toTokenSymbol = _quoteData?.quoteParam.toToken.symbol === "USD₮0" ? "USDT" : _quoteData?.quoteParam.toToken.symbol; + return fromTokenSymbol !== toTokenSymbol; + }, [_quoteData]); + return ( { @@ -82,12 +90,24 @@ const ResultOneClick = (props: any) => { animate={{ height: "auto", opacity: 1 }} exit={{ height: 0, opacity: 0 }} > - - {fees?.netFee} - + { + isExchangeToken ? ( + + 1 {_quoteData?.quoteParam.fromToken.symbol} ~ {fees?.exchangeRate} {_quoteData?.quoteParam.toToken.symbol} + + ) : ( + + {fees?.netFee} + + ) + } From 47b0c584c2f12eb04c4d916ce61261f4f1362661 Mon Sep 17 00:00:00 2001 From: gerardhalo Date: Mon, 2 Mar 2026 12:03:04 +0800 Subject: [PATCH 2/4] fix: Format exchange rate in ResultOneClick component - Updated the exchange rate display in the ResultOneClick component to format the value with six decimal places, ensuring consistency and improved readability for users. --- src/views/bridge/components/result/oneclick.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/bridge/components/result/oneclick.tsx b/src/views/bridge/components/result/oneclick.tsx index 7019c642..e712d222 100644 --- a/src/views/bridge/components/result/oneclick.tsx +++ b/src/views/bridge/components/result/oneclick.tsx @@ -52,7 +52,7 @@ const ResultOneClick = (props: any) => { bridgeFee: totalBridgeFeeLabel, bridgeFeeValue: totalBridgeFeeValue, netFee: _quoteData?.fees?.destinationGasFeeUsd, - exchangeRate: _quoteData?.exchangeRate, + exchangeRate: formatNumber(_quoteData?.exchangeRate, 6, true, { round: Big.roundDown }), slippage, }); }, { wait: 500 }); From b563b5bff99de36eae4c470aafc82c3f59dc9682 Mon Sep 17 00:00:00 2001 From: jimmygu Date: Mon, 2 Mar 2026 15:26:17 +0800 Subject: [PATCH 3/4] fix: Improve token comparison logic in ResultOneClick component - Enhanced the isExchangeToken logic to safely access token symbols using optional chaining, ensuring robust handling of potential undefined values. - Updated the comparison to ensure both token symbols are defined before checking for inequality, improving the accuracy of exchange token detection. --- src/views/bridge/components/result/oneclick.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/bridge/components/result/oneclick.tsx b/src/views/bridge/components/result/oneclick.tsx index e712d222..547ee090 100644 --- a/src/views/bridge/components/result/oneclick.tsx +++ b/src/views/bridge/components/result/oneclick.tsx @@ -74,9 +74,9 @@ const ResultOneClick = (props: any) => { }, [isFromTron, _quoteData]); const isExchangeToken = useMemo(() => { - const fromTokenSymbol = _quoteData?.quoteParam.fromToken.symbol === "USD₮0" ? "USDT" : _quoteData?.quoteParam.fromToken.symbol; - const toTokenSymbol = _quoteData?.quoteParam.toToken.symbol === "USD₮0" ? "USDT" : _quoteData?.quoteParam.toToken.symbol; - return fromTokenSymbol !== toTokenSymbol; + const fromTokenSymbol = _quoteData?.quoteParam?.fromToken?.symbol === "USD₮0" ? "USDT" : _quoteData?.quoteParam?.fromToken?.symbol; + const toTokenSymbol = _quoteData?.quoteParam?.toToken?.symbol === "USD₮0" ? "USDT" : _quoteData?.quoteParam?.toToken?.symbol; + return fromTokenSymbol && toTokenSymbol && fromTokenSymbol !== toTokenSymbol; }, [_quoteData]); return ( From afc5233ac47fab13229dfdd1a1e3efcd97d792e3 Mon Sep 17 00:00:00 2001 From: jimmygu Date: Mon, 2 Mar 2026 20:19:38 +0800 Subject: [PATCH 4/4] refactor: Simplify EVM balances token handling and improve balance calculation logic - Consolidated the logic for processing EVM token chains in the evmBalancesTokens export, enhancing maintainability. - Introduced a new setBalances function in the useEvmBalances hook to streamline balance calculations for USDC and USDT, ensuring accurate decimal handling. - Updated the Total component to react to changes in the selected token, improving the user interface responsiveness. --- src/config/tokens/index.ts | 42 ++++++++++----------- src/hooks/use-evm-balances.ts | 71 ++++++++++++++++++++--------------- src/sections/wallet/total.tsx | 4 +- src/utils/format/number.ts | 6 ++- 4 files changed, 68 insertions(+), 55 deletions(-) diff --git a/src/config/tokens/index.ts b/src/config/tokens/index.ts index dab69eb0..39c263c2 100644 --- a/src/config/tokens/index.ts +++ b/src/config/tokens/index.ts @@ -1,28 +1,28 @@ import { usdcEvm, usdcNear, usdcSol, usdcChains, usdcAptos } from "@/config/tokens/usdc"; import { usdtAptos, usdtEvm, usdtNear, usdtSol, usdtTron, usdtChains } from "@/config/tokens/usdt"; -export const evmBalancesTokens = (() => { +const evmTokenChains = [ + usdcEvm.chains, + usdtEvm.chains, +]; +export const evmBalancesTokens: { chain_id: number; tokens: string[]; decimals: number[]; }[] = (() => { const map: any = {}; - usdcEvm.chains.forEach((chain: any) => { - if (map[chain.chainName]) { - map[chain.chainName].tokens.push(chain.contractAddress); - } else { - map[chain.chainName] = { - chain_id: chain.chainId, - tokens: [chain.contractAddress] - }; - } - }); - usdtEvm.chains.forEach((chain: any) => { - if (map[chain.chainName]) { - map[chain.chainName].tokens.push(chain.contractAddress); - } else { - map[chain.chainName] = { - chain_id: chain.chainId, - tokens: [chain.contractAddress] - }; - } - }); + for (const chains of evmTokenChains) { + chains.forEach((chain: any) => { + if (map[chain.chainName]) { + map[chain.chainName].tokens.push(chain.contractAddress); + map[chain.chainName].decimals.push(chain.decimals); + map[chain.chainName].symbols.push(chain.symbol); + } else { + map[chain.chainName] = { + chain_id: chain.chainId, + tokens: [chain.contractAddress], + decimals: [chain.decimals], + symbols: [chain.symbol], + }; + } + }); + } return Object.values(map); })(); diff --git a/src/hooks/use-evm-balances.ts b/src/hooks/use-evm-balances.ts index 9537d52d..c9e1e10d 100644 --- a/src/hooks/use-evm-balances.ts +++ b/src/hooks/use-evm-balances.ts @@ -35,6 +35,43 @@ export default function useEvmBalances(auto = false) { const _balances: any = {}; const _data = res.data.data; + const setBalances = (__data: any) => { + let usdcBalance = Big(0); + let usdtBalance = Big(0); + + Object.entries(__data).forEach(([key, item]: any) => { + if (!item) return; + const currentTokenChain = evmBalancesTokens.find((token) => Number(token.chain_id) === Number(key)); + item.forEach((sl: any) => { + const currentTokenIndex = currentTokenChain?.tokens?.map?.((address) => address.toLowerCase())?.indexOf?.(sl.address.toLowerCase()); + let currentTokenDecimals = 6; + if (currentTokenChain && typeof currentTokenIndex === "number" && currentTokenIndex > -1) { + currentTokenDecimals = currentTokenChain.decimals[currentTokenIndex]; + } + const _balance = Big(sl.balance).div(10 ** currentTokenDecimals); + if (usdcAddresses.includes(sl.address)) { + usdcBalance = usdcBalance.plus(_balance); + } + if (usdtAddresses.includes(sl.address)) { + usdtBalance = usdtBalance.plus(_balance); + } + _balances[sl.address] = _balance.toString(); + }); + }); + + if (wallet?.account) { + balancesStore.set({ + evmBalances: { + ..._balances, + usdcBalance: usdcBalance.toString(), + usdtBalance: usdtBalance.toString() + } + }); + } + }; + + setBalances(_data); + const unsupportedChainIds = evmBalancesTokens.map((token: any) => Object.keys(_data).includes(token.chain_id.toString()) ? null : token.chain_id).filter(Boolean); const unsupportedBalances: any = {}; // get unsupported tokens balances from provider @@ -69,8 +106,9 @@ export default function useEvmBalances(auto = false) { return _result; }); - const balances = await Promise.all(balancePromises); - unsupportedBalances[_token.chain_id] = balances; + const balances = await Promise.allSettled(balancePromises); + const validBalances = balances.filter((balance) => balance.status === "fulfilled").map((balance) => balance.value); + unsupportedBalances[_token.chain_id] = validBalances; } } @@ -80,34 +118,7 @@ export default function useEvmBalances(auto = false) { } } - let usdcBalance = Big(0); - let usdtBalance = Big(0); - - Object.entries(_data).forEach(([key, item]: any) => { - if (!item) return; - item.forEach((sl: any) => { - const _balance = Big(sl.balance).div( - 10 ** (Number(key) === 56 ? 18 : 6) - ); - if (usdcAddresses.includes(sl.address)) { - usdcBalance = usdcBalance.plus(_balance); - } - if (usdtAddresses.includes(sl.address)) { - usdtBalance = usdtBalance.plus(_balance); - } - _balances[sl.address] = _balance.toString(); - }); - }); - - if (wallet?.account) { - balancesStore.set({ - evmBalances: { - ..._balances, - usdcBalance: usdcBalance.toString(), - usdtBalance: usdtBalance.toString() - } - }); - } + setBalances(_data); setLoading(false); } catch (error) { diff --git a/src/sections/wallet/total.tsx b/src/sections/wallet/total.tsx index c6d96d19..91fcbe7d 100644 --- a/src/sections/wallet/total.tsx +++ b/src/sections/wallet/total.tsx @@ -104,7 +104,7 @@ export default function Total() { _balanceSummariesListWithBalance.length, finalPercentages.map(percent => percent + "%").join(" ") ]; - }, [balancesStore]); + }, [balancesStore, walletStore.selectedToken]); return (
@@ -113,7 +113,7 @@ export default function Total() {
Total {walletStore.selectedToken}
- {total && Big(total).gt(0) ? ( + {total && typeof total !== "undefined" ? ( { const { @@ -33,7 +34,8 @@ export const formatNumber = ( isZeroPrecision, isShort, isShortUppercase, - round = Big.roundHalfUp + round = Big.roundHalfUp, + isLessPrecision = true, } = options || {}; const isValid = () => { @@ -65,7 +67,7 @@ export const formatNumber = ( }; } - if (Big(value).lt(Big(10).pow(-precision))) { + if (isLessPrecision && Big(value).lt(Big(10).pow(-precision))) { if (isSimple) { return `< ${prefix}${Big(10).pow(-precision).toFixed(precision, round)}`; }