@xswap-link/sdk 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/index.d.mts +6 -2
  3. package/dist/index.d.ts +6 -2
  4. package/dist/index.global.js +85 -84
  5. package/dist/index.js +1553 -1458
  6. package/dist/index.js.map +1 -1
  7. package/dist/index.mjs +1542 -1444
  8. package/dist/index.mjs.map +1 -1
  9. package/package.json +1 -1
  10. package/src/assets/icons/AdjustmentsIcon.tsx +18 -0
  11. package/src/assets/icons/CaretDownIcon.tsx +12 -0
  12. package/src/assets/icons/CaretsUpDownIcon.tsx +13 -0
  13. package/src/assets/icons/ChainlinkMarkIcon.tsx +17 -0
  14. package/src/assets/icons/ClockIcon.tsx +18 -0
  15. package/src/assets/icons/WarningIcon.tsx +16 -0
  16. package/src/assets/icons/index.ts +6 -0
  17. package/src/components/Modal/index.tsx +2 -2
  18. package/src/components/PoweredBy/index.tsx +14 -5
  19. package/src/components/Swap/Header/Controls/index.tsx +50 -36
  20. package/src/components/Swap/Header/index.tsx +12 -5
  21. package/src/components/Swap/HistoryView/ActivityCard/index.tsx +212 -0
  22. package/src/components/Swap/HistoryView/index.tsx +24 -6
  23. package/src/components/Swap/ReorderButton/ReorderButton.tsx +5 -7
  24. package/src/components/Swap/SettingsView/Delivery/index.tsx +27 -28
  25. package/src/components/Swap/SettingsView/InfiniteApproval/index.tsx +27 -24
  26. package/src/components/Swap/SettingsView/Slippage/index.tsx +44 -43
  27. package/src/components/Swap/SettingsView/index.tsx +1 -1
  28. package/src/components/Swap/SwapView/FeesPanel/DeliveryInfo/index.tsx +9 -19
  29. package/src/components/Swap/SwapView/FeesPanel/Fee/index.tsx +4 -4
  30. package/src/components/Swap/SwapView/FeesPanel/Fees/index.tsx +5 -9
  31. package/src/components/Swap/SwapView/FeesPanel/index.tsx +21 -22
  32. package/src/components/Swap/SwapView/SwapButton/index.tsx +25 -6
  33. package/src/components/Swap/SwapView/SwapPanel/AmountPanel/Balance/index.tsx +56 -12
  34. package/src/components/Swap/SwapView/SwapPanel/AmountPanel/index.tsx +42 -41
  35. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/NetworkFilter/index.tsx +157 -0
  36. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/TokenItem/index.tsx +98 -55
  37. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +160 -239
  38. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +57 -31
  39. package/src/components/Swap/SwapView/SwapPanel/UsdValue/index.tsx +27 -0
  40. package/src/components/Swap/SwapView/SwapPanel/WalletPanel/index.tsx +60 -49
  41. package/src/components/Swap/SwapView/SwapPanel/index.tsx +20 -25
  42. package/src/components/Swap/SwapView/WalletPicker/index.tsx +6 -1
  43. package/src/components/Swap/SwapView/index.tsx +2 -1
  44. package/src/components/Swap/index.tsx +4 -2
  45. package/src/components/ToggleButton/index.tsx +18 -15
  46. package/src/components/TxConfigForm/index.tsx +5 -5
  47. package/src/components/TxWidgetWC/index.tsx +4 -0
  48. package/src/components/TxWidgetWCWrapped/index.tsx +2 -0
  49. package/src/context/HistoryProvider.tsx +1 -0
  50. package/src/models/TransactionHistory.ts +1 -0
  51. package/src/models/payloads/ModalIntegrationPayload.ts +1 -0
  52. package/src/models/payloads/WidgetIntegrationPayload.ts +1 -0
  53. package/src/utils/index.ts +21 -0
  54. package/tailwind.config.js +2 -2
  55. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/ChainItem/index.tsx +0 -97
  56. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/ChainPicker/index.tsx +0 -103
  57. package/src/components/Swap/SwapView/SwapPanel/ChainPanel/index.tsx +0 -65
  58. package/src/components/Swap/SwapView/SwapPanel/MaxPanel/index.tsx +0 -43
  59. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/QuickPickTokenItem/index.tsx +0 -37
