@orderly.network/ui-transfer 3.1.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import { i18n, useTranslation, Trans } from '@orderly.network/i18n';
2
- import { registerSimpleDialog, registerSimpleSheet, Tabs, TabPanel, ArrowDownSquareFillIcon, ArrowUpSquareFillIcon, ExtensionSlot, ExtensionPositionEnum, Box, textVariants, Flex, toast, Text, cn, Button, useDocumentDirection, Spinner, Select, Input, inputFormatter, useScreen, modal, Tooltip, Tips, AlertDialog, EditIcon, ArrowLeftRightIcon, WalletIcon, DropdownMenuRoot, DropdownMenuTrigger, DropdownMenuPortal, DropdownMenuContent, ScrollArea, ChainIcon, Badge, CaretUpIcon, CaretDownIcon, SimpleDialog, CloseRoundFillIcon, ExclamationFillIcon, TokenIcon, WarningIcon, SelectItem, ChevronRightIcon, Checkbox, CloseIcon } from '@orderly.network/ui';
2
+ import { registerSimpleDialog, registerSimpleSheet, Tabs, TabPanel, ArrowDownSquareFillIcon, ArrowUpSquareFillIcon, ExtensionSlot, ExtensionPositionEnum, toast, Box, textVariants, Flex, Text, cn, Button, useDocumentDirection, Spinner, Select, Input, inputFormatter, useScreen, modal, Tooltip, Tips, AlertDialog, EditIcon, ArrowLeftRightIcon, WalletIcon, DropdownMenuRoot, DropdownMenuTrigger, DropdownMenuPortal, DropdownMenuContent, ScrollArea, ChainIcon, Badge, CaretUpIcon, CaretDownIcon, SimpleDialog, CloseRoundFillIcon, ExclamationFillIcon, TokenIcon, WarningIcon, SelectItem, ChevronRightIcon, Checkbox, CloseIcon } from '@orderly.network/ui';
3
3
  import { forwardRef, useState, isValidElement, useMemo, useEffect, useCallback, useRef } from 'react';
4
- import { useConfig, useWalletConnector, useLocalStorage, useConvert, useOdosQuote, useComputedLTV, useAccount, useAppStore, useTransfer, useSubAccountDataObserver, useSubAccountMaxWithdrawal, useTokensInfo, useEventEmitter, usePositionStream, useIndexPricesStream, useOrderlyContext, useDeposit, useAssetsHistory, useChains, useMemoizedFn, useWithdraw, useWalletTopic, useQuery, useSWR, useTokenInfo, useHoldingStream, useInternalTransfer, useDebouncedCallback, usePrivateQuery, useTransferHistory, useBalanceTopic } from '@orderly.network/hooks';
4
+ import { useConfig, useWalletConnector, useLocalStorage, useConvert, useOdosQuote, useComputedLTV, useAccount, useAppStore, useTransfer, useSubAccountDataObserver, useSubAccountMaxWithdrawal, useMainTokenStore, useEventEmitter, usePositionStream, useIndexPricesStream, useOrderlyContext, useDeposit, useAssetsHistory, useChains, useMemoizedFn, useWithdraw, useWalletTopic, useQuery, useSWR, useTokenInfo, useTokensInfo, useHoldingStream, useInternalTransfer, useDebouncedCallback, usePrivateQuery, useTransferHistory, useBalanceTopic } from '@orderly.network/hooks';
5
5
  import { Decimal, zero, praseChainIdToNumber, int2hex, toNonExponential, formatWithPrecision, isSolana } from '@orderly.network/utils';
6
6
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
- import { AccountStatusEnum, ChainNamespace, AssetHistoryStatusEnum, AssetHistorySideEnum, Arbitrum, EMPTY_OBJECT, isNativeTokenChecker, ABSTRACT_CHAIN_ID_MAP, nativeTokenAddress } from '@orderly.network/types';
7
+ import { AccountStatusEnum, ChainNamespace, AssetHistoryStatusEnum, AssetHistorySideEnum, EMPTY_OBJECT, isNativeTokenChecker, ABSTRACT_CHAIN_ID_MAP, Arbitrum, nativeTokenAddress } from '@orderly.network/types';
8
8
  import { AuthGuard, useAuthGuard } from '@orderly.network/ui-connector';
