@xswap-link/sdk 0.6.10 → 0.8.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 (46) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/index.d.mts +124 -72
  3. package/dist/index.d.ts +124 -72
  4. package/dist/index.global.js +686 -281
  5. package/dist/index.js +10 -10
  6. package/dist/index.mjs +10 -10
  7. package/package.json +1 -1
  8. package/src/assets/icons/ArrowsExchange.tsx +18 -0
  9. package/src/assets/icons/index.ts +1 -0
  10. package/src/components/Modal/index.tsx +48 -41
  11. package/src/components/Swap/Header/index.tsx +4 -2
  12. package/src/components/Swap/HistoryView/index.tsx +2 -2
  13. package/src/components/Swap/ReorderButton/ReorderButton.tsx +37 -0
  14. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/ArrowIcon.tsx +1 -1
  15. package/src/components/Swap/SwapView/SwapButton/index.tsx +31 -22
  16. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +55 -22
  17. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/index.tsx +74 -10
  18. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/index.tsx +83 -28
  19. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +9 -5
  20. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +12 -6
  21. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +50 -29
  22. package/src/components/Swap/SwapView/SwapPanel/index.tsx +8 -3
  23. package/src/components/Swap/SwapView/WalletPicker/index.tsx +7 -6
  24. package/src/components/Swap/SwapView/index.tsx +3 -3
  25. package/src/components/Swap/index.tsx +1 -1
  26. package/src/components/TxConfigForm/index.tsx +69 -19
  27. package/src/components/TxModal/index.tsx +59 -0
  28. package/src/components/TxWidgetWC/index.tsx +47 -2
  29. package/src/components/TxWidgetWCWrapped/index.tsx +33 -1
  30. package/src/components/index.ts +1 -0
  31. package/src/config/index.ts +1 -1
  32. package/src/context/SwapProvider.tsx +177 -27
  33. package/src/context/TxUIWrapper.tsx +5 -5
  34. package/src/hooks/index.ts +0 -1
  35. package/src/models/BridgeTokensDictionary.ts +7 -0
  36. package/src/models/TokenData.ts +3 -1
  37. package/src/models/index.ts +6 -5
  38. package/src/models/payloads/ModalIntegrationPayload.ts +17 -3
  39. package/src/models/payloads/WidgetIntegrationPayload.ts +15 -1
  40. package/src/services/api.ts +6 -1
  41. package/src/services/integrations/transactions.ts +40 -17
  42. package/src/types/global.d.ts +15 -0
  43. package/src/utils/validation.ts +367 -0
  44. package/tsconfig.json +3 -2
  45. package/src/context/ModalProvider.tsx +0 -63
  46. package/src/hooks/usePortal.ts +0 -79
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xswap-link/sdk",
3
- "version": "0.6.10",
3
+ "version": "0.8.0",
4
4
  "description": "JavaScript SDK for XSwap platform",
5
5
  "homepage": "https://github.com/xswap-link/xswap-sdk",
