@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
@@ -1,19 +1,19 @@
1
1
  import { ArrowDownIcon } from "@src/assets/icons";
2
+ import { Modal } from "@src/components/Modal";
2
3
  import { useSwapContext } from "@src/context";
3
- import { useModal } from "@src/context/ModalProvider";
4
- import { Chain } from "@src/models";
5
- import { useCallback, useEffect } from "react";
4
+ import { Chain, Token } from "@src/models";
5
+ import { useCallback, useEffect, useMemo, useState } from "react";
6
6
  import { useAccount } from "wagmi";
7
7
  import { SwapPanelType } from "../../../SwapView";
8
8
  import { ChainPicker } from "./ChainPicker";
9
- import { useMemo } from "react";
10
9
 
11
10
  type Props = {
12
11
  chain: Chain | undefined;
13
12
  type: SwapPanelType;
13
+ className?: string;
14
14
  };
15
15
 
16
- export const ChainPanel = ({ chain, type }: Props) => {
16
+ export const ChainPanel = ({ chain, type, className }: Props) => {
17
17
  const {
18
18
  supportedChains,
19
19
  srcChain,
@@ -23,20 +23,28 @@ export const ChainPanel = ({ chain, type }: Props) => {
23
23
  setSrcToken,
24
24
  dstToken,
25
25
  setDstToken,
26
- srcChainProvided,
27
- dstChainProvided,
26
+ srcChainLocked,
27
+ dstChainLocked,
28
+ integrationConfig,
29
+ bridgeUI,
30
+ bridgeTokensDictionary,
28
31
  } = useSwapContext();
29
32
 
30
33
  const { chainId } = useAccount();
31
34
 
32
- const projectSelectedDestinationChain = useMemo(
33
- () => type === "destination" && dstChainProvided,
34
- [type, dstChainProvided],
35
+ const projectLockedDestinationChain = useMemo(
36
+ () => type === "destination" && dstChainLocked,
37
+ [type, dstChainLocked],
38
+ );
39
+
40
+ const projectLockedSourceChain = useMemo(
41
+ () => type === "source" && srcChainLocked,
42
+ [type, srcChainLocked],
35
43
  );
36
44
 
37
45
  // select chain from user wallet
38
46
  useEffect(() => {
39
- if (!chainId || srcChainProvided) return;
47
+ if (!chainId || integrationConfig.srcChainId) return;
40
48
 
41
49
  const userChainFromWallet = supportedChains.find(
42
50
  (chain) => chain.chainId === String(chainId),
@@ -51,17 +59,61 @@ export const ChainPanel = ({ chain, type }: Props) => {
51
59
  // eslint-disable-next-line react-hooks/exhaustive-deps
52
60
  }, [chainId]);
53
61
 
54
- const { openModal } = useModal();
62
+ const [chainPickerModalOpen, setChainPickerModalOpen] = useState(false);
55
63
 
56
64
  const handleSrcChainChange = useCallback(
57
65
  (chain: Chain) => {
58
- const newSrcToken =
59
- chain.tokens.find((token) => token.symbol === srcToken?.symbol) ||
60
- chain.tokens.find((token) => token.symbol === chain.tokenSymbol);
66
+ let newSrcToken: Token | undefined = undefined;
67
+
68
+ if (bridgeUI) {
69
+ const bridgeableTokensAddresses = Object.keys(
70
+ bridgeTokensDictionary?.[chain.chainId] || {},
71
+ ).map((address) => address.toLowerCase());
72
+
73
+ // Attempt to use the same token on a new chain matching by symbol.
74
+ newSrcToken = chain.tokens.find(
75
+ (token) =>
76
+ token.symbol === srcToken?.symbol &&
77
+ bridgeableTokensAddresses.includes(token.address.toLowerCase()),
78
+ );
79
+
80
+ if (!newSrcToken) {
81
+ // The token from the previous chain is not bridgeable on the new chain.
82
+ // We will use the first available bridgeable token on the new chain.
83
+
84
+ const firstAvailableBridgeableTokenAddress =
85
+ bridgeableTokensAddresses[0];
86
+
87
+ if (!firstAvailableBridgeableTokenAddress) {
88
+ throw new Error(
89
+ `Couldn't find any available bridgeable token on the chain ${chain.chainId}, but bridging is available`,
90
+ );
91
+ }
92
+
93
+ newSrcToken = chain.tokens.find(
94
+ (token) =>
95
+ token.address.toLowerCase() ===
96
+ firstAvailableBridgeableTokenAddress.toLowerCase(),
97
+ );
98
+
99
+ if (!newSrcToken) {
100
+ throw new Error(
101
+ `Found bridgeable token (${firstAvailableBridgeableTokenAddress}) on the chain ${chain.chainId}, but token was not defined in chains collection`,
102
+ );
103
+ }
104
+ }
105
+ } else {
106
+ newSrcToken =
107
+ // Attempt to use the same token on a new chain.
108
+ chain.tokens.find((token) => token.symbol === srcToken?.symbol) ||
109
+ // Otherwise, use the default token on this chain.
110
+ chain.tokens.find((token) => token.symbol === chain.tokenSymbol);
111
+ }
112
+
61
113
  setSrcChain(chain);
62
114
  setSrcToken(newSrcToken);
63
115
  },
64
- [setSrcChain, setSrcToken, srcToken],
116
+ [setSrcChain, setSrcToken, srcToken, bridgeTokensDictionary, bridgeUI],
65
117
  );
66
118
 
67
119
  const handleDstChainChange = useCallback(
@@ -77,19 +129,22 @@ export const ChainPanel = ({ chain, type }: Props) => {
77
129
 
78
130
  return (
79
131
  <>
132
+ {chainPickerModalOpen && (
133
+ <Modal onClose={() => setChainPickerModalOpen(false)}>
134
+ <ChainPicker
135
+ type={type}
136
+ setSrcChain={handleSrcChainChange}
137
+ setDstChain={handleDstChainChange}
138
+ onClose={() => setChainPickerModalOpen(false)}
139
+ />
140
+ </Modal>
141
+ )}
142
+
80
143
  <button
81
144
  type="button"
82
- disabled={projectSelectedDestinationChain}
83
- onClick={() =>
84
- openModal(
85
- <ChainPicker
86
- type={type}
87
- supportedChains={supportedChains}
88
- setSrcChain={handleSrcChainChange}
89
- setDstChain={handleDstChainChange}
90
- />,
91
- )
92
- }
145
+ disabled={projectLockedDestinationChain || projectLockedSourceChain}
146
+ onClick={() => setChainPickerModalOpen(true)}
147
+ className={`${className || ""}`}
93
148
  >
94
149
  <div className="flex justify-between items-center p-4 gap-8">
95
150
  <div className="flex flex-col font-medium items-start">
@@ -100,7 +155,7 @@ export const ChainPanel = ({ chain, type }: Props) => {
100
155
  {chain ? chain.displayName : "Select"}
101
156
  </p>
102
157
  </div>
103
- {!projectSelectedDestinationChain && (
158
+ {!projectLockedDestinationChain && !projectLockedSourceChain && (
104
159
  <div className="w-4 h-2 fill-t_text_primary">
105
160
  <ArrowDownIcon />
106
161
  </div>
@@ -57,11 +57,15 @@ export const TokenItem = ({ token, selectedTokenAddress, onClick }: Props) => {
57
57
  })
58
58
  : "<0.0001"}
59
59
  </div>
60
- ) : address ? (
61
- <div>
62
- <Skeleton className="w-[48px] h-[12px]" />
63
- </div>
64
- ) : null}
60
+ ) : (
61
+ <>
62
+ {address ? (
63
+ <div>
64
+ <Skeleton className="w-[48px] h-[12px]" />
65
+ </div>
66
+ ) : null}
67
+ </>
68
+ )}
65
69
  </div>
66
70
  </div>
67
71
  );
@@ -10,7 +10,6 @@ import {
10
10
  } from "@src/components";
11
11
  import { SwapPanelType } from "@src/components/Swap/SwapView";
12
12
  import { useSwapContext } from "@src/context";
13
- import { useModal } from "@src/context/ModalProvider";
14
13
  import { ERC20Abi } from "@src/contracts";
15
14
  import { useEvmContractApi } from "@src/hooks";
16
15
  import { Chain, Ecosystem, ImportedTokenData, TokenOption } from "@src/models";
@@ -50,9 +49,9 @@ export const TokenPicker = ({
50
49
  const currentRouteRequestNonce = useRef<number>(0);
51
50
  const tokenSearchRef = useRef<HTMLInputElement | null>(null);
52
51
 
53
- const { supportedChains, findTokenDataByAddressAndChain } = useSwapContext();
52
+ const { bridgeUI, supportedChains, findTokenDataByAddressAndChain } =
53
+ useSwapContext();
54
54
  const evmContractApi = useEvmContractApi();
55
- const { closeModal } = useModal();
56
55
 
57
56
  useEffect(() => {
58
57
  setShowImportWarning(false);
@@ -133,6 +132,7 @@ export const TokenPicker = ({
133
132
 
134
133
  useEffect(() => {
135
134
  if (
135
+ !bridgeUI &&
136
136
  isETHAddressValid(searchValue) &&
137
137
  !findTokenDataByAddressAndChain(searchValue.toLowerCase(), chain.chainId)
138
138
  ) {
@@ -141,7 +141,13 @@ export const TokenPicker = ({
141
141
  setLoadingCustomTokenData(false);
142
142
  setCustomTokenData(null);
143
143
  }
144
- }, [searchValue, getCustomTokenData, findTokenDataByAddressAndChain, chain]);
144
+ }, [
145
+ bridgeUI,
146
+ searchValue,
147
+ getCustomTokenData,
148
+ findTokenDataByAddressAndChain,
149
+ chain,
150
+ ]);
145
151
 
146
152
  useEffect(() => {
147
153
  setSearchValue("");
@@ -217,7 +223,7 @@ export const TokenPicker = ({
217
223
  <div className="text-base/4 mb-4">Import token</div>
218
224
  <div
219
225
  className="w-4 h-4 fill-t_text_primary cursor-pointer"
220
- onClick={closeModal}
226
+ onClick={() => setModalOpen(false)}
221
227
  >
222
228
  <CloseIcon />
223
229
  </div>
@@ -301,7 +307,7 @@ export const TokenPicker = ({
301
307
  <div className="text-base/4 text-t_text_primary mb-4">{`Pick ${type} token`}</div>
302
308
  <div
303
309
  className="w-4 h-4 fill-t_text_primary cursor-pointer"
304
- onClick={closeModal}
310
+ onClick={() => setModalOpen(false)}
305
311
  >
306
312
  <CloseIcon />
307
313
  </div>
@@ -1,7 +1,6 @@
1
1
  import { ArrowDownIcon } from "@src/assets/icons";
2
- import { TokenLogo } from "@src/components";
2
+ import { Modal, TokenLogo } from "@src/components";
3
3
  import { useSwapContext } from "@src/context";
4
- import { useModal } from "@src/context/ModalProvider";
5
4
  import { Chain, Token, TokenOption } from "@src/models";
6
5
  import { useMemo, useState } from "react";
7
6
  import { SwapPanelType } from "../../index";
@@ -11,12 +10,12 @@ type Props = {
11
10
  chain: Chain | undefined;
12
11
  token: Token | undefined;
13
12
  type: SwapPanelType;
13
+ className?: string;
14
14
  };
15
15
 
16
- export const TokenPanel = ({ chain, token, type }: Props) => {
17
- const [open, setOpen] = useState(false);
18
-
16
+ export const TokenPanel = ({ chain, token, type, className }: Props) => {
19
17
  const {
18
+ bridgeUI,
20
19
  srcChainTokensOptions,
21
20
  srcChainOtherTokensOptions,
22
21
  dstChainTokensOptions,
@@ -26,21 +25,32 @@ export const TokenPanel = ({ chain, token, type }: Props) => {
26
25
  supportedChains,
27
26
  setDstToken,
28
27
  setDstChain,
29
- dstTokenProvided,
28
+ dstTokenLocked,
29
+ srcTokenLocked,
30
30
  } = useSwapContext();
31
31
 
32
- const projectSelectedDestinationToken = useMemo(
33
- () => type === "destination" && dstTokenProvided,
34
- [type, dstTokenProvided],
32
+ const integratorLockedDestinationToken = useMemo(
33
+ () => type === "destination" && dstTokenLocked,
34
+ [type, dstTokenLocked],
35
+ );
36
+
37
+ const integratorLockedSourceToken = useMemo(
38
+ () => type === "source" && srcTokenLocked,
39
+ [type, srcTokenLocked],
35
40
  );
36
41
 
37
- const { openModal, closeModal } = useModal();
42
+ const [tokenPickerModalOpen, setTokenPickerModalOpen] = useState(false);
38
43
 
39
44
  const tokensWithBalances = useMemo(
40
45
  () => (type === "source" ? srcChainTokensOptions : dstChainTokensOptions),
41
46
  [dstChainTokensOptions, srcChainTokensOptions, type],
42
47
  );
43
48
 
49
+ const pickerDisabled = useMemo(
50
+ () => type === "destination" && bridgeUI,
51
+ [bridgeUI, type],
52
+ );
53
+
44
54
  const otherTokensWithBalances = useMemo(
45
55
  () =>
46
56
  type === "source"
@@ -61,28 +71,37 @@ export const TokenPanel = ({ chain, token, type }: Props) => {
61
71
  setDstToken(token);
62
72
  setDstChain(newChain);
63
73
  }
64
- closeModal();
74
+ setTokenPickerModalOpen(false);
65
75
  };
66
76
 
67
77
  return (
68
78
  <>
79
+ {tokenPickerModalOpen && (
80
+ <Modal onClose={() => setTokenPickerModalOpen(false)}>
81
+ <TokenPicker
82
+ type={type}
83
+ chain={chain!}
84
+ tokens={tokensWithBalances}
85
+ otherTokens={otherTokensWithBalances}
86
+ selectedTokenAddress={token?.address}
87
+ onSelect={onTokenSelect}
88
+ isOpen={tokenPickerModalOpen}
89
+ setModalOpen={setTokenPickerModalOpen}
90
+ />
91
+ </Modal>
92
+ )}
93
+
69
94
  <button
70
95
  type="button"
71
- disabled={projectSelectedDestinationToken}
96
+ disabled={
97
+ pickerDisabled ||
98
+ integratorLockedDestinationToken ||
99
+ integratorLockedSourceToken
100
+ }
72
101
  onClick={() => {
73
- openModal(
74
- <TokenPicker
75
- type={type}
76
- chain={chain!}
77
- tokens={tokensWithBalances}
78
- otherTokens={otherTokensWithBalances}
79
- selectedTokenAddress={token?.address}
80
- onSelect={onTokenSelect}
81
- isOpen={open}
82
- setModalOpen={setOpen}
83
- />,
84
- );
102
+ setTokenPickerModalOpen(true);
85
103
  }}
104
+ className={`${className || ""}`}
86
105
  >
87
106
  <div className="flex justify-between items-center p-4 gap-8 border-r border-solid border-t_text_primary border-opacity-10">
88
107
  <div className="flex gap-2 items-center">
@@ -98,11 +117,13 @@ export const TokenPanel = ({ chain, token, type }: Props) => {
98
117
  </p>
99
118
  </div>
100
119
  </div>
101
- {!projectSelectedDestinationToken && (
102
- <div className="w-4 h-2 fill-t_text_primary">
103
- <ArrowDownIcon />
104
- </div>
105
- )}
120
+ {!pickerDisabled &&
121
+ !integratorLockedDestinationToken &&
122
+ !integratorLockedSourceToken && (
123
+ <div className="w-4 h-2 fill-t_text_primary">
124
+ <ArrowDownIcon />
125
+ </div>
126
+ )}
106
127
  </div>
107
128
  </button>
108
129
  </>
@@ -24,9 +24,14 @@ export const SwapPanel = ({ type }: Props) => {
24
24
 
25
25
  return (
26
26
  <div className="flex flex-col x-border rounded-xl bg-t_bg_tertiary bg-opacity-5">
27
- <div className="grid grid-cols-2 border-b border-solid border-t_text_primary border-opacity-10">
28
- <TokenPanel chain={chain} token={token} type={type} />
29
- <ChainPanel chain={chain} type={type} />
27
+ <div className="flex border-b border-solid border-t_text_primary border-opacity-10">
28
+ <TokenPanel
29
+ chain={chain}
30
+ token={token}
31
+ type={type}
32
+ className="w-full flex-grow"
33
+ />
34
+ <ChainPanel chain={chain} type={type} className="w-full max-w-[36%]" />
30
35
  </div>
31
36
  <div
32
37
  className={`flex justify-between ${
@@ -1,5 +1,4 @@
1
1
  import { CloseIcon, WalletConnectIcon } from "@src/assets/icons";
2
- import { useModal } from "@src/context/ModalProvider";
3
2
  import { FC, useCallback, useMemo } from "react";
4
3
  import { Connector, useConnect } from "wagmi";
5
4
 
@@ -27,8 +26,10 @@ const ConnectorIcon: FC<{ connector: Connector; className?: string }> = ({
27
26
  }
28
27
  };
29
28
 
30
- export const WalletPicker: FC<{ className?: string }> = ({ className }) => {
31
- const { closeModal } = useModal();
29
+ export const WalletPicker: FC<{ className?: string; onClose: () => void }> = ({
30
+ className,
31
+ onClose,
32
+ }) => {
32
33
  const { connectors, connectAsync } = useConnect();
33
34
 
34
35
  const allowedConnectors = useMemo(() => {
@@ -44,9 +45,9 @@ export const WalletPicker: FC<{ className?: string }> = ({ className }) => {
44
45
  const handleWalletClick = useCallback(
45
46
  async (connector: Connector) => {
46
47
  await connectAsync({ connector });
47
- closeModal();
48
+ onClose();
48
49
  },
49
- [connectAsync, closeModal],
50
+ [connectAsync, onClose],
50
51
  );
51
52
 
52
53
  return (
@@ -55,7 +56,7 @@ export const WalletPicker: FC<{ className?: string }> = ({ className }) => {
55
56
  <div className="text-base/4 mb-4 text-t_text_primary">Pick wallet</div>
56
57
  <div
57
58
  className="w-4 h-4 fill-t_text_primary cursor-pointer"
58
- onClick={closeModal}
59
+ onClick={onClose}
59
60
  >
60
61
  <CloseIcon />
61
62
  </div>
@@ -1,16 +1,16 @@
1
+ import { ReorderButton } from "../ReorderButton/ReorderButton";
1
2
  import { FeesPanel } from "./FeesPanel";
2
3
  import { SwapButton } from "./SwapButton";
3
4
  import { SwapPanel } from "./SwapPanel";
4
- import { ArrowIcon } from "@src/components/Swap/SwapView/ConfirmationView/TxOverview/ArrowIcon";
5
5
 
6
6
  export type SwapPanelType = "source" | "destination";
7
7
 
8
8
  export const SwapView = () => {
9
9
  return (
10
10
  <div className="flex flex-col gap-2 fill-t_text_primary">
11
- <div className="relative flex flex-col gap-5">
11
+ <div className="flex flex-col gap-5">
12
12
  <SwapPanel type="source" />
13
- <ArrowIcon />
13
+ <ReorderButton />
14
14
  <SwapPanel type="destination" />
15
15
  </div>
16
16
  <FeesPanel />
@@ -25,7 +25,7 @@ export const Swap = ({ onClose }: Props) => {
25
25
 
26
26
  return (
27
27
  <div
28
- className={`flex flex-col gap-5 p-4 mx-auto text-t_text_primary bg-t_bg_primary rounded-3xl`}
28
+ className={`relative flex flex-col gap-5 p-4 text-t_text_primary bg-t_bg_primary rounded-3xl flex-1`}
29
29
  >
30
30
  <Header onClose={onClose} />
31
31
  {view}
@@ -5,14 +5,14 @@ import {
5
5
  SwapProvider,
6
6
  TransactionProvider,
7
7
  TxUIWrapper,
8
+ useHistory,
8
9
  } from "@src/context";
9
- import { ModalProvider } from "@src/context/ModalProvider";
10
10
  import { Chain, ModalIntegrationPayload, Route } from "@src/models";
11
11
  import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
12
12
  import { FC, MouseEvent, useEffect, useMemo } from "react";
13
+ import { ErrorBoundary } from "react-error-boundary";
13
14
  import { useReconnect, WagmiProvider } from "wagmi";
14
15
  import { changeHostVariableColor } from "../../../localTheme";
15
- import { ErrorBoundary } from "react-error-boundary";
16
16
 
17
17
  export type TxConfigFormPayload = Omit<
18
18
  ModalIntegrationPayload,
@@ -24,7 +24,6 @@ export type TxConfigFormPayload = Omit<
24
24
  srcTokenAddr?: string;
25
25
  dstDisplayTokenAddr?: string;
26
26
  supportedChains: Chain[];
27
- defaultWalletPicker?: boolean;
28
27
  };
29
28
 
30
29
  const queryClient = new QueryClient();
@@ -45,6 +44,27 @@ const WagmiReload: FC = () => {
45
44
  return <></>;
46
45
  };
47
46
 
47
+ const PendingTransactionsEmitter: FC<{
48
+ onPendingTransactionsChange: ModalIntegrationPayload["onPendingTransactionsChange"];
49
+ }> = ({ onPendingTransactionsChange }) => {
50
+ const { history } = useHistory();
51
+
52
+ const pendingTransactions = useMemo(
53
+ () => history.filter((entry) => entry.status === "IN_PROGRESS"),
54
+ [history],
55
+ );
56
+
57
+ useEffect(() => {
58
+ if (onPendingTransactionsChange) {
59
+ onPendingTransactionsChange(pendingTransactions);
60
+ } else if (window.xPayOnPendingTransactionsChange) {
61
+ window.xPayOnPendingTransactionsChange(pendingTransactions);
62
+ }
63
+ }, [onPendingTransactionsChange, pendingTransactions]);
64
+
65
+ return <></>;
66
+ };
67
+
48
68
  export const TxConfigForm = ({
49
69
  integratorId,
50
70
  dstChainId,
@@ -61,6 +81,16 @@ export const TxConfigForm = ({
61
81
  lightTheme,
62
82
  defaultWalletPicker,
63
83
  styles,
84
+ onPendingTransactionsChange,
85
+ dstTokenLocked,
86
+ dstChainLocked,
87
+ srcTokenLocked,
88
+ srcChainLocked,
89
+ onDstTokenChange,
90
+ onDstChainChange,
91
+ onSrcTokenChange,
92
+ onSrcChainChange,
93
+ bridge,
64
94
  }: TxConfigFormPayload &
65
95
  (
66
96
  | {
@@ -103,6 +133,9 @@ export const TxConfigForm = ({
103
133
  <QueryClientProvider client={queryClient}>
104
134
  <WagmiReload />
105
135
  <HistoryProvider>
136
+ <PendingTransactionsEmitter
137
+ onPendingTransactionsChange={onPendingTransactionsChange}
138
+ />
106
139
  <SwapProvider
107
140
  integrationConfig={{
108
141
  integratorId,
@@ -114,6 +147,15 @@ export const TxConfigForm = ({
114
147
  desc,
115
148
  dstDisplayTokenAddr,
116
149
  defaultWalletPicker,
150
+ dstTokenLocked,
151
+ dstChainLocked,
152
+ srcTokenLocked,
153
+ srcChainLocked,
154
+ onDstTokenChange,
155
+ onDstChainChange,
156
+ onSrcTokenChange,
157
+ onSrcChainChange,
158
+ bridge,
117
159
  }}
118
160
  supportedChains={supportedChains}
119
161
  wagmiConfig={wagmiConfig}
@@ -121,24 +163,22 @@ export const TxConfigForm = ({
121
163
  >
122
164
  <TransactionProvider>
123
165
  <TxUIWrapper>
124
- <ModalProvider>
125
- {overlay ? (
126
- <div
127
- className="top-0 left-0 right-0 bottom-0 bg-[rgba(0,0,0,0.8)] fixed flex items-center justify-center z-10"
128
- onMouseDown={onBackdropClick}
129
- >
130
- <div className="relative bg-t_bg_primary rounded-3xl overflow-auto text-t_text_primary border-2 border-solid border-[rgba(255,255,255,0.1)] min-w-x_modal max-w-x_modal min-h-[432px] w-full">
131
- <Swap onSubmit={onSubmit} onClose={onClose} />
132
- <PoweredBy />
133
- </div>
134
- </div>
135
- ) : (
136
- <div className="bg-t_bg_primary rounded-3xl overflow-auto text-t_text_primary border-2 border-solid border-[rgba(255,255,255,0.1)] min-h-[432px] w-full">
137
- <Swap onSubmit={() => {}} onClose={() => {}} />
166
+ {overlay ? (
167
+ <div
168
+ className="top-0 left-0 right-0 bottom-0 bg-[rgba(0,0,0,0.8)] fixed flex flex-col items-center justify-center z-10"
169
+ onMouseDown={onBackdropClick}
170
+ >
171
+ <div className="relative bg-t_bg_primary rounded-3xl overflow-auto text-t_text_primary border-2 border-solid border-[rgba(255,255,255,0.1)] min-w-x_modal max-w-x_modal min-h-[532px] w-full">
172
+ <Swap onSubmit={onSubmit} onClose={onClose} />
138
173
  <PoweredBy />
139
174
  </div>
140
- )}
141
- </ModalProvider>
175
+ </div>
176
+ ) : (
177
+ <div className="bg-t_bg_primary rounded-3xl overflow-auto text-t_text_primary border-2 border-solid border-[rgba(255,255,255,0.1)] min-h-[532px] w-full flex flex-col">
178
+ <Swap onSubmit={() => {}} onClose={() => {}} />
179
+ <PoweredBy />
180
+ </div>
181
+ )}
142
182
  </TxUIWrapper>
143
183
  </TransactionProvider>
144
184
  </SwapProvider>
@@ -162,6 +202,11 @@ export const openTxConfigForm = async ({
162
202
  lightTheme,
163
203
  defaultWalletPicker,
164
204
  styles,
205
+ onPendingTransactionsChange,
206
+ dstTokenLocked,
207
+ dstChainLocked,
208
+ srcTokenLocked,
209
+ srcChainLocked,
165
210
  }: TxConfigFormPayload): Promise<Route> => {
166
211
  try {
167
212
  if (xpayRoot === null) {
@@ -200,6 +245,11 @@ export const openTxConfigForm = async ({
200
245
  }}
201
246
  overlay={true}
202
247
  defaultWalletPicker={defaultWalletPicker}
248
+ onPendingTransactionsChange={onPendingTransactionsChange}
249
+ dstTokenLocked={dstTokenLocked}
250
+ dstChainLocked={dstChainLocked}
251
+ srcTokenLocked={srcTokenLocked}
252
+ srcChainLocked={srcChainLocked}
203
253
  />,
204
254
  );
205
255
  });