9
9
  import { useAppContext, useAppConfig } from '@orderly.network/react-app';
10
10
  import { qrcode } from '@akamfoad/qr';
@@ -7175,6 +7175,7 @@ var SwapCoin = (props) => {
7175
7175
  }
7176
7176
  );
7177
7177
  };
7178
+ var nativeTokenAddress2 = "0x0000000000000000000000000000000000000000";
7178
7179
  var splitTokenBySymbol = (items) => {
7179
7180
  return items.reduce(
7180
7181
  (result, item) => {
@@ -7188,14 +7189,13 @@ var splitTokenBySymbol = (items) => {
7188
7189
  { usdc: [], others: [] }
7189
7190
  );
7190
7191
  };
7191
- var findChainInfo = (tokenInfo) => {
7192
+ var findMainnetQuoteChainInfo = (tokenInfo) => {
7192
7193
  const arbitrumChainInfo = tokenInfo.chain_details.find(
7193
7194
  (item) => parseInt(item.chain_id) === Arbitrum.id
7194
7195
  );
7195
7196
  const nativeTokenChainInfo = tokenInfo.chain_details.find(
7196
7197
  (item) => !item.contract_address
7197
7198
  );
7198
- const nativeTokenAddress2 = "0x0000000000000000000000000000000000000000";
7199
7199
  if (arbitrumChainInfo) {
7200
7200
  return {
7201
7201
  contract_address: arbitrumChainInfo.contract_address || nativeTokenAddress2,
@@ -7216,23 +7216,49 @@ var findChainInfo = (tokenInfo) => {
7216
7216
  decimals: tokenInfo.chain_details[0]?.decimals
7217
7217
  };
7218
7218
  };
7219
+ var getMainnetConvertTokenInfo = (tokenInfo) => {
7220
+ const chainInfo = findMainnetQuoteChainInfo(tokenInfo);
7221
+ if (!chainInfo) {
7222
+ return void 0;
7223
+ }
7224
+ return {
7225
+ ...tokenInfo,
7226
+ symbol: tokenInfo.token,
7227
+ precision: tokenInfo.decimals ?? 6,
7228
+ ...chainInfo
7229
+ };
7230
+ };
7231
+ var findQuoteTargetChainInfo = (targetToken, quoteChainId) => {
7232
+ const info = targetToken?.chain_details?.find(
7233
+ (item) => item.chain_id === quoteChainId
7234
+ );
7235
+ if (!info) {
7236
+ return void 0;
7237
+ }
7238
+ return {
7239
+ ...info,
7240
+ contract_address: info.contract_address || nativeTokenAddress2,
7241
+ precision: targetToken?.precision
7242
+ };
7243
+ };
7219
7244
  var useToken3 = (options2) => {
7220
7245
  const { defaultValue } = options2;
7221
7246
  const [sourceToken, setSourceToken] = useState();
7222
7247
  const [targetToken, setTargetToken] = useState();
7223
7248
  const [sourceTokens, setSourceTokens] = useState([]);
7224
- const tokensInfo = useTokensInfo();
7249
+ const tokensInfo = useMainTokenStore((state) => state.data);
7225
7250
  const newTokensInfo = useMemo(() => {
7226
- const filteredTokensInfo = tokensInfo.filter((item) => item.on_chain_swap);
7227
- return filteredTokensInfo.map((item) => {
7228
- const chainInfo = findChainInfo(item);
7229
- return {
7230
- ...item,
7231
- symbol: item.token,
7232
- precision: item.decimals ?? 6,
7233
- ...chainInfo
7234
- };
7235
- });
7251
+ const filteredTokensInfo = (tokensInfo ?? []).filter(
7252
+ (item) => item.on_chain_swap
7253
+ );
7254
+ return filteredTokensInfo.reduce((result, item) => {
7255
+ const tokenInfo = getMainnetConvertTokenInfo(item);
7256
+ if (!tokenInfo) {
7257
+ return result;
7258
+ }
7259
+ result.push(tokenInfo);
7260
+ return result;
7261
+ }, []);
7236
7262
  }, [tokensInfo]);
7237
7263
  useEffect(() => {
7238
7264
  const { usdc, others } = splitTokenBySymbol(newTokensInfo);
@@ -7247,13 +7273,7 @@ var useToken3 = (options2) => {
7247
7273
  setTargetToken(usdc[0]);
7248
7274
  }, [defaultValue, newTokensInfo]);
7249
7275
  const targetChainInfo = useMemo(() => {
7250
- const info = targetToken?.chain_details?.find(
7251
- (item) => item.chain_id === sourceToken?.quoteChainId
7252
- );
7253
- return {
7254
- ...info,
7255
- precision: targetToken?.precision
7256
- };
7276
+ return findQuoteTargetChainInfo(targetToken, sourceToken?.quoteChainId);
7257
7277
  }, [sourceToken, targetToken]);
7258
7278
  return {
7259
7279
  sourceToken,
@@ -7267,6 +7287,7 @@ var useToken3 = (options2) => {
7267
7287
  // src/components/convertForm/convertForm.script.tsx
7268
7288
  var { calcMinimumReceived } = account;
7269
7289
  var ORDERLY_CONVERT_SLIPPAGE_KEY = "orderly_convert_slippage";
7290
+ var ODOS_QUOTE_DEBOUNCE_MS = 300;
7270
7291
  var normalizeAmount = (amount, decimals) => {
7271
7292
  return new Decimal(amount).mul(new Decimal(10).pow(decimals)).toFixed(0);
7272
7293
  };
@@ -7324,16 +7345,26 @@ var useConvertFormScript = (options2) => {
7324
7345
  setLoading(false);
7325
7346
  });
7326
7347
  };
7327
- const [postQuote, { data: quoteData, isMutating: isQuoteLoading }] = useOdosQuote();
7328
- useEffect(() => {
7348
+ const [
7349
+ postQuote,
7350
+ { data: quoteData, reset: resetQuote, isMutating: isQuoteLoading }
7351
+ ] = useOdosQuote();
7352
+ const quoteRequest = useMemo(() => {
7329
7353
  const { quoteChainId, contract_address, decimals } = sourceToken || {};
7330
7354
  const targetAddress = targetChainInfo?.contract_address;
7331
- if (quantity && quoteChainId && contract_address && targetAddress) {
7332
- postQuote({
7355
+ if (!quantity || new Decimal(quantity).lte(0) || !quoteChainId || !contract_address || typeof decimals === "undefined" || !targetAddress || !address) {
7356
+ return null;
7357
+ }
7358
+ const inputAmount = normalizeAmount(quantity, decimals);
7359
+ return {
7360
+ inputAmount,
7361
+ inputTokenAddress: contract_address.toLowerCase(),
7362
+ outputTokenAddress: targetAddress.toLowerCase(),
7363
+ body: {
7333
7364
  chainId: parseInt(quoteChainId),
7334
7365
  inputTokens: [
7335
7366
  {
7336
- amount: normalizeAmount(quantity, decimals),
7367
+ amount: inputAmount,
7337
7368
  tokenAddress: contract_address
7338
7369
  }
7339
7370
  ],
@@ -7342,40 +7373,98 @@ var useConvertFormScript = (options2) => {
7342
7373
  proportion: 1,
7343
7374
  tokenAddress: targetAddress
7344
7375
  }
7345
- ]
7376
+ ],
7377
+ userAddr: address
7346
7378
  // simple: true,
7379
+ }
7380
+ };
7381
+ }, [
7382
+ quantity,
7383
+ sourceToken?.quoteChainId,
7384
+ sourceToken?.contract_address,
7385
+ sourceToken?.decimals,
7386
+ targetChainInfo?.contract_address,
7387
+ targetChainInfo?.decimals,
7388
+ address
7389
+ ]);
7390
+ useEffect(() => {
7391
+ resetQuote();
7392
+ if (!quoteRequest) {
7393
+ return;
7394
+ }
7395
+ let active = true;
7396
+ const timer = window.setTimeout(() => {
7397
+ postQuote(quoteRequest.body).catch((error) => {
7398
+ if (!active) {
7399
+ return;
7400
+ }
7401
+ let message = t("transfer.convert.failed");
7402
+ if (error instanceof Error) {
7403
+ message = error.message;
7404
+ } else if (error) {
7405
+ message = String(error);
7406
+ }
7407
+ if (message === "Failed to fetch") {
7408
+ message = t("transfer.convert.failed");
7409
+ }
7410
+ console.error("[convertForm] Odos quote failed:", error);
7411
+ toast.error(message);
7412
+ resetQuote();
7347
7413
  });
7414
+ }, ODOS_QUOTE_DEBOUNCE_MS);
7415
+ return () => {
7416
+ active = false;
7417
+ window.clearTimeout(timer);
7418
+ };
7419
+ }, [postQuote, quoteRequest, resetQuote, t]);
7420
+ const isQuoteDataMatched = useMemo(() => {
7421
+ if (!quoteData || !quoteRequest) {
7422
+ return false;
7423
+ }
7424
+ const inAmount = quoteData?.inAmounts?.[0]?.toString();
7425
+ const inToken = quoteData?.inTokens?.[0]?.toLowerCase();
7426
+ const outToken = quoteData?.outTokens?.[0]?.toLowerCase();
7427
+ return inAmount === quoteRequest.inputAmount && inToken === quoteRequest.inputTokenAddress && outToken === quoteRequest.outputTokenAddress;
7428
+ }, [quoteData, quoteRequest]);
7429
+ useEffect(() => {
7430
+ if (quoteData && !isQuoteDataMatched) {
7431
+ resetQuote();
7348
7432
  }
7349
- }, [quantity, sourceToken, targetChainInfo, postQuote]);
7433
+ }, [isQuoteDataMatched, quoteData, resetQuote]);
7350
7434
  const memoizedOutAmounts = useMemo(() => {
7351
- if (!quoteData || isQuoteLoading) {
7352
- return "-";
7435
+ if (quoteData && !isQuoteLoading && isQuoteDataMatched) {
7436
+ return quoteData?.outAmounts[0];
7353
7437
  }
7354
- return quoteData?.outAmounts[0];
7355
- }, [quoteData, isQuoteLoading]);
7438
+ return "-";
7439
+ }, [quoteData, isQuoteDataMatched, isQuoteLoading]);
7356
7440
  const memoizedConvertRate = useMemo(() => {
7357
- if (!quoteData || isQuoteLoading) {
7358
- return "-";
7441
+ if (quoteData && !isQuoteLoading && isQuoteDataMatched) {
7442
+ return new Decimal(
7443
+ unnormalizeAmount(
7444
+ quoteData.outAmounts[0],
7445
+ targetChainInfo?.decimals ?? 6
7446
+ )
7447
+ ).div(
7448
+ unnormalizeAmount(quoteData.inAmounts[0], sourceToken?.decimals ?? 6)
7449
+ ).toString();
7359
7450
  }
7360
- const rate = new Decimal(
7361
- unnormalizeAmount(
7362
- quoteData.outAmounts[0],
7363
- targetChainInfo?.decimals ?? 6
7364
- )
7365
- ).div(
7366
- unnormalizeAmount(quoteData.inAmounts[0], sourceToken?.decimals ?? 6)
7367
- ).toString();
7368
- return rate;
7369
- }, [isQuoteLoading, quoteData, sourceToken, targetChainInfo]);
7451
+ return "-";
7452
+ }, [
7453
+ isQuoteDataMatched,
7454
+ isQuoteLoading,
7455
+ quoteData,
7456
+ sourceToken,
7457
+ targetChainInfo
7458
+ ]);
7370
7459
  const memoizedMinimumReceived = useMemo(() => {
7371
- if (!quoteData || isQuoteLoading) {
7460
+ if (!quoteData || isQuoteLoading || !isQuoteDataMatched) {
7372
7461
  return 0;
7373
7462
  }
7374
7463
  return calcMinimumReceived({
7375
7464
  amount: quoteData?.outAmounts[0],
7376
7465
  slippage: Number(slippage)
7377
7466
  });
7378
- }, [quoteData, isQuoteLoading, slippage]);
7467
+ }, [quoteData, isQuoteDataMatched, isQuoteLoading, slippage]);
7379
7468
  const currentLtv = useComputedLTV();
7380
7469
  const nextLTV = useComputedLTV({
7381
7470
  input: Number(quantity),