6
6
  "repository": {
@@ -0,0 +1,18 @@
1
+ import { FC } from "react";
2
+
3
+ export const ArrowsExchange: FC = () => {
4
+ return (
5
+ <svg
6
+ width="14"
7
+ height="18"
8
+ viewBox="0 0 14 18"
9
+ fill="none"
10
+ xmlns="http://www.w3.org/2000/svg"
11
+ >
12
+ <path
13
+ d="M3.66665 9.83335V3.85419L1.52081 6.00002L0.333313 4.83335L4.49998 0.666687L8.66665 4.83335L7.47915 6.00002L5.33331 3.85419V9.83335H3.66665ZM9.49998 17.3334L5.33331 13.1667L6.52081 12L8.66665 14.1459V8.16669H10.3333V14.1459L12.4791 12L13.6666 13.1667L9.49998 17.3334Z"
14
+ fill="white"
15
+ />
16
+ </svg>
17
+ );
18
+ };
@@ -2,6 +2,7 @@ export * from "./ArrowDownIcon";
2
2
  export * from "./ArrowDownLongIcon";
3
3
  export * from "./ArrowLeftIcon";
4
4
  export * from "./ArrowRightIcon";
5
+ export * from "./ArrowsExchange";
5
6
  export * from "./ArrowUpIcon";
6
7
  export * from "./ArrowUpRightIcon";
7
8
  export * from "./CashbacklIcon";
@@ -1,52 +1,59 @@
1
- import { xpayShadowRoot } from "@src/config";
2
- import { MouseEvent, ReactElement } from "react";
3
- import { createPortal } from "react-dom";
1
+ import { useSwapContext } from "@src/context";
2
+ import { FC, ReactNode } from "react";
4
3
 
5
- export type ModalType = "neutral" | "waiting" | "warning" | "error" | "success";
6
- type Props = {
7
- id: string;
8
- children: ReactElement | ReactElement[];
9
- onCloseClick: () => void;
10
- type?: ModalType;
4
+ /**
5
+ * This component was created to meet the following requirements:
6
+ * - Modals needs to be inside the shadow root,
7
+ * - Modals needs to be inside all app's main contexts,
8
+ * - Modals' need to rerender on props change.
9
+ *
10
+ * Usage:
11
+ * ```
12
+ * const [open, setOpen] = useState(false);
13
+ *
14
+ * return (
15
+ * <>
16
+ * { open && <Modal onClose={() => setOpen(false)}>...</Modal>}
17
+ *
18
+ * <button onClick={() => setOpen(true)}>Open modal</button>
19
+ * </>
20
+ * );
21
+ * ```
22
+ */
23
+ export const Modal: FC<{
11
24
  className?: string;
12
- };
13
- export const Modal = ({
14
- id,
15
- children,
16
- onCloseClick,
17
- type = "waiting",
18
- className,
19
- }: Props) => {
20
- const onBackdropClick = (e: MouseEvent<HTMLDivElement>) => {
21
- e.stopPropagation();
22
- e.nativeEvent.stopImmediatePropagation();
23
- if (e.target === e.currentTarget) {
24
- onCloseClick();
25
- }
26
- };
25
+ children: ReactNode;
26
+ onClose: () => void;
27
+ }> = ({ className, children, onClose }) => {
28
+ const { overlay } = useSwapContext();
27
29
 
28
- return createPortal(
30
+ return (
29
31
  <div
30
- className="fixed box-border inset-0 z-20 flex items-center justify-center bg-black bg-opacity-80"
31
- onMouseDown={onBackdropClick}
32
+ className={`${
33
+ overlay ? "fixed bg-[rgba(0,0,0,0.8)]" : "absolute"
34
+ } top-0 left-0 right-0 bottom-0 flex items-center justify-center z-10 ${
35
+ className || ""
36
+ }`}
37
+ onMouseDown={(e) => {
38
+ e.stopPropagation();
39
+ e.nativeEvent.stopImmediatePropagation();
40
+ e.preventDefault();
41
+
42
+ if (e.target === e.currentTarget && overlay) {
43
+ onClose();
44
+ }
45
+ }}
32
46
  >
33
47
  <div
34
- className={`relative bg-t_bg_primary rounded-3xl p-4 w-full min-w-[340px] overflow-auto max-w-x_modal border-2 ${
35
- type === "error"
36
- ? "border-t_error_dark"
37
- : type === "success"
38
- ? "border-t_success_dark"
39
- : type === "warning"
40
- ? "border-t_warning_dark"
41
- : type === "waiting"
42
- ? "border-t_main_accent_dark"
43
- : "border-t_text_primary border-opacity-10"
44
- } ${className}`}
48
+ className="flex flex-col bg-t_bg_primary x-border rounded-3xl p-4 w-full min-w-[340px]"
49
+ style={{
50
+ height: overlay ? "600px" : "100%",
51
+ maxWidth: "480px",
52
+ maxHeight: "100%",
53
+ }}
45
54
  >
46
55
  {children}
47
56
  </div>
48
- </div>,
49
- xpayShadowRoot!,
50
- id,
57
+ </div>
51
58
  );
52
59
  };
@@ -5,11 +5,13 @@ type Props = {
5
5
  onClose: () => void;
6
6
  };
7
7
  export const Header = ({ onClose }: Props) => {
8
- const { tab } = useSwapContext();
8
+ const { tab, bridgeUI } = useSwapContext();
9
9
 
10
10
  return (
11
11
  <div className="flex justify-between">
12
- <div className="text-xl">{tab}</div>
12
+ <div className="text-xl">
13
+ {tab === "Swap" && bridgeUI ? "Bridge" : tab}
14
+ </div>
13
15
  <Controls onClose={onClose} />
14
16
  </div>
15
17
  );
@@ -22,7 +22,7 @@ export const HistoryView = () => {
22
22
  return (
23
23
  <Virtuoso
24
24
  data={history}
25
- style={{ height: "100%" }}
25
+ style={{ height: "532px" }}
26
26
  itemContent={(_, transaction) => {
27
27
  return <TxDataCard transaction={transaction} />;
28
28
  }}
@@ -30,5 +30,5 @@ export const HistoryView = () => {
30
30
  );
31
31
  }, [history, historyLoadedOnce]);
32
32
 
33
- return <div className="h-[40vh] overflow-hidden">{view}</div>;
33
+ return <div className="flex-1 overflow-hidden">{view}</div>;
34
34
  };
@@ -0,0 +1,37 @@
1
+ import { ArrowsExchange } from "@src/assets/icons";
2
+ import { useSwapContext } from "@src/context";
3
+ import { FC } from "react";
4
+
5
+ export const ReorderButton: FC = () => {
6
+ const {
7
+ dstChain,
8
+ dstToken,
9
+ srcChain,
10
+ srcToken,
11
+ setDstChain,
12
+ setDstToken,
13
+ setSrcChain,
14
+ setSrcToken,
15
+ } = useSwapContext();
16
+
17
+ const onReorderClick = () => {
18
+ setDstChain(srcChain);
19
+ setSrcChain(dstChain);
20
+ setDstToken(srcToken);
21
+ setSrcToken(dstToken);
22
+ };
23
+
24
+ return (
25
+ <button
26
+ onClick={onReorderClick}
27
+ aria-label="Switch target token with the source token"
28
+ className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-14 p-1 border border-solid border-t_text_primary border-opacity-10 rounded-xl bg-t_bg_secondary"
29
+ >
30
+ <div className="relative bg-gradient-to-r from-t_main_accent_light to-t_main_accent_dark w-8 h-8 rounded-lg">
31
+ <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 fill-white">
32
+ <ArrowsExchange />
33
+ </div>
34
+ </div>
35
+ </button>
36
+ );
37
+ };
@@ -2,7 +2,7 @@ import { ArrowDownLongIcon } from "@src/assets/icons";
2
2
 
3
3
  export const ArrowIcon = () => {
4
4
  return (
5
- <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 p-1 border border-solid border-t_text_primary border-opacity-10 rounded-xl bg-t_bg_secondary">
5
+ <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-14 p-1 border border-solid border-t_text_primary border-opacity-10 rounded-xl bg-t_bg_secondary">
6
6
  <div className="relative bg-gradient-to-r from-t_main_accent_light to-t_main_accent_dark w-8 h-8 rounded-xl">
7
7
  <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 fill-white">
8
8
  <ArrowDownLongIcon />
@@ -1,15 +1,15 @@
1
+ import { Modal } from "@src/components/Modal";
1
2
  import { useSwapContext, useTxUIWrapper } from "@src/context";
2
- import { useModal } from "@src/context/ModalProvider";
3
+ import { ADDRESSES } from "@src/contracts";
4
+ import { specialApprovalTokens } from "@src/contracts/specialApprovalTokens";
5
+ import useNetworks from "@src/hooks/networkManagement/useNetworks";
6
+ import { useERC20Token } from "@src/hooks/useERC20Token";
3
7
  import { TxStatus } from "@src/models";
4
8
  import { safeBigNumberFrom } from "@src/utils";
9
+ import { BigNumber } from "ethers";
5
10
  import { useCallback, useEffect, useMemo, useState } from "react";
6
11
  import { useAccount, useSwitchChain } from "wagmi";
7
12
  import { WalletPicker } from "../WalletPicker";
8
- import { BigNumber } from "ethers";
9
- import useNetworks from "@src/hooks/networkManagement/useNetworks";
10
- import { useERC20Token } from "@src/hooks/useERC20Token";
11
- import { ADDRESSES } from "@src/contracts";
12
- import { specialApprovalTokens } from "@src/contracts/specialApprovalTokens";
13
13
 
14
14
  type Button = {
15
15
  text: string;
@@ -20,10 +20,11 @@ type Button = {
20
20
  export const SwapButton = () => {
21
21
  const { address, chainId } = useAccount();
22
22
  const { switchChainAsync } = useSwitchChain();
23
- const { openModal } = useModal();
23
+ const [connectWalletModalOpen, setConnectWalletModalOpen] = useState(false);
24
24
  const { integrationConfig } = useSwapContext();
25
25
 
26
26
  const {
27
+ bridgeUI,
27
28
  error,
28
29
  srcChain,
29
30
  dstChain,
@@ -113,7 +114,7 @@ export const SwapButton = () => {
113
114
  ? "Connect wallet"
114
115
  : "Connect wallet first",
115
116
  fn: () => {
116
- openModal(<WalletPicker />);
117
+ setConnectWalletModalOpen(true);
117
118
  },
118
119
  disabled: !integrationConfig.defaultWalletPicker,
119
120
  };
@@ -199,13 +200,14 @@ export const SwapButton = () => {
199
200
  }
200
201
 
201
202
  return {
202
- text: "Swap",
203
+ text: bridgeUI ? "Bridge" : "Swap",
203
204
  fn: async () => {
204
205
  showSwapConfirmationView();
205
206
  },
206
207
  disabled: false,
207
208
  };
208
209
  }, [
210
+ bridgeUI,
209
211
  srcChainId,
210
212
  dstChainId,
211
213
  srcTokenAddress,
@@ -218,7 +220,6 @@ export const SwapButton = () => {
218
220
  isFetchingRoute,
219
221
  currentTokenAllowance,
220
222
  integrationConfig.defaultWalletPicker,
221
- openModal,
222
223
  switchChainAsync,
223
224
  enqueueTransaction,
224
225
  approve,
@@ -229,17 +230,25 @@ export const SwapButton = () => {
229
230
  ]);
230
231
 
231
232
  return (
232
- <button
233
- type="button"
234
- disabled={button.disabled}
235
- onClick={button.fn}
236
- className={`text-xl w-full py-5 cursor-pointer disabled:cursor-not-allowed rounded-2xl border-none ${
237
- button.disabled
238
- ? "bg-t_button_pr_off_bg text-t_button_pr_off_text"
239
- : "bg-gradient-to-r from-t_main_accent_light to-t_main_accent_dark text-t_button_pr_text"
240
- }`}
241
- >
242
- {button.text}
243
- </button>
233
+ <>
234
+ {connectWalletModalOpen && (
235
+ <Modal onClose={() => setConnectWalletModalOpen(false)}>
236
+ <WalletPicker onClose={() => setConnectWalletModalOpen(false)} />
237
+ </Modal>
238
+ )}
239
+
240
+ <button
241
+ type="button"
242
+ disabled={button.disabled}
243
+ onClick={button.fn}
244
+ className={`text-xl w-full py-5 cursor-pointer disabled:cursor-not-allowed rounded-2xl border-none ${
245
+ button.disabled
246
+ ? "bg-t_button_pr_off_bg text-t_button_pr_off_text"
247
+ : "bg-gradient-to-r from-t_main_accent_light to-t_main_accent_dark text-t_button_pr_text"
248
+ }`}
249
+ >
250
+ {button.text}
251
+ </button>
252
+ </>
244
253
  );
245
254
  };
@@ -1,74 +1,107 @@
1
1
  import { DotGreenIcon, HelpIcon } from "@src/assets/icons";
2
- import { Tooltip } from "@src/components";
2
+ import { SwapPanelType } from "@src/components/Swap/SwapView";
3
+ import { Tooltip } from "@src/components/Tooltip";
3
4
  import { useSwapContext } from "@src/context";
5
+ import useNetworks from "@src/hooks/networkManagement/useNetworks";
4
6
  import { Chain } from "@src/models";
5
7
  import { useMemo, useRef } from "react";
6
- import { SwapPanelType } from "../../../../../SwapView";
7
8
 
8
9
  type Props = {
9
10
  chain: Chain;
10
11
  type: SwapPanelType;
11
- disabledChain?: string;
12
+ disabledChains: string[];
12
13
  onClick: (chainId: string) => void;
13
14
  };
14
- export const ChainItem = ({ chain, type, disabledChain, onClick }: Props) => {
15
- // todo check useModal, we could improve this part to have the react state here, right now this line throws an error
16
- // const { address, chainId } = useAccount();
15
+
16
+ export const ChainItem = ({ chain, type, onClick, disabledChains }: Props) => {
17
+ const {
18
+ networks: { evm },
19
+ } = useNetworks();
17
20
 
18
21
  const tooltipTriggerRef = useRef<SVGSVGElement>(null);
19
22
 
20
- const { srcChain, dstChain } = useSwapContext();
23
+ const { srcChain, dstChain, bridgeUI } = useSwapContext();
24
+
21
25
  const currentChainId = useMemo(
22
26
  () => (type === "source" ? srcChain?.chainId : dstChain?.chainId),
23
27
  [dstChain, srcChain, type],
24
28
  );
25
29
 
26
- const connected = false; //address && chainId?.toString() === chain.chainId;
30
+ const connected = useMemo(
31
+ () => evm.signer && evm.chainId === chain.chainId,
32
+ [chain.chainId, evm.chainId, evm.signer],
33
+ );
34
+
35
+ const sameChainId = useMemo(() => {
36
+ if (!bridgeUI) {
37
+ return undefined;
38
+ }
39
+
40
+ return type === "destination" ? srcChain?.chainId : dstChain?.chainId;
41
+ }, [bridgeUI, dstChain?.chainId, srcChain?.chainId, type]);
42
+
43
+ const isInDisabledChains = disabledChains.includes(chain.chainId);
27
44
 
28
45
  return (
29
46
  <div
30
47
  onClick={() => {
31
- if (chain.chainId === disabledChain) {
48
+ if (chain.chainId === sameChainId || isInDisabledChains) {
32
49
  return;
33
50
  }
34
51
  onClick(chain.chainId);
35
52
  }}
36
- className={`flex justify-between gap-3 mt-2 mb-2 border border-solid border-transparent cursor-pointer p-4 hover:selected-chain-item ${
37
- currentChainId === chain.chainId
38
- ? "selected-chain-item"
39
- : "bg-t_bg_primary"
53
+ className={`flex justify-between items-center gap-3 mt-2 mb-2 cursor-pointer p-4 border border-solid border-white border-opacity-0 hover:selected-chain-item ${
54
+ currentChainId === chain.chainId ? "selected-chain-item" : ""
40
55
  } ${
41
- chain.chainId === disabledChain
56
+ chain.chainId === sameChainId || isInDisabledChains
42
57
  ? "disabled-chain-item cursor-default"
43
58
  : ""
44
59
  }`}
45
60
  >
46
61
  <div className="flex gap-3 items-center w-full">
47
62
  <img src={chain.image} alt={chain.name} className="w-[34px] h-[34px]" />
48
- <p className="text-t_text_primary">{chain.displayName}</p>
63
+ <p>{chain.displayName}</p>
49
64
  </div>
50
65
 
51
66
  {connected && (
52
- <div className="flex items-center gap-1">
67
+ <div className="flex items-baseline gap-1">
53
68
  <DotGreenIcon />
54
69
  <div className="text-t_text_green">connected</div>
55
70
  </div>
56
71
  )}
57
- {chain.chainId === disabledChain && (
72
+
73
+ {isInDisabledChains && chain.chainId !== sameChainId && (
58
74
  <div className="flex items-center gap-1">
59
75
  <Tooltip
60
- text="Transfers between same chain not available"
76
+ text={
77
+ bridgeUI
78
+ ? "Token is not available on this chain"
79
+ : `Transfers from ${
80
+ srcChain?.name || "the source chain"
81
+ } to this chain are currently not supported.`
82
+ }
61
83
  position="BOTTOM"
62
84
  triggerRef={tooltipTriggerRef}
63
- id="transfers-between-same-chains-tooltip"
85
+ id="transfers-from-chain-not-supported-tooltip"
64
86
  />
87
+ </div>
88
+ )}
65
89
 
66
- <HelpIcon
67
- ref={tooltipTriggerRef}
68
- className="cursor-help fill-t_main_accent_light w-[18px] h-[18px]"
90
+ {chain.chainId === sameChainId && (
91
+ <div className="flex items-center gap-1">
92
+ <Tooltip
93
+ text="Transfers between the same chain are not available"
94
+ id="transfers-between-same-chains-tooltip"
95
+ position="BOTTOM"
96
+ triggerRef={tooltipTriggerRef}
69
97
  />
70
98
  </div>
71
99
  )}
100
+
101
+ <HelpIcon
102
+ ref={tooltipTriggerRef}
103
+ className="cursor-help fill-t_main_accent_light w-[18px] h-[18px] min-w-[18px] min-h-[18px] max-w-[18px] max-h-[18px]"
104
+ />
72
105
  </div>
73
106
  );
74
107
  };
@@ -1,5 +1,5 @@
1
1
  import { CloseIcon } from "@src/assets/icons";
2
- import { useModal } from "@src/context/ModalProvider";
2
+ import { useSwapContext } from "@src/context";
3
3
  import { Chain, Web3Environment } from "@src/models";
4
4
  import { useMemo } from "react";
5
5
  import { Virtuoso } from "react-virtuoso";
@@ -8,24 +8,33 @@ import { ChainItem } from "./ChainItem";
8
8
 
9
9
  type Props = {
10
10
  type: SwapPanelType;
11
- supportedChains: Chain[];
12
11
  setSrcChain: (chain: Chain) => void;
13
12
  setDstChain: (chain: Chain) => void;
13
+ onClose: () => void;
14
14
  };
15
15
  export const ChainPicker = ({
16
16
  type,
17
- supportedChains,
18
17
  setSrcChain,
19
18
  setDstChain,
19
+ onClose,
20
20
  }: Props) => {
21
- const { closeModal } = useModal();
21
+ const {
22
+ srcChain,
23
+ srcToken,
24
+ dstChain,
25
+ dstToken,
26
+ bridgeUI,
27
+ bridgeTokensDictionary,
28
+ supportedChains,
29
+ } = useSwapContext();
22
30
 
23
31
  const filteredChains = useMemo(() => {
24
32
  return supportedChains.filter(
25
- ({ web3Environment, swapSupported }) =>
26
- web3Environment === Web3Environment.MAINNET && swapSupported,
33
+ ({ web3Environment, swapSupported, bridgeSupported }) =>
34
+ web3Environment === Web3Environment.MAINNET &&
35
+ ((bridgeUI && bridgeSupported) || (!bridgeUI && swapSupported)),
27
36
  );
28
- }, [supportedChains]);
37
+ }, [bridgeUI, supportedChains]);
29
38
 
30
39
  const select = (selectedChainId: string) => {
31
40
  const chain = supportedChains.find(
@@ -39,16 +48,66 @@ export const ChainPicker = ({
39
48
  }
40
49
 
41
50
  type === "source" ? setSrcChain(chain) : setDstChain(chain);
42
- closeModal();
51
+ onClose();
43
52
  };
44
53
 
54
+ const disabledChains = useMemo(() => {
55
+ if (!srcChain?.chainId || !srcToken?.address) {
56
+ return [];
57
+ }
58
+
59
+ if (!bridgeUI) {
60
+ const disabledForDestination =
61
+ supportedChains.find((chain) => chain.chainId === srcChain.chainId)
62
+ ?.disabledForDestination || [];
63
+
64
+ if (type === "destination") {
65
+ return filteredChains
66
+ ?.filter((chain) => disabledForDestination.includes(chain.chainId))
67
+ .map(({ chainId }) => chainId);
68
+ }
69
+
70
+ return [];
71
+ }
72
+
73
+ if (type === "destination") {
74
+ const availableChains =
75
+ bridgeTokensDictionary?.[srcChain.chainId]?.[srcToken.address];
76
+ const disabledChains = filteredChains
77
+ ?.filter((chain) => !availableChains?.[chain.chainId])
78
+ .map(({ chainId }) => chainId);
79
+ return disabledChains;
80
+ } else {
81
+ if (!dstChain || !dstToken) {
82
+ return [];
83
+ }
84
+
85
+ const availableChains =
86
+ bridgeTokensDictionary?.[dstChain.chainId]?.[dstToken.address];
87
+ const disabledChains = filteredChains
88
+ ?.filter((chain) => !availableChains?.[chain.chainId])
89
+ .map(({ chainId }) => chainId);
90
+ return disabledChains;
91
+ }
92
+ }, [
93
+ bridgeTokensDictionary,
94
+ bridgeUI,
95
+ filteredChains,
96
+ srcChain,
97
+ srcToken,
98
+ dstChain,
99
+ dstToken,
100
+ type,
101
+ supportedChains,
102
+ ]);
103
+
45
104
  return (
46
105
  <div className="flex flex-col h-full">
47
106
  <div className="flex justify-between">
48
107
  <div className="text-base/4 text-t_text_primary mb-4">{`Pick ${type} chain`}</div>
49
108
  <div
50
109
  className="w-4 h-4 fill-t_text_primary cursor-pointer"
51
- onClick={closeModal}
110
+ onClick={onClose}
52
111
  >
53
112
  <CloseIcon />
54
113
  </div>
@@ -60,7 +119,12 @@ export const ChainPicker = ({
60
119
  style={{ height: "100%" }}
61
120
  data={filteredChains}
62
121
  itemContent={(_, chain) => (
63
- <ChainItem chain={chain} type={type} onClick={select} />
122
+ <ChainItem
123
+ chain={chain}
124
+ type={type}
125
+ disabledChains={disabledChains}
126
+ onClick={select}
127
+ />
64
128
  )}
65
129
  />
66
130
  ) : (