@xswap-link/sdk 0.13.0 → 0.14.0

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/index.d.mts +6 -2
  3. package/dist/index.d.ts +6 -2
  4. package/dist/index.global.js +90 -89
  5. package/dist/index.js +1633 -1519
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +1597 -1480
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +1 -1
  10. package/src/assets/icons/AdjustmentsIcon.tsx +18 -0
  11. package/src/assets/icons/CaretDownIcon.tsx +12 -0
  12. package/src/assets/icons/CaretsUpDownIcon.tsx +13 -0
  13. package/src/assets/icons/ChainlinkMarkIcon.tsx +17 -0
  14. package/src/assets/icons/ClockIcon.tsx +18 -0
  15. package/src/assets/icons/WarningIcon.tsx +16 -0
  16. package/src/assets/icons/index.ts +6 -0
  17. package/src/components/Modal/index.tsx +2 -2
  18. package/src/components/PoweredBy/index.tsx +14 -5
  19. package/src/components/Swap/Header/Controls/index.tsx +50 -36
  20. package/src/components/Swap/Header/index.tsx +12 -5
  21. package/src/components/Swap/HistoryView/ActivityCard/index.tsx +212 -0
  22. package/src/components/Swap/HistoryView/index.tsx +24 -6
  23. package/src/components/Swap/ReorderButton/ReorderButton.tsx +5 -7
  24. package/src/components/Swap/SettingsView/Delivery/index.tsx +27 -28
  25. package/src/components/Swap/SettingsView/InfiniteApproval/index.tsx +27 -24
  26. package/src/components/Swap/SettingsView/Slippage/index.tsx +44 -43
  27. package/src/components/Swap/SettingsView/index.tsx +1 -1
  28. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/index.tsx +2 -2
  29. package/src/components/Swap/SwapView/FeesPanel/DeliveryInfo/index.tsx +9 -19
  30. package/src/components/Swap/SwapView/FeesPanel/Fee/index.tsx +4 -4
  31. package/src/components/Swap/SwapView/FeesPanel/Fees/index.tsx +5 -9
  32. package/src/components/Swap/SwapView/FeesPanel/index.tsx +21 -22
  33. package/src/components/Swap/SwapView/SwapButton/index.tsx +25 -6
  34. package/src/components/Swap/SwapView/SwapPanel/AmountPanel/Balance/index.tsx +56 -12
  35. package/src/components/Swap/SwapView/SwapPanel/AmountPanel/index.tsx +42 -41
  36. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/NetworkFilter/index.tsx +157 -0
  37. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +98 -55
  38. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +160 -239
  39. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +57 -31
  40. package/src/components/Swap/SwapView/SwapPanel/UsdValue/index.tsx +27 -0
  41. package/src/components/Swap/SwapView/SwapPanel/WalletPanel/index.tsx +60 -49
  42. package/src/components/Swap/SwapView/SwapPanel/index.tsx +20 -25
  43. package/src/components/Swap/SwapView/WalletPicker/index.tsx +6 -1
  44. package/src/components/Swap/SwapView/index.tsx +2 -1
  45. package/src/components/Swap/index.tsx +4 -2
  46. package/src/components/ToggleButton/index.tsx +18 -15
  47. package/src/components/TxConfigForm/index.tsx +5 -5
  48. package/src/components/TxWidgetWC/index.tsx +4 -0
  49. package/src/components/TxWidgetWCWrapped/index.tsx +2 -0
  50. package/src/context/HistoryProvider.tsx +1 -0
  51. package/src/context/SwapProvider.tsx +94 -67
  52. package/src/models/TransactionHistory.ts +1 -0
  53. package/src/models/payloads/ModalIntegrationPayload.ts +1 -0
  54. package/src/models/payloads/WidgetIntegrationPayload.ts +1 -0
  55. package/src/utils/index.ts +21 -0
  56. package/tailwind.config.js +2 -2
  57. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +0 -97
  58. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/index.tsx +0 -103
  59. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/index.tsx +0 -65
  60. package/src/components/Swap/SwapView/SwapPanel/MaxPanel/index.tsx +0 -43
  61. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/QuickPickTokenItem/index.tsx +0 -37
