|
1 | 1 | import { useState, useCallback, useEffect, useMemo } from 'react'; |
2 | 2 | import { useTranslation } from 'react-i18next'; |
3 | | -import type { BioAccount, BioSignedTransaction, BioUnsignedTransaction } from '@biochain/bio-sdk'; |
| 3 | +import { normalizeChainId, type BioAccount, type BioSignedTransaction, type BioUnsignedTransaction } from '@biochain/bio-sdk'; |
4 | 4 | import { Button } from '@/components/ui/button'; |
5 | 5 | import { Card, CardContent, CardTitle, CardDescription } from '@/components/ui/card'; |
6 | 6 | import { Input } from '@/components/ui/input'; |
@@ -212,6 +212,18 @@ const CHAIN_COLORS: Record<string, string> = { |
212 | 212 | const normalizeInternalChainName = (value: string): InternalChainName => |
213 | 213 | value.toUpperCase() as InternalChainName; |
214 | 214 |
|
| 215 | +const normalizeTeleportChain = (value: string | null | undefined): string => { |
| 216 | + const normalized = value?.trim(); |
| 217 | + if (!normalized) return ''; |
| 218 | + return normalizeChainId(normalized); |
| 219 | +}; |
| 220 | + |
| 221 | +const isSameTeleportChain = (left: string | null | undefined, right: string | null | undefined): boolean => { |
| 222 | + const normalizedLeft = normalizeTeleportChain(left); |
| 223 | + const normalizedRight = normalizeTeleportChain(right); |
| 224 | + return normalizedLeft.length > 0 && normalizedLeft === normalizedRight; |
| 225 | +}; |
| 226 | + |
215 | 227 | const normalizeInputAmount = (value: string, decimals: number): string => { |
216 | 228 | const normalized = value.trim(); |
217 | 229 | if (!/^\d+(\.\d+)?$/.test(normalized)) { |
@@ -312,7 +324,7 @@ export default function App() { |
312 | 324 | if (!assets || !sourceAccount) return []; |
313 | 325 | const sourceChain = selectedSourceChain ?? sourceAccount.chain; |
314 | 326 | return assets |
315 | | - .filter((asset) => asset.chain.toLowerCase() === sourceChain.toLowerCase()) |
| 327 | + .filter((asset) => isSameTeleportChain(asset.chain, sourceChain)) |
316 | 328 | .map((asset) => ({ |
317 | 329 | ...asset, |
318 | 330 | balance: formatRawBalance( |
@@ -365,16 +377,25 @@ export default function App() { |
365 | 377 | }); |
366 | 378 | setSourceAccount(account); |
367 | 379 | const accountChain = account.chain || portalChain; |
368 | | - const chainAssets = (assets ?? []).filter((asset) => asset.chain.toLowerCase() === accountChain.toLowerCase()); |
| 380 | + const sourceAssetChain = portalChain; |
| 381 | + const chainAssetsByPortal = (assets ?? []).filter( |
| 382 | + (asset) => isSameTeleportChain(asset.chain, sourceAssetChain), |
| 383 | + ); |
| 384 | + const chainAssets = |
| 385 | + chainAssetsByPortal.length > 0 |
| 386 | + ? chainAssetsByPortal |
| 387 | + : (assets ?? []).filter((asset) => isSameTeleportChain(asset.chain, accountChain)); |
369 | 388 | const uniqueAssetTypes = [...new Set(chainAssets.map((asset) => asset.assetType.toUpperCase()))]; |
| 389 | + const balanceQueryChain = |
| 390 | + normalizeTeleportChain(account.chain) || normalizeTeleportChain(portalChain); |
370 | 391 |
|
371 | 392 | if (uniqueAssetTypes.length > 0) { |
372 | 393 | const balanceEntries = await Promise.all( |
373 | 394 | uniqueAssetTypes.map(async (assetType) => { |
374 | 395 | try { |
375 | 396 | const rawBalance = await bio.request<string>({ |
376 | 397 | method: 'bio_getBalance', |
377 | | - params: [{ address: account.address, chain: account.chain, asset: assetType }], |
| 398 | + params: [{ address: account.address, chain: balanceQueryChain, asset: assetType }], |
378 | 399 | }); |
379 | 400 | return [assetType, rawBalance] as const; |
380 | 401 | } catch { |
@@ -413,7 +434,7 @@ export default function App() { |
413 | 434 | if (!window.bio || !sourceAccount || !selectedAsset) return; |
414 | 435 | setLoading(true); |
415 | 436 | setError(null); |
416 | | - const shouldExcludeSameAddress = sourceAccount.chain.toLowerCase() === selectedAsset.targetChain.toLowerCase(); |
| 437 | + const shouldExcludeSameAddress = isSameTeleportChain(sourceAccount.chain, selectedAsset.targetChain); |
417 | 438 | try { |
418 | 439 | const account = await window.bio.request<BioAccount>({ |
419 | 440 | method: 'bio_pickWallet', |
@@ -446,12 +467,12 @@ export default function App() { |
446 | 467 | assetType: selectedAsset.targetAsset, |
447 | 468 | }; |
448 | 469 |
|
449 | | - const chainLower = sourceAccount.chain.toLowerCase(); |
| 470 | + const sourceChain = normalizeTeleportChain(sourceAccount.chain); |
450 | 471 | const isInternalChain = |
451 | | - chainLower !== 'eth' && |
452 | | - chainLower !== 'bsc' && |
453 | | - chainLower !== 'tron' && |
454 | | - chainLower !== 'trc20'; |
| 472 | + sourceChain !== 'ethereum' && |
| 473 | + sourceChain !== 'binance' && |
| 474 | + sourceChain !== 'tron' && |
| 475 | + sourceChain !== 'trc20'; |
455 | 476 |
|
456 | 477 | const remark = isInternalChain |
457 | 478 | ? { |
@@ -492,12 +513,12 @@ export default function App() { |
492 | 513 | // 4. 构造 fromTrJson(根据链类型) |
493 | 514 | // 注意:EVM 需要 raw signed tx 的 hex;TRON/内链需要结构化交易体 |
494 | 515 | const fromTrJson: FromTrJson = {}; |
495 | | - const isTronChain = chainLower === 'tron' || chainLower === 'trc20'; |
496 | | - const isTrc20 = chainLower === 'trc20' || (chainLower === 'tron' && !!selectedAsset.contractAddress); |
| 516 | + const isTronChain = sourceChain === 'tron' || sourceChain === 'trc20'; |
| 517 | + const isTrc20 = sourceChain === 'trc20' || (sourceChain === 'tron' && !!selectedAsset.contractAddress); |
497 | 518 |
|
498 | | - if (chainLower === 'eth') { |
| 519 | + if (sourceChain === 'ethereum') { |
499 | 520 | fromTrJson.eth = { signTransData: extractEvmSignedTxData(signedTx.data, 'ETH') }; |
500 | | - } else if (chainLower === 'bsc') { |
| 521 | + } else if (sourceChain === 'binance') { |
501 | 522 | fromTrJson.bsc = { signTransData: extractEvmSignedTxData(signedTx.data, 'BSC') }; |
502 | 523 | } else if (isTronChain) { |
503 | 524 | if (isTrc20) { |
|
0 commit comments