@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
@@ -117,7 +117,7 @@ type SwapContext = {
117
117
  isFetchingBalances: boolean;
118
118
  isExpressDeliveryActive: boolean;
119
119
  quoteRoute: () => Promise<void>;
120
- refreshBalance: () => void;
120
+ refreshBalance: (options?: { forceRpc?: boolean }) => void;
121
121
  findTokenDataByAddressAndChain: (
122
122
  tokenAddress: string,
123
123
  chainId: string,
@@ -279,6 +279,7 @@ export const SwapProvider = ({
279
279
 
280
280
  const routeAbortController = useRef<AbortController | null>(null);
281
281
  const refreshSelectedTokenBalanceNonce = useRef(crypto.randomUUID());
282
+ const prevWalletAddresses = useRef<string | undefined>(undefined);
282
283
 
283
284
  // =============================================================================
284
285
  // Memoized Values
@@ -668,77 +669,96 @@ export const SwapProvider = ({
668
669
  srcValueWei,
669
670
  ]);
670
671
  // refreshes and updates the balance of the source token using its RPC URL.
671
- const refreshBalance = useCallback(async () => {
672
- if (
673
- (!evmAddress && !solanaAddress) ||
674
- !srcChain?.publicRpcUrls[0] ||
675
- !srcToken ||
676
- !srcToken?.address
677
- ) {
678
- return;
679
- }
680
-
681
- const nonce = crypto.randomUUID();
682
- refreshSelectedTokenBalanceNonce.current = nonce;
683
- setIsFetchingBalance(true);
684
- let balance = "0";
685
- if (srcChain?.ecosystem === Ecosystem.EVM && evmAddress) {
686
- const balanceFromBackend =
687
- tokenBalances[srcChain?.chainId]?.[srcToken.address];
688
- if (balanceFromBackend === undefined) {
689
- const balanceUI = await getBalanceOf(
690
- evmAddress,
691
- srcToken.address,
692
- srcChain?.publicRpcUrls[0],
693
- );
694
- balance = humanReadableToWei({
695
- amount: balanceUI,
696
- decimals: srcToken.decimals,
697
- });
698
- } else {
699
- balance = balanceFromBackend;
672
+ // pass { forceRpc: true } to skip the backend balances cache (e.g. right
673
+ // after a transaction, when the cached value is already stale).
674
+ const refreshBalance = useCallback(
675
+ async (options?: { forceRpc?: boolean }) => {
676
+ if (
677
+ (!evmAddress && !solanaAddress) ||
678
+ !srcChain?.publicRpcUrls[0] ||
679
+ !srcToken ||
680
+ !srcToken?.address
681
+ ) {
682
+ return;
700
683
  }
701
- } else if (srcChain?.ecosystem === Ecosystem.SOLANA && solanaAddress) {
702
- const solanaPublicKey = new PublicKey(solanaAddress);
703
- const connection = new Connection(srcChain.publicRpcUrls[0]!);
704
- if (srcToken.address === SOLANA_NATIVE_TOKEN_ADDRESS.toBase58()) {
705
- balance = new BigNumberJS(
706
- await connection.getBalance(solanaPublicKey),
707
- ).toString();
708
- } else {
709
- const tokenAccounts = await connection.getParsedTokenAccountsByOwner(
710
- solanaPublicKey,
711
- {
712
- programId: SOLANA_TOKEN_PROGRAM_ID,
713
- },
714
- );
715
- const token2022Accounts =
716
- await connection.getParsedTokenAccountsByOwner(solanaPublicKey, {
717
- programId: SOLANA_TOKEN_2022_PROGRAM_ID,
684
+
685
+ const nonce = crypto.randomUUID();
686
+ refreshSelectedTokenBalanceNonce.current = nonce;
687
+ setIsFetchingBalance(true);
688
+ let balance = "0";
689
+ if (srcChain?.ecosystem === Ecosystem.EVM && evmAddress) {
690
+ const balanceFromBackend =
691
+ tokenBalances[srcChain?.chainId]?.[srcToken.address];
692
+ if (options?.forceRpc || balanceFromBackend === undefined) {
693
+ const balanceUI = await getBalanceOf(
694
+ evmAddress,
695
+ srcToken.address,
696
+ srcChain?.publicRpcUrls[0],
697
+ );
698
+ balance = humanReadableToWei({
699
+ amount: balanceUI,
700
+ decimals: srcToken.decimals,
718
701
  });
719
- const allTokenAccount = [
720
- ...tokenAccounts.value,
721
- ...token2022Accounts.value,
722
- ];
723
- const tokenAccount = allTokenAccount.find(
724
- (account) =>
725
- account.account.data.parsed.info.mint === srcToken.address,
726
- );
727
- if (!tokenAccount) {
728
- balance = "0";
702
+ if (options?.forceRpc && balanceFromBackend !== undefined) {
703
+ // keep the backend cache in sync so token pickers and future
704
+ // non-forced refreshes see the fresh value
705
+ const chainId = srcChain.chainId;
706
+ const tokenAddress = srcToken.address;
707
+ const freshBalance = balance;
708
+ setTokenBalances((prev) => ({
709
+ ...prev,
710
+ [chainId]: {
711
+ ...prev[chainId],
712
+ [tokenAddress]: freshBalance,
713
+ },
714
+ }));
715
+ }
729
716
  } else {
730
- balance = tokenAccount.account.data.parsed.info.tokenAmount.amount;
717
+ balance = balanceFromBackend;
718
+ }
719
+ } else if (srcChain?.ecosystem === Ecosystem.SOLANA && solanaAddress) {
720
+ const solanaPublicKey = new PublicKey(solanaAddress);
721
+ const connection = new Connection(srcChain.publicRpcUrls[0]!);
722
+ if (srcToken.address === SOLANA_NATIVE_TOKEN_ADDRESS.toBase58()) {
723
+ balance = new BigNumberJS(
724
+ await connection.getBalance(solanaPublicKey),
725
+ ).toString();
726
+ } else {
727
+ const tokenAccounts = await connection.getParsedTokenAccountsByOwner(
728
+ solanaPublicKey,
729
+ {
730
+ programId: SOLANA_TOKEN_PROGRAM_ID,
731
+ },
732
+ );
733
+ const token2022Accounts =
734
+ await connection.getParsedTokenAccountsByOwner(solanaPublicKey, {
735
+ programId: SOLANA_TOKEN_2022_PROGRAM_ID,
736
+ });
737
+ const allTokenAccount = [
738
+ ...tokenAccounts.value,
739
+ ...token2022Accounts.value,
740
+ ];
741
+ const tokenAccount = allTokenAccount.find(
742
+ (account) =>
743
+ account.account.data.parsed.info.mint === srcToken.address,
744
+ );
745
+ if (!tokenAccount) {
746
+ balance = "0";
747
+ } else {
748
+ balance = tokenAccount.account.data.parsed.info.tokenAmount.amount;
749
+ }
731
750
  }
732
751
  }
733
- }
734
- if (nonce !== refreshSelectedTokenBalanceNonce.current) {
735
- return;
736
- }
752
+ if (nonce !== refreshSelectedTokenBalanceNonce.current) {
753
+ return;
754
+ }
737
755
 
738
- setSrcTokenBalanceWei(balance);
756
+ setSrcTokenBalanceWei(balance);
739
757
 
740
- setIsFetchingBalance(false);
741
- }, [evmAddress, solanaAddress, srcChain, srcToken, tokenBalances]);
758
+ setIsFetchingBalance(false);
759
+ },
760
+ [evmAddress, solanaAddress, srcChain, srcToken, tokenBalances],
761
+ );
742
762
  // retrieves token details for a given token address and chain from supported tokens mapping. (including imported tokens)
743
763
  const findTokenDataByAddressAndChain = useCallback(
744
764
  (tokenAddress: string, chainId: string): Token | undefined => {
@@ -801,9 +821,16 @@ export const SwapProvider = ({
801
821
  quoteRoute();
802
822
  }, [quoteRoute]);
803
823
  // calls refreshBalance to update source token balance on mount or when refreshBalance changes.
824
+ // when the connected wallet changed, force an RPC read — the cached backend
825
+ // balances still belong to the previous wallet until getBalances resolves.
804
826
  useEffect(() => {
805
- refreshBalance();
806
- }, [refreshBalance]);
827
+ const walletAddresses = `${evmAddress ?? ""}:${solanaAddress ?? ""}`;
828
+ const walletChanged =
829
+ prevWalletAddresses.current !== undefined &&
830
+ prevWalletAddresses.current !== walletAddresses;
831
+ prevWalletAddresses.current = walletAddresses;
832
+ refreshBalance(walletChanged ? { forceRpc: true } : undefined);
833
+ }, [refreshBalance, evmAddress, solanaAddress]);
807
834
  // fetches user all token balances when a wallet address is available and supported chains are loaded.
808
835
  useEffect(() => {
809
836
  let isCancelled = false;
@@ -43,6 +43,7 @@ export type TransactionStatus =
43
43
 
44
44
  export type Transaction = {
45
45
  messageId?: string;
46
+ receiver?: string;
46
47
  hash: string;
47
48
  timestamp: number;
48
49
  sourceChainId: string;
@@ -47,6 +47,7 @@ export type ModalIntegrationPayload = {
47
47
  srcToken?: string;
48
48
  customContractCalls?: ContractCall[];
49
49
  desc?: string;
50
+ widgetTitle?: string;
50
51
  dstDisplayToken?: string;
51
52
  lightTheme?: boolean;
52
53
  defaultWalletPicker?: boolean;
@@ -9,6 +9,7 @@ export type WidgetIntegrationPayload = {
9
9
  srcToken?: string;
10
10
  customContractCalls?: ContractCall[];
11
11
  desc?: string;
12
+ widgetTitle?: string;
12
13
  dstDisplayToken?: string;
13
14
  lightTheme?: boolean;
14
15
  defaultWalletPicker?: boolean;
@@ -77,6 +77,27 @@ export const resolveTokenAddress = (
77
77
  ?.address?.toLowerCase();
78
78
  };
79
79
 
80
+ /**
81
+ * Checks whether a transfer from `srcChain` can reach `dstChainId`,
82
+ * based on the chain-level support lists.
83
+ */
84
+ export const isChainConnectionSupported = (
85
+ srcChain: Chain | undefined,
86
+ dstChainId: string | undefined,
87
+ bridgeUI: boolean,
88
+ ): boolean => {
89
+ if (!srcChain || !dstChainId) {
90
+ return true;
91
+ }
92
+ if (srcChain.chainId === dstChainId) {
93
+ return true;
94
+ }
95
+ const supportedDst = bridgeUI
96
+ ? srcChain.supportedDstForBridge
97
+ : srcChain.supportedDstForSwap;
98
+ return !!supportedDst?.includes(dstChainId);
99
+ };
100
+
80
101
  export const sortChains = (chains: Chain[], disabledChainIds: string[]) =>
81
102
  [...chains]
82
103
 
@@ -96,10 +96,10 @@ export default {
96
96
  x_modal: "var(--modal-width, 340px)",
97
97
  },
98
98
  width: {
99
- x_modal: "var(--modal-width)",
99
+ x_modal: "var(--modal-width, 620px)",
100
100
  },
101
101
  maxWidth: {
102
- x_modal: "var(--modal-width, 480px)",
102
+ x_modal: "var(--modal-width, 620px)",
103
103
  },
104
104
  animation: {
105
105
  "spin-slow": "spin 3s linear infinite",
@@ -1,97 +0,0 @@
1
- import { DotGreenIcon } from "@src/assets/icons";
2
- import { SwapPanelType } from "@src/components/Swap/SwapView";
3
- import { useSwapContext } from "@src/context";
4
- import useNetworks from "@src/hooks/networkManagement/useNetworks";
5
- import { Chain } from "@src/models";
6
- import { useMemo } from "react";
7
-
8
- type Props = {
9
- chain: Chain;
10
- type: SwapPanelType;
11
- disabled: boolean;
12
- onClick: (chainId: string) => void;
13
- };
14
-
15
- export const ChainItem = ({ chain, type, onClick, disabled }: Props) => {
16
- const {
17
- networks: { evm },
18
- } = useNetworks();
19
-
20
- const { srcChain, dstChain, bridgeUI } = useSwapContext();
21
-
22
- const currentChainId = useMemo(
23
- () => (type === "source" ? srcChain?.chainId : dstChain?.chainId),
24
- [dstChain, srcChain, type],
25
- );
26
-
27
- const connected = useMemo(
28
- () => evm.signer && evm.chainId === chain.chainId,
29
- [chain.chainId, evm.chainId, evm.signer],
30
- );
31
-
32
- const sameChainId = useMemo(() => {
33
- if (!bridgeUI) {
34
- return undefined;
35
- }
36
-
37
- return type === "destination" ? srcChain?.chainId : dstChain?.chainId;
38
- }, [bridgeUI, dstChain?.chainId, srcChain?.chainId, type]);
39
-
40
- const getTooltipText = () => {
41
- if (chain.chainId === sameChainId) {
42
- return "Transfers between the same chains are not available";
43
- }
44
- if (disabled) {
45
- return bridgeUI
46
- ? "Token is not available on this chain"
47
- : `Swap from ${
48
- srcChain?.displayName || "the source chain"
49
- } to this chain is currently not supported.`;
50
- }
51
- return "";
52
- };
53
-
54
- const tooltipText = getTooltipText();
55
-
56
- return (
57
- <div className="group relative">
58
- <div
59
- onClick={() => {
60
- if (chain.chainId === sameChainId || disabled) {
61
- return;
62
- }
63
- onClick(chain.chainId);
64
- }}
65
- className={`flex justify-between items-center gap-2 mt-2 mb-2 cursor-pointer p-4 border border-solid border-white border-opacity-0 hover:selected-chain-item ${
66
- currentChainId === chain.chainId ? "selected-chain-item" : ""
67
- } ${
68
- chain.chainId === sameChainId || disabled
69
- ? "disabled-chain-item cursor-default"
70
- : ""
71
- }`}
72
- >
73
- <div className="flex gap-3 items-center w-full">
74
- <img
75
- src={chain.image}
76
- alt={chain.name}
77
- className="w-[34px] h-[34px]"
78
- />
79
- <p>{chain.displayName}</p>
80
- </div>
81
-
82
- {tooltipText && (
83
- <div className="w-full text-center opacity-0 group-hover:opacity-100 text-xs transition-opacity duration-200">
84
- {tooltipText}
85
- </div>
86
- )}
87
-
88
- {connected && (
89
- <div className="flex items-baseline gap-1">
90
- <DotGreenIcon />
91
- <div className="text-t_text_green">connected</div>
92
- </div>
93
- )}
94
- </div>
95
- </div>
96
- );
97
- };
@@ -1,103 +0,0 @@
1
- import { CloseIcon, SearchIcon } from "@src/assets/icons";
2
- import { useSwapContext } from "@src/context";
3
- import { useMemo, useState, useRef, useEffect } from "react";
4
- import { Virtuoso } from "react-virtuoso";
5
- import { SwapPanelType } from "../../../../SwapView";
6
- import { ChainItem } from "./ChainItem";
7
- import { TextInput } from "@src/components";
8
-
9
- type Props = {
10
- type: SwapPanelType;
11
- onClose: () => void;
12
- };
13
-
14
- export const ChainPicker = ({ type, onClose }: Props) => {
15
- const { setSrcChain, setDstChain, srcChainOptions, dstChainOptions } =
16
- useSwapContext();
17
-
18
- const [searchValue, setSearchValue] = useState("");
19
- const chainSearchRef = useRef<HTMLInputElement | null>(null);
20
-
21
- useEffect(() => {
22
- if (chainSearchRef.current) {
23
- setTimeout(() => {
24
- chainSearchRef.current?.focus();
25
- }, 10);
26
- }
27
- }, []);
28
-
29
- // search input filtering
30
- const filteredChains = useMemo(() => {
31
- const chains = type === "source" ? srcChainOptions : dstChainOptions;
32
- if (!searchValue) return chains;
33
-
34
- return chains.filter((chain) => {
35
- const searchLower = searchValue.toLowerCase();
36
- return (
37
- chain.displayName.toLowerCase().includes(searchLower) ||
38
- chain.chainId.toLowerCase().includes(searchLower)
39
- );
40
- });
41
- }, [type, srcChainOptions, dstChainOptions, searchValue]);
42
-
43
- const select = (selectedChainId: string) => {
44
- const chain = filteredChains.find(
45
- ({ chainId }) => chainId === selectedChainId,
46
- );
47
-
48
- if (!chain) {
49
- throw new Error(
50
- `ChainPicker > selected chain id that is absent in chain options list.`,
51
- );
52
- }
53
-
54
- type === "source" ? setSrcChain(chain) : setDstChain(chain);
55
- onClose();
56
- };
57
-
58
- return (
59
- <div className="flex flex-col h-full">
60
- <div className="flex justify-between">
61
- <div className="text-base/4 text-t_text_primary mb-4">{`Pick ${type} chain`}</div>
62
- <div
63
- className="w-4 h-4 fill-t_text_primary cursor-pointer"
64
- onClick={onClose}
65
- >
66
- <CloseIcon />
67
- </div>
68
- </div>
69
-
70
- <TextInput
71
- ref={chainSearchRef}
72
- inputIcon={
73
- <div className="fill-t_text_primary">
74
- <SearchIcon />
75
- </div>
76
- }
77
- placeholder="Search chain name"
78
- value={searchValue}
79
- handleChange={setSearchValue}
80
- />
81
-
82
- <div className="horizontal-separator mt-4" />
83
- <div className="h-full pt-4">
84
- {filteredChains.length ? (
85
- <Virtuoso
86
- style={{ height: "100%" }}
87
- data={filteredChains}
88
- itemContent={(_, chain) => (
89
- <ChainItem
90
- chain={chain}
91
- type={type}
92
- disabled={chain.disabled}
93
- onClick={select}
94
- />
95
- )}
96
- />
97
- ) : (
98
- <div className="flex justify-center mt-4">No chain found.</div>
99
- )}
100
- </div>
101
- </div>
102
- );
103
- };
@@ -1,65 +0,0 @@
1
- import { ArrowDownIcon } from "@src/assets/icons";
2
- import { Modal } from "@src/components/Modal";
3
- import { useSwapContext } from "@src/context";
4
- import { Chain } from "@src/models";
5
- import { useMemo, useState } from "react";
6
- import { SwapPanelType } from "../../../SwapView";
7
- import { ChainPicker } from "./ChainPicker";
8
-
9
- type Props = {
10
- chain: Chain | undefined;
11
- type: SwapPanelType;
12
- className?: string;
13
- };
14
-
15
- export const ChainPanel = ({ chain, type, className }: Props) => {
16
- const { srcChainLocked, dstChainLocked } = useSwapContext();
17
-
18
- const projectLockedDestinationChain = useMemo(
19
- () => type === "destination" && dstChainLocked,
20
- [type, dstChainLocked],
21
- );
22
-
23
- const projectLockedSourceChain = useMemo(
24
- () => type === "source" && srcChainLocked,
25
- [type, srcChainLocked],
26
- );
27
-
28
- const [chainPickerModalOpen, setChainPickerModalOpen] = useState(false);
29
-
30
- return (
31
- <>
32
- {chainPickerModalOpen && (
33
- <Modal onClose={() => setChainPickerModalOpen(false)}>
34
- <ChainPicker
35
- type={type}
36
- onClose={() => setChainPickerModalOpen(false)}
37
- />
38
- </Modal>
39
- )}
40
-
41
- <button
42
- type="button"
43
- disabled={projectLockedDestinationChain || projectLockedSourceChain}
44
- onClick={() => setChainPickerModalOpen(true)}
45
- className={`${className || ""}`}
46
- >
47
- <div className="flex justify-between items-center p-4 gap-8">
48
- <div className="flex flex-col font-medium items-start">
49
- <p className="text-xs opacity-60">
50
- {type === "source" ? "From:" : "To:"}
51
- </p>
52
- <p className={`${chain ? "" : "opacity-60"}`}>
53
- {chain ? chain.displayName : "Select"}
54
- </p>
55
- </div>
56
- {!projectLockedDestinationChain && !projectLockedSourceChain && (
57
- <div className="w-4 h-2 fill-t_text_primary">
58
- <ArrowDownIcon />
59
- </div>
60
- )}
61
- </div>
62
- </button>
63
- </>
64
- );
65
- };
@@ -1,43 +0,0 @@
1
- import { useSwapContext } from "@src/context";
2
- import { weiToHumanReadable } from "@src/utils";
3
- import { SwapPanelType } from "../../index";
4
-
5
- type Props = {
6
- type: SwapPanelType;
7
- };
8
- export const MaxPanel = ({ type }: Props) => {
9
- const { srcToken, srcTokenBalanceWei, srcTokenBalanceInfo, setSrcValue } =
10
- useSwapContext();
11
-
12
- return (
13
- <button
14
- type="button"
15
- className={`flex items-center w-16 justify-center p-4 gap-8 ${
16
- !srcTokenBalanceInfo && "opacity-60"
17
- } ${
18
- type === "source" &&
19
- "border-l border-solid border-t_text_primary border-opacity-10"
20
- }`}
21
- disabled={!srcTokenBalanceInfo}
22
- onClick={() =>
23
- setSrcValue(
24
- weiToHumanReadable({
25
- amount: srcTokenBalanceWei,
26
- decimals: srcToken?.decimals || 18,
27
- precisionFractionalPlaces: srcToken?.decimals || 18,
28
- }),
29
- )
30
- }
31
- >
32
- {type === "source" && (
33
- <p
34
- className={`border-b border-solid border-t_text_primary ${
35
- !srcTokenBalanceInfo && "border-opacity-60"
36
- }`}
37
- >
38
- Max
39
- </p>
40
- )}
41
- </button>
42
- );
43
- };
@@ -1,37 +0,0 @@
1
- import { TokenLogo } from "@src/components";
2
- import { TokenOption } from "@src/models";
3
-
4
- type Props = {
5
- token: TokenOption;
6
- selectedTokenAddress: string | undefined;
7
- onClick: () => void;
8
- };
9
- export const QuickPickTokenItem = ({
10
- token,
11
- selectedTokenAddress,
12
- onClick,
13
- }: Props) => {
14
- return (
15
- <button
16
- type="button"
17
- className={`flex gap-2 py-2 pr-[14px] pl-2 items-center border border-solid border-t_text_primary border-opacity-10 rounded-3xl text-start hover:bg-t_bg_tertiary hover:bg-opacity-10 ${
18
- token.address.toLowerCase() === selectedTokenAddress?.toLowerCase()
19
- ? "bg-t_bg_tertiary bg-opacity-10"
20
- : "bg-t_bg_primary"
21
- }`}
22
- onClick={onClick}
23
- >
24
- <TokenLogo
25
- token={token}
26
- className="w-6 h-6"
27
- generatedLogoClassName="w-6 h-6"
28
- />
29
- <div className="flex flex-col gap-1 text-xs font-medium !leading-3">
30
- <div className="text-t_text_primary">{token.name}</div>
31
- <div className="text-t_text_primary text-opacity-50">
32
- {token.symbol}
33
- </div>
34
- </div>
35
- </button>
36
- );
37
- };