@@ -4,7 +4,6 @@ import { CloseIcon, CopyIcon, SearchIcon } from "@src/assets/icons";
4
4
  import {
5
5
  Button,
6
6
  Spinner,
7
- TextInput,
8
7
  TokenLogoWithChain,
9
8
  UnknownTokenLogo,
10
9
  } from "@src/components";
@@ -14,6 +13,7 @@ import { ERC20Abi } from "@src/contracts";
14
13
  import { useEvmContractApi } from "@src/hooks";
15
14
  import { Chain, Ecosystem, ImportedTokenData, TokenOption } from "@src/models";
16
15
  import {
16
+ isChainConnectionSupported,
17
17
  isETHAddressValid,
18
18
  isServer,
19
19
  isSolanaAddressValid,
@@ -22,7 +22,7 @@ import {
22
22
  import { BigNumber, ethers } from "ethers";
23
23
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
24
24
  import { GroupedVirtuoso } from "react-virtuoso";
25
- import { QuickPickTokenItem } from "./QuickPickTokenItem";
25
+ import { NetworkFilter } from "./NetworkFilter";
26
26
  import { TokenItem } from "./TokenItem";
27
27
  import { useAccount } from "wagmi";
28
28
  import { Connection, PublicKey } from "@solana/web3.js";
@@ -55,13 +55,15 @@ export const TokenPicker = ({
55
55
  const [loadingCustomTokenData, setLoadingCustomTokenData] = useState(false);
56
56
  const [customTokenData, setCustomTokenData] =
57
57
  useState<ImportedTokenData | null>(null);
58
- const [showQuickPicks, setShowQuickPicks] = useState(true);
58
+ const [networkFilter, setNetworkFilter] = useState<Chain | undefined>(chain);
59
59
  const currentRouteRequestNonce = useRef<number>(0);
60
60
  const tokenSearchRef = useRef<HTMLInputElement | null>(null);
61
61
 
62
62
  const {
63
63
  bridgeUI,
64
64
  supportedChains,
65
+ srcChain,
66
+ dstChain,
65
67
  findTokenDataByAddressAndChain,
66
68
  tokenPrices,
67
69
  addTokenToChainIfNotExists,
@@ -295,40 +297,26 @@ export const TokenPicker = ({
295
297
 
296
298
  useEffect(() => {
297
299
  setSearchValue("");
300
+ setNetworkFilter(chain);
301
+ // eslint-disable-next-line react-hooks/exhaustive-deps
298
302
  }, [isOpen]);
299
303
 
300
304
  const isMatch = (value, searchValue) =>
301
305
  value.toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
302
306
 
303
- const filteredTokens = useMemo(
304
- () =>
305
- tokens?.filter(
306
- (token) =>
307
- isMatch(token.symbol, searchValue) ||
308
- isMatch(token.name, searchValue) ||
309
- token.address.toLowerCase() === searchValue.toLowerCase(),
310
- ),
311
- [searchValue, tokens],
312
- );
313
-
314
- const otherFilteredTokens = useMemo(
315
- () =>
316
- otherTokens?.filter(
317
- (token) =>
318
- isMatch(token.symbol, searchValue) ||
319
- isMatch(token.name, searchValue) ||
320
- token.address.toLowerCase() === searchValue.toLowerCase(),
321
- ),
322
- [searchValue, otherTokens],
323
- );
324
-
325
- useEffect(() => {
326
- if (isOpen && tokenSearchRef.current) {
327
- setTimeout(() => {
328
- tokenSearchRef.current?.focus();
329
- }, 10); // delay focus a tiny bit to ensure it works
330
- }
331
- }, [isOpen]);
307
+ const visibleTokens = useMemo(() => {
308
+ const all = [...(tokens || []), ...(otherTokens || [])];
309
+ return all.filter((token) => {
310
+ if (networkFilter && token.chainId !== networkFilter.chainId) {
311
+ return false;
312
+ }
313
+ return (
314
+ isMatch(token.symbol, searchValue) ||
315
+ isMatch(token.name, searchValue) ||
316
+ token.address.toLowerCase() === searchValue.toLowerCase()
317
+ );
318
+ });
319
+ }, [tokens, otherTokens, searchValue, networkFilter]);
332
320
 
333
321
  const calculateTokenValue = useCallback(
334
322
  (token: TokenOption) => {
@@ -342,119 +330,107 @@ export const TokenPicker = ({
342
330
  [tokenPrices],
343
331
  );
344
332
 
345
- const ownedFilteredTokens = useMemo(() => {
346
- return [
347
- ...filteredTokens.filter((token) =>
348
- BigNumber.from(token?.balance || "0").gt(0),
349
- ),
350
- ...otherFilteredTokens.filter((token) =>
351
- BigNumber.from(token?.balance || "0").gt(0),
352
- ),
353
- ].sort((tokenA, tokenB) => {
354
- const valueA = calculateTokenValue(tokenA);
355
- const valueB = calculateTokenValue(tokenB);
356
- // First sort by USD value
357
- if (valueB !== valueA) {
358
- return valueB - valueA;
359
- }
360
- // If USD values are equal (or both 0), sort by priority
361
- return tokenB.priority - tokenA.priority;
362
- });
363
- }, [filteredTokens, otherFilteredTokens, calculateTokenValue]);
333
+ const ownedTokens = useMemo(() => {
334
+ if (!address && !solanaAddress) {
335
+ return [];
336
+ }
337
+ return visibleTokens
338
+ .filter((token) => BigNumber.from(token?.balance || "0").gt(0))
339
+ .sort((tokenA, tokenB) => {
340
+ const valueA = calculateTokenValue(tokenA);
341
+ const valueB = calculateTokenValue(tokenB);
342
+ // First sort by USD value
343
+ if (valueB !== valueA) {
344
+ return valueB - valueA;
345
+ }
346
+ // If USD values are equal (or both 0), sort by priority
347
+ return tokenB.priority - tokenA.priority;
348
+ });
349
+ }, [visibleTokens, address, solanaAddress, calculateTokenValue]);
364
350
 
365
- const allTokens = useMemo(() => {
366
- const currentChainTokens = filteredTokens
367
- .filter((token) => BigNumber.from(token?.balance || "0").eq(0))
368
- .sort(
369
- (tokenDataA, tokenDataB) => tokenDataB.priority - tokenDataA.priority,
370
- );
371
- const otherChainTokens = otherFilteredTokens
372
- .filter((token) => BigNumber.from(token?.balance || "0").eq(0))
373
- .sort(
374
- (tokenDataA, tokenDataB) => tokenDataB.priority - tokenDataA.priority,
375
- );
351
+ const recommendedTokens = useMemo(
352
+ () =>
353
+ visibleTokens
354
+ .filter(
355
+ (token) =>
356
+ !(address || solanaAddress) ||
357
+ BigNumber.from(token?.balance || "0").eq(0),
358
+ )
359
+ .sort(
360
+ (tokenDataA, tokenDataB) => tokenDataB.priority - tokenDataA.priority,
361
+ ),
362
+ [visibleTokens, address, solanaAddress],
363
+ );
376
364
 
377
- // Create groups based on chain and wallet connection status
378
- const groups = chain
365
+ const tokenGroups = useMemo(() => {
366
+ return ownedTokens.length
379
367
  ? [
380
- ...(!!(address || solanaAddress) && ownedFilteredTokens.length
381
- ? [ownedFilteredTokens]
382
- : []),
383
- currentChainTokens,
384
- otherChainTokens,
368
+ { label: "MY TOKENS.", tokens: ownedTokens },
369
+ { label: "RECOMMENDED.", tokens: recommendedTokens },
385
370
  ]
386
- : [
387
- ...(!!(address || solanaAddress) && ownedFilteredTokens.length
388
- ? [ownedFilteredTokens]
389
- : []),
390
- [...currentChainTokens, ...otherChainTokens],
391
- ];
392
-
393
- return groups.flat();
394
- }, [
395
- filteredTokens,
396
- otherFilteredTokens,
397
- ownedFilteredTokens,
398
- chain,
399
- address,
400
- solanaAddress,
401
- ]);
371
+ : [{ label: "RECOMMENDED.", tokens: recommendedTokens }];
372
+ }, [ownedTokens, recommendedTokens]);
402
373
 
403
- const ownedTokens = useMemo(
404
- () => allTokens.filter((token) => token.balance?.gt(0)),
405
- [allTokens],
374
+ const allTokens = useMemo(
375
+ () => tokenGroups.flatMap((group) => group.tokens),
376
+ [tokenGroups],
406
377
  );
407
378
 
408
- const tokenGroups = useMemo(() => {
409
- const currentChainTokens = filteredTokens
410
- .filter((token) => BigNumber.from(token?.balance || "0").eq(0))
411
- .sort(
412
- (tokenDataA, tokenDataB) => tokenDataB.priority - tokenDataA.priority,
413
- );
414
- const otherChainTokens = otherFilteredTokens
415
- .filter((token) => BigNumber.from(token?.balance || "0").eq(0))
416
- .sort(
417
- (tokenDataA, tokenDataB) => tokenDataB.priority - tokenDataA.priority,
379
+ const getResetWarning = useCallback(
380
+ (token: TokenOption): SwapPanelType | null => {
381
+ if (type === "destination") {
382
+ if (
383
+ srcChain &&
384
+ !isChainConnectionSupported(srcChain, token.chainId, bridgeUI)
385
+ ) {
386
+ return "source";
387
+ }
388
+ return null;
389
+ }
390
+ const tokenChain = supportedChains.find(
391
+ ({ chainId }) => chainId === token.chainId,
418
392
  );
393
+ if (
394
+ dstChain &&
395
+ tokenChain &&
396
+ !isChainConnectionSupported(tokenChain, dstChain.chainId, bridgeUI)
397
+ ) {
398
+ return "destination";
399
+ }
400
+ return null;
401
+ },
402
+ [type, srcChain, dstChain, bridgeUI, supportedChains],
403
+ );
419
404
 
420
- return chain
421
- ? [
422
- ...(!!(address || solanaAddress) && ownedFilteredTokens.length
423
- ? [ownedFilteredTokens]
424
- : []),
425
- currentChainTokens,
426
- otherChainTokens,
427
- ]
428
- : [
429
- ...(!!(address || solanaAddress) && ownedFilteredTokens.length
430
- ? [ownedFilteredTokens]
431
- : []),
432
- [...currentChainTokens, ...otherChainTokens],
433
- ];
434
- }, [
435
- chain,
436
- address,
437
- solanaAddress,
438
- filteredTokens,
439
- otherFilteredTokens,
440
- ownedFilteredTokens,
441
- ]);
405
+ useEffect(() => {
406
+ if (isOpen && tokenSearchRef.current) {
407
+ setTimeout(() => {
408
+ tokenSearchRef.current?.focus();
409
+ }, 10); // delay focus a tiny bit to ensure it works
410
+ }
411
+ }, [isOpen]);
442
412
 
443
413
  return showImportWarning ? (
444
414
  <>
445
- <div className="flex justify-between">
446
- <div className="text-base/4 mb-4">Import token</div>
447
- <div
448
- className="w-4 h-4 fill-t_text_primary cursor-pointer"
415
+ <div className="flex justify-between items-center mb-6">
416
+ <div className="text-2xl leading-8 tracking-[0.01em]">
417
+ Import token
418
+ </div>
419
+ <button
420
+ type="button"
421
+ aria-label="Close"
422
+ className="flex items-center justify-center w-8 h-8 rounded-md bg-t_bg_tertiary bg-opacity-5 hover:bg-opacity-10 transition-colors"
449
423
  onClick={() => setModalOpen(false)}
450
424
  >
451
- <CloseIcon />
452
- </div>
425
+ <div className="w-4 h-4 opacity-50 fill-t_text_primary flex items-center justify-center">
426
+ <CloseIcon />
427
+ </div>
428
+ </button>
453
429
  </div>
454
430
  <div className="flex flex-col h-full gap-2">
455
431
  {customTokenData && (
456
432
  <div
457
- className={`token-picker-container grow-0 bg-t_bg_secondary border border-solid border-t_text_primary border-opacity-10 rounded-xl py-2 pr-2 pl-4 hover:cursor-pointer`}
433
+ className={`flex gap-3 py-3 px-4 items-center grow-0 bg-t_bg_tertiary bg-opacity-[0.03] border border-solid border-t_text_primary border-opacity-10 rounded-xl`}
458
434
  >
459
435
  <UnknownTokenLogo
460
436
  tokenName={customTokenData.name}
@@ -464,7 +440,7 @@ export const TokenPicker = ({
464
440
  <div className="overflow-hidden whitespace-nowrap text-ellipsis text-sm font-medium">
465
441
  {customTokenData.name}
466
442
  </div>
467
- <div className="token-picker__all__symbol">
443
+ <div className="text-sm text-t_text_primary text-opacity-50">
468
444
  {customTokenData.symbol}
469
445
  </div>
470
446
  </div>
@@ -478,19 +454,19 @@ export const TokenPicker = ({
478
454
  )
479
455
  }
480
456
  aria-label={`Copy ${customTokenData.symbol} token address`}
481
- className="flex items-center p-2 fill-white cursor-pointer hover:fill-t_main_accent_light"
457
+ className="flex items-center p-2 fill-t_text_primary cursor-pointer hover:fill-t_main_accent_light"
482
458
  >
483
459
  <CopyIcon className="w-5 h-5" />
484
460
  </button>
485
461
  </div>
486
462
  </div>
487
463
  )}
488
- <div className="px-2 py-4 rounded-xl border border-x_orange text-sm">
464
+ <div className="px-4 py-4 rounded-xl border border-solid border-t_warning_dark text-sm text-t_text_primary text-opacity-80">
489
465
  Ensure that you have verified the token address and confirmed its
490
466
  correctness
491
467
  </div>
492
- <div className="bg-t_bg_secondary border border-solid border-t_text_primary border-opacity-10 rounded-xl p-2">
493
- <div className="text-sm mb-2">
468
+ <div className="bg-t_bg_tertiary bg-opacity-[0.03] border border-solid border-t_text_primary border-opacity-10 rounded-xl p-4">
469
+ <div className="text-sm mb-2 text-t_text_primary text-opacity-80">
494
470
  Be mindful that anyone can create tokens, even counterfeit versions
495
471
  of existing ones. Certain tokens and their technical specifications
496
472
  might not be compatible with XSwap services. By importing such
@@ -501,21 +477,21 @@ export const TokenPicker = ({
501
477
  onClick={() => setAcceptRisks((state) => !state)}
502
478
  className="flex items-center"
503
479
  >
504
- <div className="flex justify-center items-center p-1 w-6 h-6 border-2 border-white rounded-md mr-2">
480
+ <div className="flex justify-center items-center p-1 w-6 h-6 border-2 border-solid border-t_text_primary border-opacity-50 rounded-md mr-2">
505
481
  {acceptRisks && (
506
482
  <FontAwesomeIcon icon={faCheck} className="w-4 h-4" />
507
483
  )}
508
484
  </div>
509
485
 
510
- <div className="font-bold">Accept</div>
486
+ <div className="font-medium">Accept</div>
511
487
  </button>
512
488
  </div>
513
489
  <div className="flex grow items-end justify-center">
514
490
  <Button
515
491
  type="button"
516
492
  disabled={!acceptRisks}
517
- className={`token-picker__import-button w-full ${
518
- !acceptRisks ? "!cursor-not-allowed" : ""
493
+ className={`w-full !rounded-[10px] !py-3 !text-sm !font-medium bg-gradient-to-br from-t_main_accent_light to-t_main_accent_dark !text-t_button_pr_text ${
494
+ !acceptRisks ? "!cursor-not-allowed opacity-50" : ""
519
495
  }`}
520
496
  onClick={importCustomToken}
521
497
  >
@@ -526,49 +502,43 @@ export const TokenPicker = ({
526
502
  </>
527
503
  ) : (
528
504
  <>
529
- <div className="flex justify-between">
530
- <div className="text-base/4 text-t_text_primary mb-4">{`Pick ${type} token`}</div>
531
- <div
532
- className="w-4 h-4 fill-t_text_primary cursor-pointer"
505
+ <div className="flex justify-between items-center mb-6">
506
+ <div className="text-2xl leading-8 tracking-[0.01em] text-t_text_primary">
507
+ Select Token
508
+ </div>
509
+ <button
510
+ type="button"
511
+ aria-label="Close"
512
+ className="flex items-center justify-center w-8 h-8 rounded-md bg-t_bg_tertiary bg-opacity-5 hover:bg-opacity-10 transition-colors"
533
513
  onClick={() => setModalOpen(false)}
534
514
  >
535
- <CloseIcon />
536
- </div>
515
+ <div className="w-4 h-4 opacity-50 fill-t_text_primary flex items-center justify-center">
516
+ <CloseIcon />
517
+ </div>
518
+ </button>
537
519
  </div>
538
520
 
539
- <TextInput
540
- ref={tokenSearchRef}
541
- inputIcon={
542
- <div className="fill-t_text_primary">
521
+ <div className="flex items-center justify-between gap-2 h-14 pl-4 pr-1 rounded-xl bg-t_bg_tertiary bg-opacity-[0.03] border border-solid border-t_text_primary border-opacity-5 mb-6">
522
+ <div className="flex items-center gap-2 flex-1 min-w-0">
523
+ <div className="fill-t_text_primary opacity-50 [&_svg]:w-4 [&_svg]:h-4 flex items-center shrink-0">
543
524
  <SearchIcon />
544
525
  </div>
545
- }
546
- placeholder="Search name or paste address"
547
- value={searchValue}
548
- handleChange={setSearchValue}
549
- />
550
- <div
551
- className={`flex flex-wrap gap-1 my-4 mx-0 transition-all duration-300 ${
552
- showQuickPicks
553
- ? "opacity-100 max-h-[200px]"
554
- : "opacity-0 max-h-0 overflow-hidden"
555
- }`}
556
- >
557
- {tokens
558
- .filter((token) => token?.quickPick)
559
- .map((token) => (
560
- <QuickPickTokenItem
561
- key={token.address}
562
- token={token}
563
- selectedTokenAddress={selectedTokenAddress}
564
- onClick={() => {
565
- onSelect(token);
566
- setModalOpen(false);
567
- }}
568
- />
569
- ))}
526
+ <input
527
+ ref={tokenSearchRef}
528
+ value={searchValue}
529
+ onChange={(e) => setSearchValue(e.target.value)}
530
+ placeholder="Search name or paste address"
531
+ className="bg-transparent border-none outline-none w-full text-sm leading-6 text-t_text_primary placeholder:text-t_text_primary placeholder:text-opacity-40"
532
+ />
533
+ </div>
534
+ <NetworkFilter
535
+ type={type}
536
+ selectedChain={networkFilter}
537
+ onSelect={setNetworkFilter}
538
+ />
570
539
  </div>
571
- <div className="flex flex-col mx-0 h-full">
540
+
541
+ <div className="flex flex-col mx-0 h-full min-h-0 flex-1">
572
542
  {loadingCustomTokenData ? (
573
543
  <div className="flex justify-center w-full py-4 px-0">
574
544
  <Spinner className="w-9 h-9" />
@@ -576,7 +546,7 @@ export const TokenPicker = ({
576
546
  ) : (
577
547
  <>
578
548
  {customTokenData ? (
579
- <div className={`token-picker-container hover:cursor-default`}>
549
+ <div className="flex gap-3 py-3 px-4 items-center rounded-xl bg-t_bg_tertiary bg-opacity-[0.03]">
580
550
  <TokenLogoWithChain
581
551
  token={customTokenData}
582
552
  chain={chain}
@@ -593,14 +563,14 @@ export const TokenPicker = ({
593
563
  {chain?.displayName}
594
564
  </div>
595
565
  </div>
596
- <div className="token-picker__all__symbol">
566
+ <div className="text-sm text-t_text_primary text-opacity-50">
597
567
  {customTokenData.symbol}
598
568
  </div>
599
569
  </div>
600
570
  <div>
601
571
  <Button
602
572
  type="button"
603
- className="h-8 py-0 px-4 text-t_text_primary leading-[14px] rounded-[32px] bg-gradient-to-r from-t_main_accent_light to-t_main_accent_dark"
573
+ className="h-8 py-0 px-4 leading-[14px] rounded-lg bg-gradient-to-br from-t_main_accent_light to-t_main_accent_dark !text-t_button_pr_text"
604
574
  onClick={() => setShowImportWarning(true)}
605
575
  >
606
576
  Import
@@ -608,83 +578,34 @@ export const TokenPicker = ({
608
578
  </div>
609
579
  </div>
610
580
  ) : (
611
- <div className="flex flex-col h-full gap-8 w-[calc(100%+32px)] mx-[-16px]">
581
+ <div className="flex flex-col h-full">
612
582
  <GroupedVirtuoso
613
583
  style={{ maxHeight: "700px", height: "100%" }}
614
- groupCounts={tokenGroups.map((group) => group?.length)}
615
- scrollerRef={(ref) => {
616
- if (ref) {
617
- ref.addEventListener("scroll", (e) => {
618
- const target = e.target as HTMLDivElement;
619
- setShowQuickPicks(target.scrollTop < 10);
620
- });
621
- }
622
- }}
584
+ groupCounts={tokenGroups.map((group) => group.tokens.length)}
623
585
  groupContent={(index) => (
624
- <div className="py-1 bg-t_bg_primary text-t_text_primary">
625
- <div className="px-4 text-left">
626
- {(() => {
627
- if (chain) {
628
- // chain is selected
629
- switch (index) {
630
- case 0: {
631
- if (!address && !solanaAddress) {
632
- return `${chain.displayName} network`;
633
- }
634
- return ownedTokens.length
635
- ? "My tokens"
636
- : `${chain.displayName} network`;
637
- }
638
- case 1: {
639
- if (!address && !solanaAddress) {
640
- return "Other networks";
641
- }
642
- return `${chain.displayName} network`;
643
- }
644
- case 2: {
645
- return "Other networks";
646
- }
647
- default: {
648
- return "Undefined group";
649
- }
650
- }
651
- } else {
652
- // chain is not selected
653
- switch (index) {
654
- case 0: {
655
- if (!address) {
656
- return "All networks";
657
- }
658
- return ownedTokens.length
659
- ? "My tokens"
660
- : "All networks";
661
- }
662
- case 1: {
663
- return "All networks";
664
- }
665
- default: {
666
- return "Undefined group";
667
- }
668
- }
669
- }
670
- })()}
671
- </div>
672
- <div className="horizontal-separator" />
673
- {!tokenGroups[index]?.length && (
674
- <div className="text-center py-1">No token found</div>
586
+ <div className="pb-3 bg-t_bg_primary">
587
+ <p className="text-[10px] font-medium leading-4 tracking-[0.015em] text-t_text_primary text-opacity-30 text-left">
588
+ {tokenGroups[index]?.label}
589
+ </p>
590
+ {!tokenGroups[index]?.tokens.length && (
591
+ <div className="text-center py-1 text-sm text-t_text_primary text-opacity-50">
592
+ No token found
593
+ </div>
675
594
  )}
676
595
  </div>
677
596
  )}
678
597
  itemContent={(index) => {
598
+ const token = allTokens[index];
679
599
  return (
680
- allTokens[index] && (
600
+ token && (
681
601
  <TokenItem
682
602
  panelType={type}
683
- token={allTokens[index]}
603
+ token={token}
684
604
  selectedChainId={chain?.chainId}
685
605
  selectedTokenAddress={selectedTokenAddress}
606
+ resetWarning={getResetWarning(token)}
686
607
  onClick={() => {
687
- onSelect(allTokens[index]!);
608
+ onSelect(token);
688
609
  setModalOpen(false);
689
610
  }}
690
611
  />