@@ -1,7 +1,8 @@
1
- import { ArrowDownIcon } from "@src/assets/icons";
2
- import { Modal, TokenLogo } from "@src/components";
1
+ import { ChevronDownIcon } from "@src/assets/icons";
2
+ import { Modal, TokenLogoWithChain } from "@src/components";
3
3
  import { useSwapContext } from "@src/context";
4
4
  import { Chain, Token, TokenOption } from "@src/models";
5
+ import { isChainConnectionSupported } from "@src/utils";
5
6
  import { useMemo, useState } from "react";
6
7
  import { SwapPanelType } from "../../index";
7
8
  import { TokenPicker } from "./TokenPicker";
@@ -16,6 +17,8 @@ type Props = {
16
17
  export const TokenPanel = ({ chain, token, type, className }: Props) => {
17
18
  const {
18
19
  bridgeUI,
20
+ srcChain,
21
+ dstChain,
19
22
  srcChainTokensOptions,
20
23
  srcChainOtherTokensOptions,
21
24
  dstChainTokensOptions,
@@ -67,13 +70,37 @@ export const TokenPanel = ({ chain, token, type, className }: Props) => {
67
70
  if (type === "source") {
68
71
  setSrcToken(token);
69
72
  setSrcChain(newChain);
73
+ // The new source chain cannot reach the current destination —
74
+ // reset the destination so the user picks a reachable one.
75
+ if (
76
+ dstChain &&
77
+ !isChainConnectionSupported(newChain, dstChain.chainId, bridgeUI)
78
+ ) {
79
+ setDstChain(undefined);
80
+ setDstToken(undefined);
81
+ }
70
82
  } else {
71
83
  setDstToken(token);
72
84
  setDstChain(newChain);
85
+ // The current source cannot reach the new destination chain —
86
+ // reset the source so the user picks a reachable one.
87
+ if (
88
+ srcChain &&
89
+ newChain &&
90
+ !isChainConnectionSupported(srcChain, newChain.chainId, bridgeUI)
91
+ ) {
92
+ setSrcChain(undefined);
93
+ setSrcToken(undefined);
94
+ }
73
95
  }
74
96
  setTokenPickerModalOpen(false);
75
97
  };
76
98
 
99
+ const locked =
100
+ pickerDisabled ||
101
+ integratorLockedDestinationToken ||
102
+ integratorLockedSourceToken;
103
+
77
104
  return (
78
105
  <>
79
106
  {tokenPickerModalOpen && (
@@ -93,42 +120,41 @@ export const TokenPanel = ({ chain, token, type, className }: Props) => {
93
120
 
94
121
  <button
95
122
  type="button"
96
- disabled={
97
- pickerDisabled ||
98
- integratorLockedDestinationToken ||
99
- integratorLockedSourceToken
100
- }
123
+ disabled={locked}
101
124
  onClick={() => {
102
125
  setTokenPickerModalOpen(true);
103
126
  }}
104
- className={`${className || ""}`}
127
+ className={`flex items-center gap-1 shrink-0 rounded-lg ${
128
+ locked ? "" : "hover:opacity-80 transition-opacity"
129
+ } ${className || ""}`}
105
130
  >
106
- <div className="flex justify-between items-center p-4 gap-8 border-r border-solid border-t_text_primary border-opacity-10">
107
- <div className="flex gap-2 items-center">
108
- <TokenLogo
131
+ <div className="flex items-center gap-3">
132
+ <p
133
+ className={`text-sm font-medium leading-6 tracking-[0.01em] text-t_text_primary ${
134
+ token ? "" : "opacity-60"
135
+ }`}
136
+ >
137
+ {token
138
+ ? token.symbol
139
+ : type === "destination" && bridgeUI
140
+ ? "-"
141
+ : "Select"}
142
+ </p>
143
+ {token && (
144
+ <TokenLogoWithChain
109
145
  token={token}
110
- className="w-9 h-9"
111
- generatedLogoClassName="w-9 h-9 text-[16px]"
146
+ chain={chain}
147
+ tokenLogoClassName="w-10 h-10"
148
+ generatedLogoClassName="w-10 h-10 text-[16px]"
149
+ chainLogoClassName="w-[18px]"
112
150
  />
113
- <div className="flex flex-col font-medium items-start">
114
- <p className="text-xs opacity-60">Token: </p>
115
- <p className={`${token ? "" : "opacity-60"}`}>
116
- {token
117
- ? token.symbol
118
- : type === "destination" && bridgeUI
119
- ? "-"
120
- : "Select"}
121
- </p>
122
- </div>
123
- </div>
124
- {!pickerDisabled &&
125
- !integratorLockedDestinationToken &&
126
- !integratorLockedSourceToken && (
127
- <div className="w-4 h-2 fill-t_text_primary">
128
- <ArrowDownIcon />
129
- </div>
130
- )}
151
+ )}
131
152
  </div>
153
+ {!locked && (
154
+ <div className="flex items-center justify-center w-6 h-6 fill-t_text_primary opacity-50 [&_svg]:w-3 [&_svg]:h-3">
155
+ <ChevronDownIcon />
156
+ </div>
157
+ )}
132
158
  </button>
133
159
  </>
134
160
  );
@@ -0,0 +1,27 @@
1
+ import { Skeleton } from "@src/components";
2
+ import { useSwapContext } from "@src/context";
3
+ import { useMemo } from "react";
4
+ import { SwapPanelType } from "../../../SwapView";
5
+
6
+ type Props = {
7
+ type: SwapPanelType;
8
+ };
9
+
10
+ export const UsdValue = ({ type }: Props) => {
11
+ const { srcValueUsd, dstValueUsd, isFetchingRoute } = useSwapContext();
12
+
13
+ const valueUsd = useMemo(
14
+ () => (type === "source" ? srcValueUsd : dstValueUsd),
15
+ [dstValueUsd, srcValueUsd, type],
16
+ );
17
+
18
+ if (type === "destination" && isFetchingRoute) {
19
+ return <Skeleton className="w-[80px] h-[16px]" />;
20
+ }
21
+
22
+ return (
23
+ <p className="text-[10px] leading-4 tracking-[0.01em] text-t_text_primary text-opacity-50 whitespace-nowrap">
24
+ {valueUsd ? `${valueUsd} USD` : ""}
25
+ </p>
26
+ );
27
+ };
@@ -1,7 +1,9 @@
1
+ import { ChevronDownIcon } from "@src/assets/icons";
1
2
  import { useWallet } from "@src/context/WalletProvider";
3
+ import { useSwapContext } from "@src/context";
2
4
  import { SwapPanelType } from "../..";
3
5
  import { Chain } from "@src/models";
4
- import { useCallback } from "react";
6
+ import { useCallback, useMemo } from "react";
5
7
  import { shortAddress } from "@src/utils";
6
8
 
7
9
  type Props = {
@@ -10,7 +12,7 @@ type Props = {
10
12
  className?: string;
11
13
  };
12
14
 
13
- export const WalletPanel = ({ chain, type, className }: Props) => {
15
+ export const WalletPanel = ({ chain, className }: Props) => {
14
16
  const {
15
17
  setOpenEVMWalletModal,
16
18
  setOpenSolanaWalletModal,
@@ -19,13 +21,33 @@ export const WalletPanel = ({ chain, type, className }: Props) => {
19
21
  solana,
20
22
  sui,
21
23
  } = useWallet();
24
+ const { integrationConfig, hasOnConnectWalletCallback, onConnectWallet } =
25
+ useSwapContext();
26
+
27
+ const openEvmWalletModal = useCallback(() => {
28
+ // Mirror SwapButton's contract: when the integrator supplied their own
29
+ // connect handler and did not opt into the built-in picker, defer to it
30
+ // (e.g. the host dapp's RainbowKit modal) instead of opening the SDK picker.
31
+ if (!integrationConfig.defaultWalletPicker && hasOnConnectWalletCallback) {
32
+ onConnectWallet();
33
+ return;
34
+ }
35
+ setOpenEVMWalletModal(true);
36
+ evm.connectWallet();
37
+ }, [
38
+ integrationConfig.defaultWalletPicker,
39
+ hasOnConnectWalletCallback,
40
+ onConnectWallet,
41
+ setOpenEVMWalletModal,
42
+ evm,
43
+ ]);
44
+
22
45
  const openWalletModal = useCallback(() => {
23
46
  if (!chain) {
24
47
  return;
25
48
  }
26
49
  if (chain.ecosystem === "evm") {
27
- setOpenEVMWalletModal(true);
28
- evm.connectWallet();
50
+ openEvmWalletModal();
29
51
  } else if (chain.ecosystem === "solana") {
30
52
  setOpenSolanaWalletModal(true);
31
53
  solana.connectWallet();
@@ -34,55 +56,44 @@ export const WalletPanel = ({ chain, type, className }: Props) => {
34
56
  }
35
57
  }, [
36
58
  chain,
37
- evm,
59
+ openEvmWalletModal,
38
60
  solana,
39
- setOpenEVMWalletModal,
40
61
  setOpenSolanaWalletModal,
41
62
  setOpenSuiWalletModal,
42
63
  ]);
43
- const renderAddress = useCallback(
44
- (chainEcosystem: string) => {
45
- if (chainEcosystem === "evm") {
46
- return shortAddress(evm.address || "");
47
- } else if (chainEcosystem === "solana") {
48
- return shortAddress(solana.address || "");
49
- } else if (chainEcosystem === "sui") {
50
- return shortAddress(sui.address || "");
51
- }
52
- },
53
- [evm, solana, sui],
54
- );
64
+
65
+ const address = useMemo(() => {
66
+ if (!chain) {
67
+ return "";
68
+ }
69
+ if (chain.ecosystem === "evm") {
70
+ return evm.address || "";
71
+ } else if (chain.ecosystem === "solana") {
72
+ return solana.address || "";
73
+ } else if (chain.ecosystem === "sui") {
74
+ return sui.address || "";
75
+ }
76
+ return "";
77
+ }, [chain, evm, solana, sui]);
78
+
79
+ if (!chain) {
80
+ return null;
81
+ }
82
+
55
83
  return (
56
- <>
57
- <button
58
- type="button"
59
- onClick={() => openWalletModal()}
60
- className={`${className || ""}`}
61
- >
62
- <div className="flex justify-between items-center p-4 gap-8">
63
- <div className="flex flex-col items-start">
64
- {type === "source" ? (
65
- <div className="flex items-center gap-2">
66
- <p className="text-xs font-medium opacity-60">Sender:</p>
67
- {chain && (
68
- <p className="text-sm font-medium">
69
- {renderAddress(chain.ecosystem)}
70
- </p>
71
- )}
72
- </div>
73
- ) : (
74
- <div className="flex items-center gap-2">
75
- <p className="text-xs font-medium opacity-60">Receiver:</p>
76
- {chain && (
77
- <p className="text-sm font-medium">
78
- {renderAddress(chain.ecosystem)}
79
- </p>
80
- )}
81
- </div>
82
- )}
83
- </div>
84
- </div>
85
- </button>
86
- </>
84
+ <button
85
+ type="button"
86
+ onClick={openWalletModal}
87
+ className={`flex items-center justify-center gap-0.5 px-2 py-1 rounded bg-t_bg_tertiary bg-opacity-5 hover:bg-opacity-10 transition-colors ${
88
+ className || ""
89
+ }`}
90
+ >
91
+ <p className="text-[10px] leading-4 tracking-[0.01em] text-t_text_primary whitespace-nowrap">
92
+ {address ? shortAddress(address) : "Connect"}
93
+ </p>
94
+ <div className="flex items-center justify-center w-4 h-4 fill-t_text_primary opacity-50 [&_svg]:w-2.5 [&_svg]:h-2.5">
95
+ <ChevronDownIcon />
96
+ </div>
97
+ </button>
87
98
  );
88
99
  };
@@ -2,9 +2,9 @@ import { useSwapContext } from "@src/context";
2
2
  import { useMemo } from "react";
3
3
  import { SwapPanelType } from "../index";
4
4
  import { AmountPanel } from "./AmountPanel";
5
- import { ChainPanel } from "./ChainPanel";
6
- import { MaxPanel } from "./MaxPanel";
5
+ import { Balance } from "./AmountPanel/Balance";
7
6
  import { TokenPanel } from "./TokenPanel";
7
+ import { UsdValue } from "./UsdValue";
8
8
  import { WalletPanel } from "./WalletPanel";
9
9
 
10
10
  type Props = {
@@ -24,31 +24,26 @@ export const SwapPanel = ({ type }: Props) => {
24
24
  );
25
25
 
26
26
  return (
27
- <div className="flex flex-col x-border rounded-xl bg-t_bg_tertiary bg-opacity-5">
28
- <div className="flex border-b border-solid border-t_text_primary border-opacity-10">
29
- <WalletPanel chain={chain} type={type} className="w-full flex-grow" />
27
+ <div
28
+ className={`flex flex-col gap-2 px-4 sm:px-6 py-4 rounded-2xl bg-t_bg_secondary bg-opacity-60 ${
29
+ type === "source"
30
+ ? "bg-gradient-to-r from-t_bg_tertiary/5 to-t_bg_tertiary/5 border border-solid border-t_text_primary border-opacity-10"
31
+ : "bg-gradient-to-r from-t_bg_tertiary/[0.03] to-t_bg_tertiary/[0.03]"
32
+ }`}
33
+ >
34
+ <div className="flex gap-2 items-center w-full">
35
+ <p className="text-[10px] leading-4 tracking-[0.01em] text-t_text_primary text-opacity-50">
36
+ {type === "source" ? "Source" : "Destination"}
37
+ </p>
38
+ <WalletPanel chain={chain} type={type} />
30
39
  </div>
31
- <div className="flex border-b border-solid border-t_text_primary border-opacity-10">
32
- <TokenPanel
33
- chain={chain}
34
- token={token}
35
- type={type}
36
- className="w-full flex-grow"
37
- />
38
- <ChainPanel
39
- chain={chain}
40
- type={type}
41
- className="w-full max-w-[160px]"
42
- />
43
- </div>
44
- <div
45
- className={`flex justify-between rounded-b-[11px] ${
46
- type === "destination" &&
47
- "bg-gradient-to-r from-t_main_accent_light/20 to-t_main_accent_dark/20"
48
- }`}
49
- >
40
+ <div className="flex items-center justify-between w-full gap-4">
50
41
  <AmountPanel type={type} />
51
- <MaxPanel type={type} />
42
+ <TokenPanel chain={chain} token={token} type={type} />
43
+ </div>
44
+ <div className="flex items-center justify-between w-full gap-4">
45
+ <UsdValue type={type} />
46
+ <Balance type={type} />
52
47
  </div>
53
48
  </div>
54
49
  );
@@ -169,7 +169,12 @@ export const WalletPicker: FC<{
169
169
  )}
170
170
  {ecosystem === Ecosystem.SOLANA && (
171
171
  <>
172
- {wallets.map((wallet) => {
172
+ {wallets
173
+ // MetaMask registers as a Wallet Standard Solana wallet (in more
174
+ // than one variant) but doesn't actually work here, so keep it out
175
+ // of the Solana picker entirely.
176
+ .filter((wallet) => !/metamask/i.test(wallet.adapter.name))
177
+ .map((wallet) => {
173
178
  const isConnected =
174
179
  publicKey && activeWallet?.adapter.name === wallet.adapter.name;
175
180
  return (
@@ -8,11 +8,12 @@ export type SwapPanelType = "source" | "destination";
8
8
  export const SwapView = () => {
9
9
  return (
10
10
  <div className="flex flex-col gap-6 fill-t_text_primary">
11
- <div className="flex flex-col gap-[11px]">
11
+ <div className="flex flex-col gap-1.5">
12
12
  <SwapPanel type="source" />
13
13
  <ReorderButton />
14
14
  <SwapPanel type="destination" />
15
15
  </div>
16
+ <div className="h-px w-full gradient-sections-separator-container" />
16
17
  <FeesPanel />
17
18
  <SwapButton />
18
19
  </div>
@@ -1,3 +1,4 @@
1
+ import { PoweredBy } from "@src/components/PoweredBy";
1
2
  import { useSwapContext } from "@src/context";
2
3
  import { useMemo } from "react";
3
4
  import { Header } from "./Header";
@@ -25,10 +26,11 @@ export const Swap = ({ onClose }: Props) => {
25
26
 
26
27
  return (
27
28
  <div
28
- className={`relative flex flex-col gap-4 p-2 text-t_text_primary bg-t_bg_primary rounded-2xl flex-1`}
29
+ className={`relative flex flex-col gap-6 p-5 sm:p-6 text-t_text_primary bg-t_bg_secondary bg-opacity-50 backdrop-blur-[12px] rounded-[20px] border border-solid border-t_text_primary border-opacity-10 flex-1`}
29
30
  >
30
31
  <Header onClose={onClose} />
31
- {view}
32
+ <div className="flex flex-col flex-1 min-h-0">{view}</div>
33
+ <PoweredBy />
32
34
  </div>
33
35
  );
34
36
  };
@@ -5,22 +5,25 @@ type Props = {
5
5
 
6
6
  const ToggleButton = ({ checked, onClick }: Props) => {
7
7
  return (
8
- <div>
8
+ <button
9
+ type="button"
10
+ role="switch"
11
+ aria-checked={checked}
12
+ onClick={onClick}
13
+ className={`relative inline-flex items-center w-12 h-6 p-[3px] rounded-full cursor-pointer transition-colors border-none ${
14
+ checked
15
+ ? "bg-gradient-to-r from-t_main_accent_light/40 to-t_main_accent_dark/60"
16
+ : "bg-t_bg_tertiary bg-opacity-10"
17
+ }`}
18
+ >
9
19
  <span
10
- className="inline-flex w-14 h-9 p-3 relative align-middle box-border overflow-hidden cursor-pointer"
11
- onClick={onClick}
12
- >
13
- <span className="h-full w-full rounded-lg bg-t_bg_tertiary bg-opacity-30"></span>
14
- <span
15
- className={`transition-all w-5 h-5 rounded-full absolute translate-y-[-4px]
16
- ${
17
- checked
18
- ? "translate-x-[12px] bg-t_main_accent_light"
19
- : "bg-t_bg_tertiary"
20
- } `}
21
- ></span>
22
- </span>
23
- </div>
20
+ className={`w-[18px] h-[18px] rounded-full transition-transform ${
21
+ checked
22
+ ? "translate-x-6 bg-t_main_accent_light"
23
+ : "translate-x-0 bg-t_text_primary opacity-40"
24
+ }`}
25
+ ></span>
26
+ </button>
24
27
  );
25
28
  };
26
29
 
@@ -1,4 +1,4 @@
1
- import { PoweredBy, Swap } from "@src/components";
1
+ import { Swap } from "@src/components";
2
2
  import { getWagmiConfig, waitForInitialization, xpayRoot } from "@src/config";
3
3
  import {
4
4
  HistoryProvider,
@@ -87,6 +87,7 @@ export const TxConfigForm = (props: TxConfigFormProps) => {
87
87
  srcTokenAddr,
88
88
  customContractCalls,
89
89
  desc,
90
+ widgetTitle,
90
91
  dstDisplayTokenAddr,
91
92
  supportedChains,
92
93
  onSubmit,
@@ -161,6 +162,7 @@ export const TxConfigForm = (props: TxConfigFormProps) => {
161
162
  srcTokenAddr,
162
163
  customContractCalls,
163
164
  desc,
165
+ widgetTitle,
164
166
  dstDisplayTokenAddr,
165
167
  defaultWalletPicker,
166
168
  dstTokenLocked,
@@ -187,15 +189,13 @@ export const TxConfigForm = (props: TxConfigFormProps) => {
187
189
  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"
188
190
  onMouseDown={onBackdropClick}
189
191
  >
190
- <div className="relative bg-t_bg_primary rounded-2xl overflow-auto text-t_text_primary border-[1px] border-solid border-[rgba(255,255,255,0.1)] w-x_modal min-w-x_modal max-w-x_modal min-h-[532px]">
192
+ <div className="relative rounded-[20px] overflow-auto text-t_text_primary w-x_modal min-w-x_modal max-w-x_modal min-h-[532px] flex flex-col">
191
193
  <Swap onSubmit={onSubmit} onClose={onClose} />
192
- <PoweredBy />
193
194
  </div>
194
195
  </div>
195
196
  ) : (
196
- <div className="bg-t_bg_primary rounded-2xl overflow-auto text-t_text_primary border-[1px] border-solid border-[rgba(255,255,255,0.1)] min-h-[532px] w-x_modal min-w-x_modal max-w-x_modal flex flex-col">
197
+ <div className="rounded-[20px] overflow-auto text-t_text_primary min-h-[532px] w-x_modal min-w-x_modal max-w-x_modal flex flex-col">
197
198
  <Swap onSubmit={() => {}} onClose={() => {}} />
198
- <PoweredBy />
199
199
  </div>
200
200
  )}
201
201
  </TxUIWrapper>
@@ -21,6 +21,7 @@ const TxWidget = ({
21
21
  srcToken: srcTokenId,
22
22
  customContractCalls = [],
23
23
  desc,
24
+ widgetTitle,
24
25
  dstDisplayToken,
25
26
  lightTheme,
26
27
  defaultWalletPicker,
@@ -116,6 +117,7 @@ const TxWidget = ({
116
117
  srcTokenAddr={srcTokenAddr}
117
118
  customContractCalls={customContractCalls}
118
119
  desc={desc}
120
+ widgetTitle={widgetTitle}
119
121
  dstDisplayTokenAddr={dstDisplayToken}
120
122
  supportedChains={supportedChains}
121
123
  overlay={false}
@@ -166,6 +168,7 @@ export const createTxWidgetWC = () => {
166
168
  srcToken: "string",
167
169
  customContractCalls: "json",
168
170
  desc: "string",
171
+ widgetTitle: "string",
169
172
  dstDisplayToken: "string",
170
173
  lightTheme: "boolean",
171
174
  defaultWalletPicker: "boolean",
@@ -204,6 +207,7 @@ export type TxWidgetWCAttributes = {
204
207
  "src-token": WidgetIntegrationPayload["srcToken"];
205
208
  "custom-contract-calls": string | undefined;
206
209
  desc: WidgetIntegrationPayload["desc"];
210
+ "widget-title": WidgetIntegrationPayload["widgetTitle"];
207
211
  "dst-display-token": WidgetIntegrationPayload["dstDisplayToken"];
208
212
  "light-theme": WidgetIntegrationPayload["lightTheme"];
209
213
  "default-wallet-picker": WidgetIntegrationPayload["defaultWalletPicker"];
@@ -32,6 +32,7 @@ export const TxWidgetWCWrapped = ({
32
32
  srcToken,
33
33
  customContractCalls = [],
34
34
  desc,
35
+ widgetTitle,
35
36
  dstDisplayToken,
36
37
  lightTheme,
37
38
  defaultWalletPicker,
@@ -85,6 +86,7 @@ export const TxWidgetWCWrapped = ({
85
86
  src-token={srcToken}
86
87
  custom-contract-calls={JSON.stringify(customContractCalls)}
87
88
  desc={desc}
89
+ widget-title={widgetTitle}
88
90
  dst-display-token={dstDisplayToken}
89
91
  light-theme={lightTheme}
90
92
  default-wallet-picker={defaultWalletPicker}
@@ -230,6 +230,7 @@ export const HistoryProvider = ({ children }: HistoryProviderProps) => {
230
230
 
231
231
  fetchedTransactions.push({
232
232
  messageId: entry.messageId,
233
+ receiver: entry.walletAddress,
233
234
  hash: entry.source.transactionHash,
234
235
  timestamp: timestampMs / 1000,
235
236
  sourceChainId: entry.source.blockchainId,
@@ -43,6 +43,7 @@ export type TransactionStatus =
43
43
 
44
44
  export type Transaction = {
45
45
  messageId?: string;
46
+ receiver?: string;
46
47
  hash: string;
47
48
  timestamp: number;
48
49
  sourceChainId: string;
@@ -47,6 +47,7 @@ export type ModalIntegrationPayload = {
47
47
  srcToken?: string;
48
48
  customContractCalls?: ContractCall[];
49
49
  desc?: string;
50
+ widgetTitle?: string;
50
51
  dstDisplayToken?: string;
51
52
  lightTheme?: boolean;
52
53
  defaultWalletPicker?: boolean;
@@ -9,6 +9,7 @@ export type WidgetIntegrationPayload = {
9
9
  srcToken?: string;
10
10
  customContractCalls?: ContractCall[];
11
11
  desc?: string;
12
+ widgetTitle?: string;
12
13
  dstDisplayToken?: string;
13
14
  lightTheme?: boolean;
14
15
  defaultWalletPicker?: boolean;
@@ -77,6 +77,27 @@ export const resolveTokenAddress = (
77
77
  ?.address?.toLowerCase();
78
78
  };
79
79
 
80
+ /**
81
+ * Checks whether a transfer from `srcChain` can reach `dstChainId`,
82
+ * based on the chain-level support lists.
83
+ */
84
+ export const isChainConnectionSupported = (
85
+ srcChain: Chain | undefined,
86
+ dstChainId: string | undefined,
87
+ bridgeUI: boolean,
88
+ ): boolean => {
89
+ if (!srcChain || !dstChainId) {
90
+ return true;
91
+ }
92
+ if (srcChain.chainId === dstChainId) {
93
+ return true;
94
+ }
95
+ const supportedDst = bridgeUI
96
+ ? srcChain.supportedDstForBridge
97
+ : srcChain.supportedDstForSwap;
98
+ return !!supportedDst?.includes(dstChainId);
99
+ };
100
+
80
101
  export const sortChains = (chains: Chain[], disabledChainIds: string[]) =>
81
102
  [...chains]
82
103
 
@@ -96,10 +96,10 @@ export default {
96
96
  x_modal: "var(--modal-width, 340px)",
97
97
  },
98
98
  width: {
99
- x_modal: "var(--modal-width)",
99
+ x_modal: "var(--modal-width, 620px)",
100
100
  },
101
101
  maxWidth: {
102
- x_modal: "var(--modal-width, 480px)",
102
+ x_modal: "var(--modal-width, 620px)",
103
103
  },
104
104
  animation: {
105
105
  "spin-slow": "spin 3s linear infinite",