@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
@@ -0,0 +1,59 @@
1
+ import { xpayShadowRoot } from "@src/config";
2
+ import { MouseEvent, ReactElement } from "react";
3
+ import { createPortal } from "react-dom";
4
+
5
+ export type TxModalType =
6
+ | "neutral"
7
+ | "waiting"
8
+ | "warning"
9
+ | "error"
10
+ | "success";
11
+
12
+ type Props = {
13
+ id: string;
14
+ children: ReactElement | ReactElement[];
15
+ onCloseClick: () => void;
16
+ type?: TxModalType;
17
+ className?: string;
18
+ };
19
+
20
+ export const TxModal = ({
21
+ id,
22
+ children,
23
+ onCloseClick,
24
+ type = "waiting",
25
+ className,
26
+ }: Props) => {
27
+ const onBackdropClick = (e: MouseEvent<HTMLDivElement>) => {
28
+ e.stopPropagation();
29
+ e.nativeEvent.stopImmediatePropagation();
30
+ if (e.target === e.currentTarget) {
31
+ onCloseClick();
32
+ }
33
+ };
34
+
35
+ return createPortal(
36
+ <div
37
+ className="fixed box-border inset-0 z-20 flex items-center justify-center bg-black bg-opacity-80"
38
+ onMouseDown={onBackdropClick}
39
+ >
40
+ <div
41
+ className={`relative bg-t_bg_primary rounded-3xl p-4 w-full min-w-[340px] overflow-auto max-w-x_modal border-2 ${
42
+ type === "error"
43
+ ? "border-t_error_dark"
44
+ : type === "success"
45
+ ? "border-t_success_dark"
46
+ : type === "warning"
47
+ ? "border-t_warning_dark"
48
+ : type === "waiting"
49
+ ? "border-t_main_accent_dark"
50
+ : "border-t_text_primary border-opacity-10"
51
+ } ${className}`}
52
+ >
53
+ {children}
54
+ </div>
55
+ </div>,
56
+ xpayShadowRoot!,
57
+ id,
58
+ );
59
+ };
@@ -5,12 +5,12 @@ import {
5
5
  WidgetIntegrationPayload,
6
6
  } from "@src/models";
7
7
  import { getChains } from "@src/services";
8
+ import { isServer } from "@src/utils";
8
9
  import { createWebComponent } from "@src/utils/webComponents";
9
10
  import { useEffect, useState } from "react";
10
11
  import { Spinner } from "../Spinner";
11
12
  import { TxConfigForm } from "../TxConfigForm";
12
13
  import CSS from "../global.css";
13
- import { isServer } from "@src/utils";
14
14
 
