@xswap-link/sdk 0.9.0 → 0.9.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xswap-link/sdk",
3
- "version": "0.9.0",
3
+ "version": "0.9.2",
4
4
  "description": "JavaScript SDK for XSwap platform",
5
5
  "homepage": "https://github.com/xswap-link/xswap-sdk",
6
6
  "repository": {
@@ -36,6 +36,8 @@
36
36
  "@fortawesome/react-fontawesome": "^0.2.0",
37
37
  "@r2wc/core": "^1.1.0",
38
38
  "@tanstack/react-query": "^5.64.2",
39
+ "@wagmi/connectors": "^5.7.5",
40
+ "@wagmi/core": "^2.16.3",
39
41
  "async-retry": "^1.3.3",
40
42
  "bignumber.js": "4.0.4",
41
43
  "date-fns": "^3.6.0",
@@ -34,6 +34,8 @@ export const SwapButton = () => {
34
34
  srcTokenBalanceWei,
35
35
  isFetchingRoute,
36
36
  isAsyncDataLoaded,
37
+ hasOnConnectWalletCallback,
38
+ onConnectWallet,
37
39
  } = useSwapContext();
38
40
 
39
41
  const { setTxStatus, setTxMsg, setTxModalOpen, enqueueTransaction } =
@@ -111,13 +113,19 @@ export const SwapButton = () => {
111
113
 
112
114
  if (!address) {
113
115
  return {
114
- text: integrationConfig.defaultWalletPicker
115
- ? "Connect Wallet"
116
- : "Connect Wallet First",
116
+ text:
117
+ integrationConfig.defaultWalletPicker || hasOnConnectWalletCallback
118
+ ? "Connect Wallet"
119
+ : "Connect Wallet First",
117
120
  fn: () => {
118
- setConnectWalletModalOpen(true);
121
+ if (integrationConfig.defaultWalletPicker) {
122
+ setConnectWalletModalOpen(true);
123
+ } else if (hasOnConnectWalletCallback) {
124
+ onConnectWallet();
125
+ }
119
126
  },
120
- disabled: !integrationConfig.defaultWalletPicker,
127
+ disabled:
128
+ !integrationConfig.defaultWalletPicker && !hasOnConnectWalletCallback,
121
129
  };
122
130
  }
123
131
 
@@ -1,10 +1,9 @@
1
- import { DotGreenIcon, HelpIcon } from "@src/assets/icons";
1
+ import { DotGreenIcon } from "@src/assets/icons";
2
2
  import { SwapPanelType } from "@src/components/Swap/SwapView";
3
- import { Tooltip } from "@src/components/Tooltip";
4
3
  import { useSwapContext } from "@src/context";
5
4
  import useNetworks from "@src/hooks/networkManagement/useNetworks";
6
5
  import { Chain } from "@src/models";
7
- import { useMemo, useRef } from "react";
6
+ import { useMemo } from "react";
8
7
 
9
8
  type Props = {
10
9
  chain: Chain;
@@ -18,8 +17,6 @@ export const ChainItem = ({ chain, type, onClick, disabled }: Props) => {
18
17
  networks: { evm },
19
18
  } = useNetworks();
20
19
 
21
- const tooltipTriggerRef = useRef<SVGSVGElement>(null);
22
-
23
20
  const { srcChain, dstChain, bridgeUI } = useSwapContext();
24
21
 
25
22
  const currentChainId = useMemo(
@@ -40,66 +37,61 @@ export const ChainItem = ({ chain, type, onClick, disabled }: Props) => {
40
37
  return type === "destination" ? srcChain?.chainId : dstChain?.chainId;
41
38
  }, [bridgeUI, dstChain?.chainId, srcChain?.chainId, type]);
42
39
 
43
- return (
44
- <div
45
- onClick={() => {
46
- if (chain.chainId === sameChainId || disabled) {
47
- return;
48
- }
49
- onClick(chain.chainId);
50
- }}
51
- 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 ${
52
- currentChainId === chain.chainId ? "selected-chain-item" : ""
53
- } ${
54
- chain.chainId === sameChainId || disabled
55
- ? "disabled-chain-item cursor-default"
56
- : ""
57
- }`}
58
- >
59
- <div className="flex gap-3 items-center w-full">
60
- <img src={chain.image} alt={chain.name} className="w-[34px] h-[34px]" />
61
- <p>{chain.displayName}</p>
62
- </div>
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
+ };
63
53
 
64
- {connected && (
65
- <div className="flex items-baseline gap-1">
66
- <DotGreenIcon />
67
- <div className="text-t_text_green">connected</div>
68
- </div>
69
- )}
54
+ const tooltipText = getTooltipText();
70
55
 
71
- {disabled && chain.chainId !== sameChainId && (
72
- <div className="flex items-center gap-1">
73
- <Tooltip
74
- text={
75
- bridgeUI
76
- ? "Token is not available on this chain"
77
- : `Transfers from ${
78
- srcChain?.name || "the source chain"
79
- } to this chain are currently not supported.`
80
- }
81
- position="BOTTOM"
82
- triggerRef={tooltipTriggerRef}
83
- id="transfers-from-chain-not-supported-tooltip"
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]"
84
78
  />
79
+ <p>{chain.displayName}</p>
85
80
  </div>
86
- )}
87
81
 
88
- {chain.chainId === sameChainId && (
89
- <div className="flex items-center gap-1">
90
- <Tooltip
91
- text="Transfers between the same chain are not available"
92
- id="transfers-between-same-chains-tooltip"
93
- position="BOTTOM"
94
- triggerRef={tooltipTriggerRef}
95
- />
96
- </div>
97
- )}
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
+ )}
98
87
 
99
- <HelpIcon
100
- ref={tooltipTriggerRef}
101
- className="cursor-help fill-t_main_accent_light w-[18px] h-[18px] min-w-[18px] min-h-[18px] max-w-[18px] max-h-[18px]"
102
- />
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>
103
95
  </div>
104
96
  );
105
97
  };
@@ -18,7 +18,7 @@ export const TokenItem = ({
18
18
  onClick,
19
19
  selectedChainId,
20
20
  }: Props) => {
21
- const { supportedChains } = useSwapContext();
21
+ const { supportedChains, tokenPrices } = useSwapContext();
22
22
  const { address } = useAccount();
23
23
 
24
24
  const chain = useMemo(
@@ -26,6 +26,26 @@ export const TokenItem = ({
26
26
  [supportedChains, token],
27
27
  );
28
28
 
29
+ const tokenPrice = useMemo(() => {
30
+ const prices = tokenPrices[token.chainId];
31
+ return prices?.[token.address];
32
+ }, [token, tokenPrices]);
33
+
34
+ const tokenBalance = useMemo(() => {
35
+ if (!token.balance || !token.decimals) return null;
36
+ return Number(ethers.utils.formatUnits(token.balance, token.decimals));
37
+ }, [token.balance, token.decimals]);
38
+
39
+ const hasBalance = useMemo(
40
+ () => token.balance && !token.balance.eq(0),
41
+ [token.balance],
42
+ );
43
+
44
+ const tokenValueUsd = useMemo(() => {
45
+ if (!tokenBalance || !tokenPrice || !hasBalance) return null;
46
+ return tokenBalance * +tokenPrice;
47
+ }, [tokenBalance, tokenPrice, hasBalance]);
48
+
29
49
  return (
30
50
  <div
31
51
  className={`token-picker-container ${
@@ -55,16 +75,21 @@ export const TokenItem = ({
55
75
  </div>
56
76
 
57
77
  {token.balance && token.decimals ? (
58
- <div className="text-xs text-t_text_primary text-opacity-50">
59
- {token.balance.eq(0) ||
60
- Number(ethers.utils.formatUnits(token.balance, token.decimals)) >
61
- 0.0001
62
- ? weiToHumanReadable({
63
- amount: token.balance.toString(),
64
- decimals: token.decimals,
65
- precisionFractionalPlaces: 4,
66
- })
67
- : "<0.0001"}
78
+ <div className="text-right">
79
+ <div className="text-xs text-t_text_primary">
80
+ {token.balance.eq(0) || tokenBalance! > 0.0001
81
+ ? weiToHumanReadable({
82
+ amount: token.balance.toString(),
83
+ decimals: token.decimals,
84
+ precisionFractionalPlaces: 4,
85
+ })
86
+ : "<0.0001"}
87
+ </div>
88
+ {hasBalance && (
89
+ <div className="text-xs text-t_text_primary text-opacity-50">
90
+ {tokenValueUsd ? `$${tokenValueUsd.toFixed(2)}` : "$ -"}
91
+ </div>
92
+ )}
68
93
  </div>
69
94
  ) : (
70
95
  <>
@@ -51,8 +51,12 @@ export const TokenPicker = ({
51
51
  const currentRouteRequestNonce = useRef<number>(0);
52
52
  const tokenSearchRef = useRef<HTMLInputElement | null>(null);
53
53
 
54
- const { bridgeUI, supportedChains, findTokenDataByAddressAndChain } =
55
- useSwapContext();
54
+ const {
55
+ bridgeUI,
56
+ supportedChains,
57
+ findTokenDataByAddressAndChain,
58
+ tokenPrices,
59
+ } = useSwapContext();
56
60
  const { address } = useAccount();
57
61
  const evmContractApi = useEvmContractApi();
58
62
 
@@ -191,6 +195,15 @@ export const TokenPicker = ({
191
195
  }, [isOpen]);
192
196
 
193
197
  const allTokens = useMemo(() => {
198
+ const calculateTokenValue = (token: TokenOption) => {
199
+ if (!token.balance || !token.decimals) return 0;
200
+ const balance = Number(
201
+ ethers.utils.formatUnits(token.balance, token.decimals),
202
+ );
203
+ const price = tokenPrices[token.chainId]?.[token.address];
204
+ return price ? balance * Number(price) : 0;
205
+ };
206
+
194
207
  const ownedFilteredTokens = [
195
208
  ...filteredTokens.filter((token) =>
196
209
  BigNumber.from(token?.balance || "0").gt(0),
@@ -198,9 +211,16 @@ export const TokenPicker = ({
198
211
  ...otherFilteredTokens.filter((token) =>
199
212
  BigNumber.from(token?.balance || "0").gt(0),
200
213
  ),
201
- ].sort(
202
- (tokenDataA, tokenDataB) => tokenDataB.priority - tokenDataA.priority,
203
- );
214
+ ].sort((tokenA, tokenB) => {
215
+ const valueA = calculateTokenValue(tokenA);
216
+ const valueB = calculateTokenValue(tokenB);
217
+ // First sort by USD value
218
+ if (valueB !== valueA) {
219
+ return valueB - valueA;
220
+ }
221
+ // If USD values are equal (or both 0), sort by priority
222
+ return tokenB.priority - tokenA.priority;
223
+ });
204
224
 
205
225
  const currentChainTokens = filteredTokens
206
226
  .filter((token) => BigNumber.from(token?.balance || "0").eq(0))
@@ -231,7 +251,7 @@ export const TokenPicker = ({
231
251
  ];
232
252
 
233
253
  return groups.flat();
234
- }, [filteredTokens, otherFilteredTokens, chain, address]);
254
+ }, [filteredTokens, otherFilteredTokens, chain, address, tokenPrices]);
235
255
 
236
256
  const ownedTokens = useMemo(
237
257
  () => allTokens.filter((token) => token.balance?.gt(0)),
@@ -113,7 +113,11 @@ export const TokenPanel = ({ chain, token, type, className }: Props) => {
113
113
  <div className="flex flex-col font-medium items-start">
114
114
  <p className="text-xs opacity-60">Token: </p>
115
115
  <p className={`${token ? "" : "opacity-60"}`}>
116
- {token ? token.symbol : "Select"}
116
+ {token
117
+ ? token.symbol
118
+ : type === "destination" && bridgeUI
119
+ ? "-"
120
+ : "Select"}
117
121
  </p>
118
122
  </div>
119
123
  </div>
@@ -38,7 +38,7 @@ export const SwapPanel = ({ type }: Props) => {
38
38
  />
39
39
  </div>
40
40
  <div
41
- className={`flex justify-between ${
41
+ className={`flex justify-between rounded-b-[11px] ${
42
42
  type === "destination" &&
43
43
  "bg-gradient-to-r from-t_main_accent_light/20 to-t_main_accent_dark/20"
44
44
  }`}
@@ -7,8 +7,8 @@ export type SwapPanelType = "source" | "destination";
7
7
 
8
8
  export const SwapView = () => {
9
9
  return (
10
- <div className="flex flex-col gap-2 fill-t_text_primary">
11
- <div className="flex flex-col gap-[10px]">
10
+ <div className="flex flex-col gap-6 fill-t_text_primary">
11
+ <div className="flex flex-col gap-[11px]">
12
12
  <SwapPanel type="source" />
13
13
  <ReorderButton />
14
14
  <SwapPanel type="destination" />
@@ -13,7 +13,7 @@ const positionToClass: Record<Position, string> = {
13
13
 
14
14
  export const Tooltip: FC<{
15
15
  id: string;
16
- position: "TOP" | "BOTTOM" | "LEFT" | "RIGHT";
16
+ position: Position;
17
17
  text: string;
18
18
  triggerRef: RefObject<Element>;
19
19
  }> = ({ id, position, text, triggerRef }) => {
@@ -32,9 +32,14 @@ const WagmiReload: FC = () => {
32
32
  const { reconnect } = useReconnect();
33
33
 
34
34
  useEffect(() => {
35
+ let count = 0;
35
36
  const interval = setInterval(() => {
36
37
  reconnect();
37
- }, 200);
38
+ count++;
39
+ if (count >= 5) {
40
+ clearInterval(interval);
41
+ }
42
+ }, 1000);
38
43
 
39
44
  return () => {
40
45
  clearInterval(interval);
@@ -91,6 +96,7 @@ export const TxConfigForm = ({
91
96
  onSrcTokenChange,
92
97
  onSrcChainChange,
93
98
  bridge,
99
+ onConnectWallet,
94
100
  }: TxConfigFormPayload &
95
101
  (
96
102
  | {
@@ -156,6 +162,7 @@ export const TxConfigForm = ({
156
162
  onSrcTokenChange,
157
163
  onSrcChainChange,
158
164
  bridge,
165
+ onConnectWallet,
159
166
  }}
160
167
  supportedChains={supportedChains}
161
168
  wagmiConfig={wagmiConfig}
@@ -33,6 +33,7 @@ const TxWidget = ({
33
33
  onDstChainChange,
34
34
  onSrcTokenChange,
35
35
  onSrcChainChange,
36
+ onConnectWallet,
36
37
  bridge,
37
38
  }: WidgetIntegrationPayload) => {
38
39
  const [loading, setLoading] = useState(true);
@@ -95,6 +96,7 @@ const TxWidget = ({
95
96
  onDstChainChange={onDstChainChange}
96
97
  onSrcTokenChange={onSrcTokenChange}
97
98
  onSrcChainChange={onSrcChainChange}
99
+ onConnectWallet={onConnectWallet}
98
100
  bridge={bridge}
99
101
  />
100
102
  )}
@@ -45,6 +45,7 @@ export const TxWidgetWCWrapped = ({
45
45
  onDstChainChange,
46
46
  onSrcTokenChange,
47
47
  onSrcChainChange,
48
+ onConnectWallet,
48
49
  bridge,
49
50
  }: WidgetIntegrationPayload) => {
50
51
  useEffect(() => {
@@ -55,12 +56,14 @@ export const TxWidgetWCWrapped = ({
55
56
  window.xPayOnDstChainChange = onDstChainChange;
56
57
  window.xPayOnSrcTokenChange = onSrcTokenChange;
57
58
  window.xPayOnSrcChainChange = onSrcChainChange;
59
+ window.xPayOnConnectWallet = onConnectWallet;
58
60
  }, [
59
61
  onPendingTransactionsChange,
60
62
  onDstTokenChange,
61
63
  onDstChainChange,
62
64
  onSrcTokenChange,
63
65
  onSrcChainChange,
66
+ onConnectWallet,
64
67
  ]);
65
68
 
66
69
  return (
@@ -3,8 +3,8 @@ import { isServer } from "@src/utils";
3
3
  import { Transport } from "viem";
4
4
  import * as WagmiChains from "viem/chains";
5
5
  import { mainnet } from "viem/chains";
6
- import { Config, createConfig, createStorage, http } from "wagmi";
7
- import { injected, metaMask, safe, walletConnect } from "wagmi/connectors";
6
+ import { Config, createConfig, createStorage, http } from "@wagmi/core";
7
+ import { injected, walletConnect, coinbaseWallet } from "@wagmi/connectors";
8
8
 
9
9
  const storage = createStorage({
10
10
  key: "xpay.wagmi.store",
@@ -19,11 +19,13 @@ export const getWagmiConfig = (supportedChains: Chain[]): Config => {
19
19
  transports,
20
20
  connectors: [
21
21
  injected(),
22
- metaMask(),
23
- safe(),
22
+ coinbaseWallet({
23
+ appLogoUrl: "https://xswap.link/favicon.ico",
24
+ appName: "XSwap",
25
+ }),
24
26
  walletConnect({
25
27
  projectId: "c392898b45ac587a280b5eb33e92aeb0",
26
- showQrModal: false,
28
+ showQrModal: true,
27
29
  }),
28
30
  ],
29
31
  storage,
@@ -64,8 +64,7 @@ type SwapContext = {
64
64
  setSrcChain: Dispatch<SetStateAction<Chain | undefined>>;
65
65
  srcChainTokensOptions: TokenOption[];
66
66
  srcChainOtherTokensOptions: TokenOption[];
67
- srcChainTokensPrices: TokenPrices;
68
- dstChainTokensPrices: TokenPrices;
67
+ tokenPrices: TokenPrices;
69
68
  srcToken: Token | undefined;
70
69
  setSrcToken: Dispatch<SetStateAction<Token | undefined>>;
71
70
  dstChain: Chain | undefined;
@@ -110,6 +109,8 @@ type SwapContext = {
110
109
  chainId: string,
111
110
  ) => Token | undefined;
112
111
  bridgeTokensDictionary: BridgeTokensDictionary | null;
112
+ onConnectWallet: () => void;
113
+ hasOnConnectWalletCallback: boolean;
113
114
  };
114
115
 
115
116
  const functionNotImplemented = () => {
@@ -128,8 +129,7 @@ const init: SwapContext = {
128
129
  srcChain: undefined,
129
130
  srcChainTokensOptions: [],
130
131
  srcChainOtherTokensOptions: [],
131
- srcChainTokensPrices: {},
132
- dstChainTokensPrices: {},
132
+ tokenPrices: {},
133
133
  dstChain: undefined,
134
134
  dstChainTokensOptions: [],
135
135
  dstChainOtherTokensOptions: [],
@@ -174,6 +174,8 @@ const init: SwapContext = {
174
174
  refreshBalance: functionNotImplemented,
175
175
  findTokenDataByAddressAndChain: functionNotImplemented,
176
176
  bridgeTokensDictionary: null,
177
+ onConnectWallet: functionNotImplemented,
178
+ hasOnConnectWalletCallback: false,
177
179
  };
178
180
 
179
181
  const swapContext = createContext(init);
@@ -246,12 +248,7 @@ export const SwapProvider = ({
246
248
  const [dstChainTokensOptions, setDstChainTokensOptions] = useState(
247
249
  init.dstChainTokensOptions,
248
250
  );
249
- const [srcChainTokensPrices, setSrcChainTokensPrices] = useState(
250
- init.srcChainTokensPrices,
251
- );
252
- const [dstChainTokensPrices, setDstChainTokensPrices] = useState(
253
- init.dstChainTokensPrices,
254
- );
251
+ const [tokenPrices, setTokenPrices] = useState(init.tokenPrices);
255
252
  const [srcChainOtherTokensOptions, setSrcChainOtherTokensOptions] = useState(
256
253
  init.srcChainOtherTokensOptions,
257
254
  );
@@ -265,6 +262,15 @@ export const SwapProvider = ({
265
262
 
266
263
  const { history } = useHistory();
267
264
 
265
+ useEffect(() => {
266
+ if (supportedChains.length > 0) {
267
+ const chainIds = supportedChains.map((chain) => chain.chainId);
268
+ getPrices({ chainId: chainIds }).then((prices) => {
269
+ setTokenPrices(prices);
270
+ });
271
+ }
272
+ }, [supportedChains]);
273
+
268
274
  const supportedTokens: Record<string, Record<string, Token>> = useMemo(() => {
269
275
  const customTokens = !isServer
270
276
  ? JSON.parse(localStorage.getItem("custom-tokens") || "{}")
@@ -406,36 +412,21 @@ export const SwapProvider = ({
406
412
  [srcToken?.decimals, srcValue],
407
413
  );
408
414
 
409
- // fetch srcTokenPrices
410
- useEffect(() => {
411
- if (srcChain) {
412
- getPrices({ chainId: srcChain.chainId, currency: "USD" }).then((prices) =>
413
- setSrcChainTokensPrices(prices),
414
- );
415
- }
416
- }, [srcChain]);
417
-
418
- // fetch dstTokenPrices
419
- useEffect(() => {
420
- if (dstChain) {
421
- getPrices({ chainId: dstChain.chainId, currency: "USD" }).then((prices) =>
422
- setDstChainTokensPrices(prices),
423
- );
424
- }
425
- }, [dstChain]);
426
-
427
415
  const srcValueUsd = useMemo(() => {
428
416
  if (
429
417
  srcToken &&
430
- srcChainTokensPrices &&
431
- srcChainTokensPrices[srcToken.address]
418
+ srcChain &&
419
+ tokenPrices &&
420
+ tokenPrices[srcChain.chainId] &&
421
+ tokenPrices[srcChain.chainId]?.[srcToken.address]
432
422
  ) {
433
423
  return (
434
- Number(srcValue) * Number(srcChainTokensPrices[srcToken.address])
424
+ Number(srcValue) *
425
+ Number(tokenPrices[srcChain.chainId]?.[srcToken.address])
435
426
  ).toFixed(2);
436
427
  }
437
428
  return null;
438
- }, [srcChainTokensPrices, srcToken, srcValue]);
429
+ }, [tokenPrices, srcToken, srcValue, srcChain]);
439
430
  const dstValue = useMemo(
440
431
  () =>
441
432
  weiToHumanReadable({
@@ -457,15 +448,18 @@ export const SwapProvider = ({
457
448
  const dstValueUsd = useMemo(() => {
458
449
  if (
459
450
  dstToken &&
460
- dstChainTokensPrices &&
461
- dstChainTokensPrices[dstToken.address]
451
+ dstChain &&
452
+ tokenPrices &&
453
+ tokenPrices[dstChain?.chainId] &&
454
+ tokenPrices[dstChain?.chainId]?.[dstToken.address]
462
455
  ) {
463
456
  return (
464
- Number(dstValue) * Number(dstChainTokensPrices[dstToken.address])
457
+ Number(dstValue) *
458
+ Number(tokenPrices[dstChain?.chainId]?.[dstToken.address])
465
459
  ).toFixed(2);
466
460
  }
467
461
  return null;
468
- }, [dstChainTokensPrices, dstToken, dstValue]);
462
+ }, [tokenPrices, dstToken, dstValue, dstChain]);
469
463
  const dstValueMin = useMemo(
470
464
  () =>
471
465
  weiToHumanReadable({
@@ -933,6 +927,18 @@ export const SwapProvider = ({
933
927
  // eslint-disable-next-line react-hooks/exhaustive-deps
934
928
  }, [integrationConfig.onSrcTokenChange, srcToken]);
935
929
 
930
+ const onConnectWallet = useCallback(() => {
931
+ if (integrationConfig.onConnectWallet) {
932
+ integrationConfig.onConnectWallet();
933
+ } else if (window.xPayOnConnectWallet) {
934
+ window.xPayOnConnectWallet();
935
+ }
936
+ }, [integrationConfig]);
937
+
938
+ const hasOnConnectWalletCallback = useMemo(() => {
939
+ return !!(integrationConfig.onConnectWallet || window.xPayOnConnectWallet);
940
+ }, [integrationConfig.onConnectWallet]);
941
+
936
942
  return (
937
943
  <swapContext.Provider
938
944
  value={{
@@ -950,8 +956,7 @@ export const SwapProvider = ({
950
956
  setSrcChain,
951
957
  srcChainTokensOptions,
952
958
  srcChainOtherTokensOptions,
953
- dstChainTokensPrices,
954
- srcChainTokensPrices,
959
+ tokenPrices,
955
960
  dstChain,
956
961
  setDstChain,
957
962
  dstChainTokensOptions,
@@ -993,6 +998,8 @@ export const SwapProvider = ({
993
998
  dstTokenLocked,
994
999
  dstChainLocked,
995
1000
  bridgeTokensDictionary,
1001
+ onConnectWallet,
1002
+ hasOnConnectWalletCallback,
996
1003
  }}
997
1004
  >
998
1005
  {children}
@@ -40,7 +40,9 @@ export type Prices = {
40
40
  };
41
41
 
42
42
  export type TokenPrices = {
43
- [tokenAddress: string]: string;
43
+ [chainId: string]: {
44
+ [tokenAddress: string]: string;
45
+ };
44
46
  };
45
47
 
46
48
  export type TokenBalances = {
@@ -1,4 +1,4 @@
1
1
  export type GetPricesPayload = {
2
- chainId: string;
2
+ chainId: string[];
3
3
  currency?: string;
4
4
  };
@@ -61,5 +61,6 @@ export type ModalIntegrationPayload = {
61
61
  token: { address: string; symbol: string } | undefined,
62
62
  ) => void;
63
63
  onSrcChainChange?: (chain: string | undefined) => void;
64
+ onConnectWallet?: () => void;
64
65
  bridge?: boolean;
65
66
  };
@@ -25,5 +25,6 @@ export type WidgetIntegrationPayload = {
25
25
  token: { address: string; symbol: string } | undefined,
26
26
  ) => void;
27
27
  onSrcChainChange?: (chain: string | undefined) => void;
28
+ onConnectWallet?: () => void;
28
29
  bridge?: boolean;
29
30
  };