15
15
  const TxWidget = ({
16
16
  integratorId,
@@ -24,6 +24,16 @@ const TxWidget = ({
24
24
  lightTheme,
25
25
  defaultWalletPicker,
26
26
  styles,
27
+ onPendingTransactionsChange,
28
+ dstTokenLocked,
29
+ dstChainLocked,
30
+ srcTokenLocked,
31
+ srcChainLocked,
32
+ onDstTokenChange,
33
+ onDstChainChange,
34
+ onSrcTokenChange,
35
+ onSrcChainChange,
36
+ bridge,
27
37
  }: WidgetIntegrationPayload) => {
28
38
  const [loading, setLoading] = useState(true);
29
39
  const [supportedChains, setSupportedChains] = useState<Chain[]>([]);
@@ -57,7 +67,9 @@ const TxWidget = ({
57
67
  <style>{CSS}</style>
58
68
 
59
69
  {loading ? (
60
- <Spinner className="w-10 h-10" />
70
+ <div className="min-h-[532px] w-full flex items-center justify-center">
71
+ <Spinner className="w-10 h-10" />
72
+ </div>
61
73
  ) : (
62
74
  <TxConfigForm
63
75
  integratorId={integratorId}
@@ -73,6 +85,16 @@ const TxWidget = ({
73
85
  lightTheme={lightTheme}
74
86
  defaultWalletPicker={defaultWalletPicker}
75
87
  styles={parsedStyles}
88
+ onPendingTransactionsChange={onPendingTransactionsChange}
89
+ dstTokenLocked={dstTokenLocked}
90
+ dstChainLocked={dstChainLocked}
91
+ srcTokenLocked={srcTokenLocked}
92
+ srcChainLocked={srcChainLocked}
93
+ onDstTokenChange={onDstTokenChange}
94
+ onDstChainChange={onDstChainChange}
95
+ onSrcTokenChange={onSrcTokenChange}
96
+ onSrcChainChange={onSrcChainChange}
97
+ bridge={bridge}
76
98
  />
77
99
  )}
78
100
  </>
@@ -106,6 +128,16 @@ export const createTxWidgetWC = () => {
106
128
  lightTheme: "boolean",
107
129
  defaultWalletPicker: "boolean",
108
130
  styles: "json",
131
+ onPendingTransactionsChange: "function",
132
+ dstTokenLocked: "boolean",
133
+ dstChainLocked: "boolean",
134
+ srcTokenLocked: "boolean",
135
+ srcChainLocked: "boolean",
136
+ bridge: "boolean",
137
+ onDstTokenChange: "function",
138
+ onDstChainChange: "function",
139
+ onSrcTokenChange: "function",
140
+ onSrcChainChange: "function",
109
141
  },
110
142
  });
111
143
 
@@ -116,6 +148,8 @@ export const createTxWidgetWC = () => {
116
148
  return TxWidgetWC;
117
149
  };
118
150
 
151
+ // Most fields are required here to enforce adding them in TxWidgetWCWrapped.
152
+ // callbacks are optional, because it will not be passed in TxWidgetWCWrapped.
119
153
  export type TxWidgetWCAttributes = {
120
154
  "integrator-id": WidgetIntegrationPayload["integratorId"];
121
155
  "dst-chain": WidgetIntegrationPayload["dstChain"];
@@ -128,4 +162,15 @@ export type TxWidgetWCAttributes = {
128
162
  "light-theme": WidgetIntegrationPayload["lightTheme"];
129
163
  "default-wallet-picker": WidgetIntegrationPayload["defaultWalletPicker"];
130
164
  styles: string | undefined;
165
+ "on-pending-transactions-change"?:
166
+ | WidgetIntegrationPayload["onPendingTransactionsChange"];
167
+ "dst-token-locked": WidgetIntegrationPayload["dstTokenLocked"] | undefined;
168
+ "dst-chain-locked": WidgetIntegrationPayload["dstChainLocked"] | undefined;
169
+ "src-token-locked": WidgetIntegrationPayload["srcTokenLocked"] | undefined;
170
+ "src-chain-locked": WidgetIntegrationPayload["srcChainLocked"] | undefined;
171
+ "on-dst-token-change"?: WidgetIntegrationPayload["onDstTokenChange"];
172
+ "on-dst-chain-change"?: WidgetIntegrationPayload["onDstChainChange"];
173
+ "on-src-token-change"?: WidgetIntegrationPayload["onSrcTokenChange"];
174
+ "on-src-chain-change"?: WidgetIntegrationPayload["onSrcChainChange"];
175
+ bridge: WidgetIntegrationPayload["bridge"] | undefined;
131
176
  };
@@ -1,6 +1,7 @@
1
1
  import { WidgetIntegrationPayload } from "@src/models";
2
- import { createTxWidgetWC, TxWidgetWCAttributes } from "../TxWidgetWC";
3
2
  import { isServer } from "@tanstack/react-query";
3
+ import { useEffect } from "react";
4
+ import { createTxWidgetWC, TxWidgetWCAttributes } from "../TxWidgetWC";
4
5
 
5
6
  const TxWidgetWC = createTxWidgetWC();
6
7
 
@@ -35,7 +36,33 @@ export const TxWidgetWCWrapped = ({
35
36
  lightTheme,
36
37
  defaultWalletPicker,
37
38
  styles,
39
+ onPendingTransactionsChange,
40
+ dstTokenLocked,
41
+ dstChainLocked,
42
+ srcTokenLocked,
43
+ srcChainLocked,
44
+ onDstTokenChange,
45
+ onDstChainChange,
46
+ onSrcTokenChange,
47
+ onSrcChainChange,
48
+ bridge,
38
49
  }: WidgetIntegrationPayload) => {
50
+ useEffect(() => {
51
+ // We couldn't find a way to pass a function to the web component created by @r2wc/core.
52
+ // It is assigned to window to be accessed later from within the web component.
53
+ window.xPayOnPendingTransactionsChange = onPendingTransactionsChange;
54
+ window.xPayOnDstTokenChange = onDstTokenChange;
55
+ window.xPayOnDstChainChange = onDstChainChange;
56
+ window.xPayOnSrcTokenChange = onSrcTokenChange;
57
+ window.xPayOnSrcChainChange = onSrcChainChange;
58
+ }, [
59
+ onPendingTransactionsChange,
60
+ onDstTokenChange,
61
+ onDstChainChange,
62
+ onSrcTokenChange,
63
+ onSrcChainChange,
64
+ ]);
65
+
39
66
  return (
40
67
  <xpay-widget
41
68
  integrator-id={integratorId}
@@ -49,6 +76,11 @@ export const TxWidgetWCWrapped = ({
49
76
  light-theme={lightTheme}
50
77
  default-wallet-picker={defaultWalletPicker}
51
78
  styles={typeof styles === "string" ? styles : JSON.stringify(styles)}
79
+ dst-token-locked={dstTokenLocked}
80
+ dst-chain-locked={dstChainLocked}
81
+ src-token-locked={srcTokenLocked}
82
+ src-chain-locked={srcChainLocked}
83
+ bridge={bridge}
52
84
  ></xpay-widget>
53
85
  );
54
86
  };
@@ -17,6 +17,7 @@ export * from "./TokenLogo/WithChain";
17
17
  export * from "./Tooltip";
18
18
  export * from "./TxConfigForm";
19
19
  export * from "./TxDataCard";
20
+ export * from "./TxModal";
20
21
  export * from "./TxStatusButton";
21
22
  export * from "./TxWidgetWC";
22
23
  export * from "./TxWidgetWCWrapped";
@@ -1,2 +1,2 @@
1
- export * from "./wagmiConfig";
2
1
  export * from "./init";
2
+ export * from "./wagmiConfig";
@@ -8,6 +8,8 @@ import {
8
8
  } from "@src/constants";
9
9
  import { ADDRESSES } from "@src/contracts";
10
10
  import {
11
+ BridgeToken,
12
+ BridgeTokensDictionary,
11
13
  Chain,
12
14
  Route,
13
15
  Token,
@@ -16,7 +18,12 @@ import {
16
18
  Transaction,
17
19
  Web3Environment,
18
20
  } from "@src/models";
19
- import { getBalances, getPrices, getRoute } from "@src/services";
21
+ import {
22
+ getBalances,
23
+ getBridgeTokens,
24
+ getPrices,
25
+ getRoute,
26
+ } from "@src/services";
20
27
  import {
21
28
  deepMergeObjects,
22
29
  getBalanceOf,
@@ -25,6 +32,7 @@ import {
25
32
  safeBigNumberFrom,
26
33
  weiToHumanReadable,
27
34
  } from "@src/utils";
35
+ import { mapToValidPath } from "@src/utils/validation";
28
36
  import BigNumberJS from "bignumber.js";
29
37
  import { BigNumber, constants } from "ethers";
30
38
  import {
@@ -44,6 +52,7 @@ import { useHistory } from "./HistoryProvider";
44
52
 
45
53
  type Tab = "Swap" | "History" | "Settings";
46
54
  type SwapContext = {
55
+ bridgeUI: boolean;
47
56
  integrationConfig: Partial<TxConfigFormPayload>;
48
57
  wagmiConfig: Config;
49
58
  supportedChains: Chain[];
@@ -53,22 +62,22 @@ type SwapContext = {
53
62
  error: string;
54
63
  setError: Dispatch<SetStateAction<string>>;
55
64
  feeToken: Token | undefined;
56
- srcChainProvided: boolean;
57
65
  srcChain: Chain | undefined;
58
66
  setSrcChain: Dispatch<SetStateAction<Chain | undefined>>;
59
67
  srcChainTokensOptions: TokenOption[];
60
68
  srcChainOtherTokensOptions: TokenOption[];
61
69
  srcChainTokensPrices: TokenPrices;
62
70
  dstChainTokensPrices: TokenPrices;
63
- srcTokenProvided: boolean;
64
71
  srcToken: Token | undefined;
65
72
  setSrcToken: Dispatch<SetStateAction<Token | undefined>>;
66
- dstChainProvided: boolean;
67
73
  dstChain: Chain | undefined;
68
74
  setDstChain: Dispatch<SetStateAction<Chain | undefined>>;
69
75
  dstChainTokensOptions: TokenOption[];
70
76
  dstChainOtherTokensOptions: TokenOption[];
71
- dstTokenProvided: boolean;
77
+ dstTokenLocked: boolean;
78
+ dstChainLocked?: boolean;
79
+ srcTokenLocked?: boolean;
80
+ srcChainLocked?: boolean;
72
81
  dstToken: Token | undefined;
73
82
  setDstToken: Dispatch<SetStateAction<Token | undefined>>;
74
83
  srcValue: string;
@@ -102,6 +111,7 @@ type SwapContext = {
102
111
  tokenAddress: string,
103
112
  chainId: string,
104
113
  ) => Token | undefined;
114
+ bridgeTokensDictionary: BridgeTokensDictionary | null;
105
115
  };
106
116
 
107
117
  const functionNotImplemented = () => {
@@ -109,6 +119,7 @@ const functionNotImplemented = () => {
109
119
  };
110
120
 
111
121
  const init: SwapContext = {
122
+ bridgeUI: false,
112
123
  integrationConfig: {},
113
124
  wagmiConfig: {} as Config,
114
125
  supportedChains: [],
@@ -116,19 +127,19 @@ const init: SwapContext = {
116
127
  overlay: false,
117
128
  error: "",
118
129
  feeToken: undefined,
119
- srcChainProvided: false,
120
130
  srcChain: undefined,
121
131
  srcChainTokensOptions: [],
122
132
  srcChainOtherTokensOptions: [],
123
133
  srcChainTokensPrices: {},
124
134
  dstChainTokensPrices: {},
125
- dstChainProvided: false,
126
135
  dstChain: undefined,
127
136
  dstChainTokensOptions: [],
128
137
  dstChainOtherTokensOptions: [],
129
- srcTokenProvided: false,
130
138
  srcToken: undefined,
131
- dstTokenProvided: false,
139
+ dstTokenLocked: false,
140
+ dstChainLocked: false,
141
+ srcTokenLocked: false,
142
+ srcChainLocked: false,
132
143
  dstToken: undefined,
133
144
  srcValue: "",
134
145
  srcValueWei: "",
@@ -164,6 +175,7 @@ const init: SwapContext = {
164
175
  quoteRoute: functionNotImplemented,
165
176
  refreshBalance: functionNotImplemented,
166
177
  findTokenDataByAddressAndChain: functionNotImplemented,
178
+ bridgeTokensDictionary: null,
167
179
  };
168
180
 
169
181
  const swapContext = createContext(init);
@@ -189,22 +201,28 @@ export const SwapProvider = ({
189
201
  const [infiniteApproval, setInfiniteApproval] = useState(
190
202
  init.infiniteApproval,
191
203
  );
192
- const srcTokenProvided = useMemo(
193
- () => !!integrationConfig?.srcTokenAddr,
194
- [integrationConfig?.srcTokenAddr],
204
+ const srcTokenLocked = useMemo(
205
+ () => !!integrationConfig?.srcTokenLocked,
206
+ [integrationConfig?.srcTokenLocked],
207
+ );
208
+ const dstTokenLocked = useMemo(
209
+ () => !!integrationConfig?.dstTokenLocked,
210
+ [integrationConfig?.dstTokenLocked],
195
211
  );
196
- const dstTokenProvided = useMemo(
197
- () => !!integrationConfig?.dstTokenAddr,
198
- [integrationConfig?.dstTokenAddr],
212
+ const srcChainLocked = useMemo(
213
+ () => !!integrationConfig?.srcChainLocked,
214
+ [integrationConfig?.srcChainLocked],
199
215
  );
200
- const srcChainProvided = useMemo(
201
- () => !!integrationConfig?.srcChainId,
202
- [integrationConfig?.srcChainId],
216
+ const dstChainLocked = useMemo(
217
+ () => !!integrationConfig?.dstChainLocked,
218
+ [integrationConfig?.dstChainLocked],
203
219
  );
204
- const dstChainProvided = useMemo(
205
- () => !!integrationConfig?.dstChainId,
206
- [integrationConfig?.dstChainId],
220
+
221
+ const bridgeUI = useMemo(
222
+ () => !!integrationConfig.bridge,
223
+ [integrationConfig.bridge],
207
224
  );
225
+
208
226
  const [slippage, setSlippage] = useState(init.slippage);
209
227
  const [srcChain, setSrcChain] = useState(init.srcChain);
210
228
  const [dstChain, setDstChain] = useState(init.dstChain);
@@ -288,14 +306,66 @@ export const SwapProvider = ({
288
306
  return tempChainToTokenOptionsMap;
289
307
  }, [supportedTokens]);
290
308
 
309
+ const [bridgeTokens, setBridgeTokens] = useState<BridgeToken[]>([]);
310
+ useEffect(() => {
311
+ (async () => {
312
+ const data = await getBridgeTokens();
313
+ setBridgeTokens(data);
314
+ })();
315
+ }, []);
316
+
317
+ const bridgeTokensDictionary = useMemo(() => {
318
+ const result: BridgeTokensDictionary = {};
319
+
320
+ for (const dict of bridgeTokens) {
321
+ const [chainId0, address0] = Object.entries(dict)[0]!;
322
+ const [chainId1, address1] = Object.entries(dict)[1]!;
323
+ if (!result[chainId0]) {
324
+ result[chainId0] = {};
325
+ }
326
+ if (!result[chainId0][address0]) {
327
+ result[chainId0][address0] = {};
328
+ }
329
+ result[chainId0][address0][chainId1] = address1;
330
+ if (!result[chainId1]) {
331
+ result[chainId1] = {};
332
+ }
333
+ if (!result[chainId1][address1]) {
334
+ result[chainId1][address1] = {};
335
+ }
336
+ result[chainId1][address1][chainId0] = address0;
337
+ }
338
+
339
+ if (Object.keys(result).length) {
340
+ return result;
341
+ }
342
+
343
+ return null;
344
+ }, [bridgeTokens]);
345
+
291
346
  const getTokenOptions = useCallback(
292
- (chainId: string, oppositeChainId: string) => {
347
+ (chainId: string | undefined, oppositeChainId: string | undefined) => {
293
348
  if (!chainId || !oppositeChainId) {
294
349
  return [];
295
350
  }
351
+
352
+ if (bridgeTokensDictionary && bridgeUI) {
353
+ if (!chainToTokenOptionsMap[chainId]) {
354
+ return [];
355
+ }
356
+
357
+ return chainToTokenOptionsMap[chainId].filter((tokenData) => {
358
+ const supportedTokensAddresses = Object.keys(
359
+ bridgeTokensDictionary[chainId] || {},
360
+ );
361
+
362
+ return supportedTokensAddresses.includes(tokenData.address);
363
+ });
364
+ }
365
+
296
366
  return chainToTokenOptionsMap[chainId] || [];
297
367
  },
298
- [chainToTokenOptionsMap],
368
+ [bridgeTokensDictionary, bridgeUI, chainToTokenOptionsMap],
299
369
  );
300
370
 
301
371
  const srcTokenBalanceInfo = useMemo(() => {
@@ -665,9 +735,88 @@ export const SwapProvider = ({
665
735
  setDstToken(initDstToken);
666
736
  }, [integrationConfig, supportedChains]);
667
737
 
738
+ useEffect(() => {
739
+ if (!bridgeTokensDictionary) {
740
+ return;
741
+ }
742
+
743
+ const { source, target } = mapToValidPath({
744
+ source: { chain: srcChain, token: srcToken },
745
+ target: { chain: dstChain, token: dstToken },
746
+ type: bridgeUI ? "BRIDGE" : "SWAP",
747
+ supportedChains,
748
+ bridgeTokensDictionary,
749
+ });
750
+
751
+ if (source.chain?.chainId !== srcChain?.chainId) {
752
+ setSrcChain(source.chain);
753
+ }
754
+
755
+ if (target.chain?.chainId !== dstChain?.chainId) {
756
+ setDstChain(target.chain);
757
+ }
758
+
759
+ if (source.token?.address !== srcToken?.address) {
760
+ setSrcToken(source.token);
761
+ }
762
+
763
+ if (target.token?.address !== dstToken?.address) {
764
+ setDstToken(target.token);
765
+ }
766
+ }, [
767
+ srcChain,
768
+ srcToken,
769
+ dstChain,
770
+ dstToken,
771
+ bridgeUI,
772
+ supportedChains,
773
+ bridgeTokensDictionary,
774
+ ]);
775
+
776
+ useEffect(() => {
777
+ if (integrationConfig.onDstChainChange) {
778
+ integrationConfig.onDstChainChange(dstChain?.chainId);
779
+ } else if (window.xPayOnDstChainChange) {
780
+ window.xPayOnDstChainChange(dstChain?.chainId);
781
+ }
782
+ }, [integrationConfig, dstChain]);
783
+
784
+ useEffect(() => {
785
+ const token = dstToken
786
+ ? { address: dstToken.address.toLowerCase(), symbol: dstToken.symbol }
787
+ : undefined;
788
+
789
+ if (integrationConfig.onDstTokenChange) {
790
+ integrationConfig.onDstTokenChange(token);
791
+ } else if (window.xPayOnDstTokenChange) {
792
+ window.xPayOnDstTokenChange(token);
793
+ }
794
+ }, [integrationConfig, dstToken]);
795
+
796
+ useEffect(() => {
797
+ if (integrationConfig.onSrcChainChange) {
798
+ integrationConfig.onSrcChainChange(srcChain?.chainId);
799
+ } else if (window.xPayOnSrcChainChange) {
800
+ window.xPayOnSrcChainChange(srcChain?.chainId);
801
+ }
802
+ }, [integrationConfig, srcChain]);
803
+
804
+ useEffect(() => {
805
+ const token = srcToken
806
+ ? { address: srcToken.address.toLowerCase(), symbol: srcToken.symbol }
807
+ : undefined;
808
+
809
+ if (integrationConfig.onSrcTokenChange) {
810
+ integrationConfig.onSrcTokenChange(token);
811
+ } else if (window.xPayOnSrcTokenChange) {
812
+ window.xPayOnSrcTokenChange(token);
813
+ }
814
+ }, [integrationConfig, srcToken]);
815
+
668
816
  return (
669
817
  <swapContext.Provider
670
818
  value={{
819
+ bridgeUI,
671
820
  integrationConfig,
672
821
  wagmiConfig,
673
822
  supportedChains,
@@ -677,22 +826,18 @@ export const SwapProvider = ({
677
826
  error,
678
827
  setError,
679
828
  feeToken,
680
- srcChainProvided,
681
829
  srcChain,
682
830
  setSrcChain,
683
831
  srcChainTokensOptions,
684
832
  srcChainOtherTokensOptions,
685
833
  dstChainTokensPrices,
686
834
  srcChainTokensPrices,
687
- dstChainProvided,
688
835
  dstChain,
689
836
  setDstChain,
690
837
  dstChainTokensOptions,
691
838
  dstChainOtherTokensOptions,
692
- srcTokenProvided,
693
839
  srcToken,
694
840
  setSrcToken,
695
- dstTokenProvided,
696
841
  dstToken,
697
842
  setDstToken,
698
843
  srcValue,
@@ -723,6 +868,11 @@ export const SwapProvider = ({
723
868
  quoteRoute,
724
869
  refreshBalance,
725
870
  findTokenDataByAddressAndChain,
871
+ srcTokenLocked,
872
+ srcChainLocked,
873
+ dstTokenLocked,
874
+ dstChainLocked,
875
+ bridgeTokensDictionary,
726
876
  }}
727
877
  >
728
878
  {children}
@@ -1,10 +1,10 @@
1
1
  import { CloseIcon } from "@src/assets/icons";
2
2
  import {
3
3
  Button,
4
- Modal,
5
- ModalType,
6
4
  SnackMessage,
7
5
  Spinner,
6
+ TxModal,
7
+ TxModalType,
8
8
  } from "@src/components";
9
9
  import { ConfirmationView } from "@src/components/Swap/SwapView/ConfirmationView";
10
10
  import { CCIP_EXPLORER } from "@src/constants";
@@ -319,7 +319,7 @@ export const TxUIWrapper = ({ children }: Props) => {
319
319
  isTxModalOpenRef.current = flag;
320
320
  }, []);
321
321
 
322
- const modalType: ModalType = useMemo(
322
+ const modalType: TxModalType = useMemo(
323
323
  () =>
324
324
  txError
325
325
  ? "error"
@@ -369,14 +369,14 @@ export const TxUIWrapper = ({ children }: Props) => {
369
369
  return (
370
370
  <TxUIWrapperContext.Provider value={state}>
371
371
  {isTxModalOpen && (
372
- <Modal
372
+ <TxModal
373
373
  id="tx_modal"
374
374
  className="max-w-x_modal"
375
375
  type={modalType}
376
376
  onCloseClick={closeTxModal}
377
377
  >
378
378
  <ConfirmationView onCloseClick={closeTxModal} />
379
- </Modal>
379
+ </TxModal>
380
380
  )}
381
381
  {children}
382
382
  </TxUIWrapperContext.Provider>
@@ -1,5 +1,4 @@
1
1
  export * from "./useBatchQuery";
2
2
  export * from "./useDebounce";
3
3
  export * from "./useEvmContractApi";
4
- export * from "./usePortal";
5
4
  export * from "./useXPower";
@@ -0,0 +1,7 @@
1
+ export type BridgeTokensDictionary = {
2
+ [chainId0: string]: {
3
+ [tokenAddress0: string]: {
4
+ [chainId1: string]: string; // string is tokenAddress1
5
+ };
6
+ };
7
+ };
@@ -1,5 +1,5 @@
1
- import { Web3Environment } from "./Web3Environment";
2
1
  import { BigNumber } from "ethers";
2
+ import { Web3Environment } from "./Web3Environment";
3
3
 
4
4
  export type Chain = {
5
5
  ecosystem: string;
@@ -17,6 +17,8 @@ export type Chain = {
17
17
  publicRpcUrls: string[];
18
18
  privateRpcUrls?: string[];
19
19
  scanApiURL?: string;
20
+ defaultDstChain?: string;
21
+ disabledForDestination?: string[];
20
22
  };
21
23
 
22
24
  export type Token = {
@@ -1,7 +1,6 @@
1
1
  export * from "./Addresses";
2
- export * from "./XSwapConfig";
3
2
  export * from "./BridgeToken";
4
- export * from "./TokenData";
3
+ export * from "./BridgeTokensDictionary";
5
4
  export * from "./CoinTypeAddress";
6
5
  export * from "./CollectFees";
7
6
  export * from "./ContractCall";
@@ -11,9 +10,11 @@ export * from "./forms";
11
10
  export * from "./integrations";
12
11
  export * from "./payloads";
13
12
  export * from "./Protocol";
14
- export * from "./Route";
15
- export * from "./Web3Environment";
16
- export * from "./XSwapCallType";
17
13
  export * from "./Referral";
14
+ export * from "./Route";
15
+ export * from "./TokenData";
18
16
  export * from "./TransactionHistory";
19
17
  export * from "./TxUIWrapper";
18
+ export * from "./Web3Environment";
19
+ export * from "./XSwapCallType";
20
+ export * from "./XSwapConfig";