@xswap-link/sdk 0.14.1 → 0.15.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 +6 -0
  2. package/dist/index.global.js +92 -92
  3. package/dist/index.js +1799 -1725
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +1752 -1681
  6. package/dist/index.mjs.map +1 -1
  7. package/localTheme.ts +1 -1
  8. package/package.json +1 -1
  9. package/src/assets/icons/ChainlinkMarkIcon.tsx +4 -5
  10. package/src/assets/icons/CheckCircleThinIcon.tsx +22 -0
  11. package/src/assets/icons/ChevronDownThinIcon.tsx +39 -0
  12. package/src/assets/icons/ChevronDownWideThinIcon.tsx +18 -0
  13. package/src/assets/icons/ChevronsUpDownThinIcon.tsx +21 -0
  14. package/src/assets/icons/CloseIcon.tsx +3 -2
  15. package/src/assets/icons/ErrorCircleThinIcon.tsx +22 -0
  16. package/src/assets/icons/LinkExternalThinIcon.tsx +19 -0
  17. package/src/assets/icons/LoadingRingIcon.tsx +22 -0
  18. package/src/assets/icons/ProgressRingThinIcon.tsx +29 -0
  19. package/src/assets/icons/SearchThinIcon.tsx +15 -0
  20. package/src/assets/icons/SignThinIcon.tsx +15 -0
  21. package/src/assets/icons/WalletCheckThinIcon.tsx +24 -0
  22. package/src/assets/icons/index.ts +11 -0
  23. package/src/components/PoweredBy/index.tsx +1 -1
  24. package/src/components/Swap/Header/index.tsx +2 -4
  25. package/src/components/Swap/HistoryView/ActivityCard/index.tsx +110 -115
  26. package/src/components/Swap/HistoryView/index.tsx +10 -7
  27. package/src/components/Swap/ReorderButton/ReorderButton.tsx +4 -4
  28. package/src/components/Swap/SettingsView/Delivery/index.tsx +19 -17
  29. package/src/components/Swap/SettingsView/InfiniteApproval/index.tsx +19 -17
  30. package/src/components/Swap/SettingsView/Slippage/index.tsx +55 -49
  31. package/src/components/Swap/SwapView/ConfirmationView/TokenTiles/index.tsx +69 -0
  32. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/Header/index.tsx +13 -25
  33. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/Steps/index.tsx +65 -113
  34. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/index.tsx +19 -23
  35. package/src/components/Swap/SwapView/ConfirmationView/TxResult/index.tsx +51 -74
  36. package/src/components/Swap/SwapView/FeesPanel/index.tsx +4 -4
  37. package/src/components/Swap/SwapView/SwapButton/index.tsx +0 -29
  38. package/src/components/Swap/SwapView/SwapPanel/AmountPanel/index.tsx +2 -2
  39. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/ChainPicker/index.tsx +3 -3
  40. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/NetworkFilter/index.tsx +17 -16
  41. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/TokenPicker/index.tsx +91 -40
  42. package/src/components/Swap/SwapView/SwapPanel/TokenPanel/index.tsx +4 -4
  43. package/src/components/Swap/SwapView/SwapPanel/UsdValue/index.tsx +2 -2
  44. package/src/components/Swap/SwapView/SwapPanel/WalletPanel/index.tsx +10 -16
  45. package/src/components/Swap/SwapView/SwapPanel/index.tsx +3 -3
  46. package/src/components/Swap/SwapView/WalletPicker/index.tsx +131 -139
  47. package/src/components/Swap/SwapView/index.tsx +11 -7
  48. package/src/components/Swap/WalletPickerView/index.tsx +65 -0
  49. package/src/components/Swap/index.tsx +23 -6
  50. package/src/components/ToggleButton/index.tsx +5 -7
  51. package/src/components/TokenLogo/index.tsx +1 -1
  52. package/src/components/TxModal/index.tsx +14 -4
  53. package/src/components/global.css +18 -1
  54. package/src/constants/index.ts +4 -0
  55. package/src/context/SwapProvider.tsx +106 -19
  56. package/src/utils/validation.ts +9 -4
  57. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/ArrowIcon.tsx +0 -13
  58. package/src/components/Swap/SwapView/ConfirmationView/TxOverview/SwapPanel/index.tsx +0 -72
  59. package/src/components/Swap/SwapView/ConfirmationView/TxResult/TokenItem/index.tsx +0 -25
@@ -4,7 +4,7 @@ import {
4
4
  DotRedIcon,
5
5
  WalletConnectIcon,
6
6
  } from "@src/assets/icons";
7
- import { FC, useCallback } from "react";
7
+ import { FC, ReactNode, useCallback } from "react";
8
8
  import { Connector, useAccount, useConnect, useDisconnect } from "wagmi";
9
9
  import { useWallet as useSolanaWallet } from "@solana/wallet-adapter-react";
10
10
  import { Ecosystem } from "@src/models";
@@ -24,7 +24,7 @@ const ConnectorIcon: FC<{ connector: Connector; className?: string }> = ({
24
24
  case "WalletConnect": {
25
25
  return (
26
26
  <WalletConnectIcon
27
- className={`w-[34px] h-[34px] rounded-md ${className || ""}`}
27
+ className={`w-10 h-10 rounded-lg shrink-0 ${className || ""}`}
28
28
  />
29
29
  );
30
30
  }
@@ -33,13 +33,50 @@ const ConnectorIcon: FC<{ connector: Connector; className?: string }> = ({
33
33
  <img
34
34
  src={connector.icon}
35
35
  alt={connector.name}
36
- className={`w-[34px] h-[34px] rounded-md ${className || ""}`}
36
+ className={`w-10 h-10 rounded-lg shrink-0 ${className || ""}`}
37
37
  />
38
38
  );
39
39
  }
40
40
  }
41
41
  };
42
42
 
43
+ /** Wallet list row styled after the ChainPicker/TokenItem rows. */
44
+ const WalletRow: FC<{
45
+ icon: ReactNode;
46
+ name: string;
47
+ isConnected: boolean;
48
+ onClick: () => void;
49
+ }> = ({ icon, name, isConnected, onClick }) => (
50
+ <div className="pb-2">
51
+ <button
52
+ type="button"
53
+ onClick={onClick}
54
+ className={`group flex gap-3 items-center w-full p-3 sm:p-4 rounded-xl cursor-pointer bg-gradient-to-r from-t_bg_tertiary/[0.02] to-t_bg_tertiary/[0.02] bg-[rgba(40,40,40,0.15)] hover:bg-t_bg_tertiary hover:bg-opacity-10 transition-colors ${
55
+ isConnected ? "!bg-t_bg_tertiary !bg-opacity-10" : ""
56
+ }`}
57
+ >
58
+ {icon}
59
+ <div className="flex justify-between items-center gap-2 w-full min-w-0">
60
+ <p className="text-sm font-medium leading-5 tracking-[0.01em] text-t_text_primary text-left">
61
+ {name}
62
+ </p>
63
+ {isConnected && (
64
+ <span className="flex items-center gap-1.5 text-xs leading-[18px] tracking-[0.01em] whitespace-nowrap">
65
+ <span className="group-hover:hidden flex items-center gap-1.5 text-t_text_green">
66
+ <DotGreenIcon />
67
+ Connected
68
+ </span>
69
+ <span className="hidden group-hover:flex items-center gap-1.5 text-t_text_red">
70
+ <DotRedIcon />
71
+ Disconnect
72
+ </span>
73
+ </span>
74
+ )}
75
+ </div>
76
+ </button>
77
+ </div>
78
+ );
79
+
43
80
  export const WalletPicker: FC<{
44
81
  ecosystem: Ecosystem;
45
82
  className?: string;
@@ -114,167 +151,122 @@ export const WalletPicker: FC<{
114
151
  }
115
152
  }, [disconnectSuiWalletMut, onClose]);
116
153
 
154
+ // The host's wagmi config may register the same connector more than once
155
+ // (e.g. WalletConnect via several RainbowKit wallets) — show each name once.
156
+ const visibleConnectors = connectors.filter(
157
+ (connector, index) =>
158
+ connectors.findIndex(({ name }) => name === connector.name) === index,
159
+ );
160
+
161
+ const visibleSolanaWallets = wallets
162
+ // MetaMask registers as a Wallet Standard Solana wallet (in more
163
+ // than one variant) but doesn't actually work here, so keep it out
164
+ // of the Solana picker entirely.
165
+ .filter((wallet) => !/metamask/i.test(wallet.adapter.name));
166
+
117
167
  return (
118
- <div className={`flex flex-col h-full ${className || ""}`}>
119
- <div className="flex justify-between">
120
- <div className="text-base/4 mb-4 text-t_text_primary">Pick wallet</div>
121
- <div
122
- className="w-4 h-4 fill-t_text_primary cursor-pointer"
168
+ <div className={`flex flex-col h-full min-h-0 ${className || ""}`}>
169
+ <div className="flex justify-between items-center mb-6">
170
+ <div className="text-2xl leading-8 tracking-[0.01em] text-t_text_primary">
171
+ Select Wallet
172
+ </div>
173
+ <button
174
+ type="button"
175
+ aria-label="Close"
176
+ className="flex items-center justify-center w-8 h-8 rounded-md bg-t_bg_tertiary bg-opacity-5 hover:bg-opacity-10 transition-colors"
123
177
  onClick={onClose}
124
178
  >
125
- <CloseIcon />
126
- </div>
179
+ <div className="w-4 h-4 opacity-50 fill-t_text_primary flex items-center justify-center">
180
+ <CloseIcon />
181
+ </div>
182
+ </button>
127
183
  </div>
128
- <div className="horizontal-separator" />
129
- <div className="h-full pt-4">
130
- {ecosystem === Ecosystem.EVM && (
131
- <>
132
- {connectors.map((connector) => {
133
- const isConnected = activeConnector?.id === connector.id;
134
- return (
135
- <button
136
- key={connector.id}
137
- onClick={async () => {
138
- isConnected
139
- ? disconnect()
140
- : await handleEvmWalletClick(connector);
141
- onClose();
142
- }}
143
- className="group flex items-center w-full gap-3 mt-2 mb-2 cursor-pointer p-4 border border-solid border-white border-opacity-0 hover:selected-wallet-item"
144
- >
145
- <ConnectorIcon connector={connector} />
146
- <div className="text-t_text_primary">{connector.name}</div>
147
- {isConnected && (
148
- <>
149
- <div className="flex w-full justify-end items-baseline gap-1">
150
- <div className="group-hover:hidden">
151
- <DotGreenIcon />
152
- </div>
153
- <div className="hidden group-hover:block">
154
- <DotRedIcon />
155
- </div>
156
- <div className="text-t_text_green group-hover:hidden">
157
- connected
158
- </div>
159
- <div className="text-t_text_red hidden group-hover:block">
160
- disconnect
161
- </div>
162
- </div>
163
- </>
164
- )}
165
- </button>
166
- );
167
- })}
168
- </>
169
- )}
170
- {ecosystem === Ecosystem.SOLANA && (
171
- <>
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) => {
184
+ <div className="flex flex-col flex-1 min-h-0 overflow-y-auto">
185
+ {ecosystem === Ecosystem.EVM &&
186
+ visibleConnectors.map((connector) => {
187
+ const isConnected = activeConnector?.id === connector.id;
188
+ return (
189
+ <WalletRow
190
+ key={connector.id}
191
+ icon={<ConnectorIcon connector={connector} />}
192
+ name={connector.name}
193
+ isConnected={isConnected}
194
+ onClick={async () => {
195
+ isConnected
196
+ ? disconnect()
197
+ : await handleEvmWalletClick(connector);
198
+ onClose();
199
+ }}
200
+ />
201
+ );
202
+ })}
203
+ {ecosystem === Ecosystem.SOLANA &&
204
+ (visibleSolanaWallets.length ? (
205
+ visibleSolanaWallets.map((wallet) => {
178
206
  const isConnected =
179
- publicKey && activeWallet?.adapter.name === wallet.adapter.name;
207
+ !!publicKey &&
208
+ activeWallet?.adapter.name === wallet.adapter.name;
180
209
  return (
181
- <button
210
+ <WalletRow
182
211
  key={wallet.adapter.name}
212
+ icon={
213
+ <img
214
+ src={wallet.adapter.icon}
215
+ alt={wallet.adapter.name}
216
+ className="w-10 h-10 rounded-lg shrink-0"
217
+ />
218
+ }
219
+ name={wallet.adapter.name}
220
+ isConnected={isConnected}
183
221
  onClick={async () => {
184
222
  isConnected
185
223
  ? await disconnectSolana()
186
224
  : await handleConnectSolana(wallet.adapter.name);
187
225
  onClose();
188
226
  }}
189
- className="group flex items-center w-full gap-3 mt-2 mb-2 cursor-pointer p-4 border border-solid border-white border-opacity-0 hover:selected-wallet-item"
190
- >
191
- <img
192
- src={wallet.adapter.icon}
193
- alt={wallet.adapter.name}
194
- className={`w-[34px] h-[34px] rounded-md ${
195
- className || ""
196
- }`}
197
- />
198
- <div className="text-t_text_primary">
199
- {wallet.adapter.name}
200
- </div>
201
- {isConnected && (
202
- <>
203
- <div className="flex w-full justify-end items-baseline gap-1">
204
- <div className="group-hover:hidden">
205
- <DotGreenIcon />
206
- </div>
207
- <div className="hidden group-hover:block">
208
- <DotRedIcon />
209
- </div>
210
- <div className="text-t_text_green group-hover:hidden">
211
- connected
212
- </div>
213
- <div className="text-t_text_red hidden group-hover:block">
214
- disconnect
215
- </div>
216
- </div>
217
- </>
218
- )}
219
- </button>
227
+ />
220
228
  );
221
- })}
222
- </>
223
- )}
224
- {ecosystem === Ecosystem.SUI && (
225
- <>
226
- {suiWallets.map((wallet) => {
229
+ })
230
+ ) : (
231
+ <div className="text-center py-1 text-sm text-t_text_primary text-opacity-50">
232
+ No wallet found
233
+ </div>
234
+ ))}
235
+ {ecosystem === Ecosystem.SUI &&
236
+ (suiWallets.length ? (
237
+ suiWallets.map((wallet) => {
227
238
  const isConnected =
228
239
  !!suiAccount?.address &&
229
240
  suiCurrentWallet?.currentWallet?.name === wallet.name;
230
-
231
- const icon = wallet.icon;
232
-
233
241
  return (
234
- <button
242
+ <WalletRow
235
243
  key={wallet.name}
244
+ icon={
245
+ wallet.icon ? (
246
+ <img
247
+ src={wallet.icon}
248
+ alt={wallet.name}
249
+ className="w-10 h-10 rounded-lg shrink-0"
250
+ />
251
+ ) : (
252
+ <div className="w-10 h-10 rounded-lg shrink-0 bg-t_bg_tertiary bg-opacity-10" />
253
+ )
254
+ }
255
+ name={wallet.name}
256
+ isConnected={isConnected}
236
257
  onClick={async () => {
237
258
  isConnected
238
259
  ? await handleDisconnectSui()
239
260
  : await handleConnectSui(wallet);
240
261
  }}
241
- className="group flex items-center w-full gap-3 mt-2 mb-2 cursor-pointer p-4 border border-solid border-white border-opacity-0 hover:selected-wallet-item"
242
- >
243
- {icon ? (
244
- <img
245
- src={icon}
246
- alt={wallet.name}
247
- className={`w-[34px] h-[34px] rounded-md ${
248
- className || ""
249
- }`}
250
- />
251
- ) : (
252
- <div className="w-[34px] h-[34px] rounded-md bg-white/10" />
253
- )}
254
-
255
- <div className="text-t_text_primary">{wallet.name}</div>
256
-
257
- {isConnected && (
258
- <div className="flex w-full justify-end items-baseline gap-1">
259
- <div className="group-hover:hidden">
260
- <DotGreenIcon />
261
- </div>
262
- <div className="hidden group-hover:block">
263
- <DotRedIcon />
264
- </div>
265
- <div className="text-t_text_green group-hover:hidden">
266
- connected
267
- </div>
268
- <div className="text-t_text_red hidden group-hover:block">
269
- disconnect
270
- </div>
271
- </div>
272
- )}
273
- </button>
262
+ />
274
263
  );
275
- })}
276
- </>
277
- )}
264
+ })
265
+ ) : (
266
+ <div className="text-center py-1 text-sm text-t_text_primary text-opacity-50">
267
+ No wallet found
268
+ </div>
269
+ ))}
278
270
  </div>
279
271
  </div>
280
272
  );
@@ -7,14 +7,18 @@ export type SwapPanelType = "source" | "destination";
7
7
 
8
8
  export const SwapView = () => {
9
9
  return (
10
- <div className="flex flex-col gap-6 fill-t_text_primary">
11
- <div className="flex flex-col gap-1.5">
12
- <SwapPanel type="source" />
13
- <ReorderButton />
14
- <SwapPanel type="destination" />
10
+ <div className="flex flex-col gap-8 fill-t_text_primary">
11
+ <div className="flex flex-col gap-6">
12
+ {/* ReorderButton is a zero-height anchor between the panels, so the
13
+ flex gap applies twice — 6px above and below it, 12px total. */}
14
+ <div className="flex flex-col gap-1.5">
15
+ <SwapPanel type="source" />
16
+ <ReorderButton />
17
+ <SwapPanel type="destination" />
18
+ </div>
19
+ <div className="h-px w-full gradient-sections-separator-container" />
20
+ <FeesPanel />
15
21
  </div>
16
- <div className="h-px w-full gradient-sections-separator-container" />
17
- <FeesPanel />
18
22
  <SwapButton />
19
23
  </div>
20
24
  );
@@ -0,0 +1,65 @@
1
+ import { Ecosystem } from "@src/models";
2
+ import { useWallet } from "@src/context/WalletProvider";
3
+ import { WalletPicker } from "../SwapView/WalletPicker";
4
+
5
+ /**
6
+ * Wallet picker rendered while one of the wallet modals is open, presented
7
+ * exactly like PickerView:
8
+ * - sm and up it replaces the swap view inside the widget container, so it
9
+ * sits on the exact same glass background,
10
+ * - below sm the same element becomes a bottom sheet pinned to the viewport.
11
+ */
12
+ export const WalletPickerView = () => {
13
+ const {
14
+ openEVMWalletModal,
15
+ setOpenEVMWalletModal,
16
+ openSolanaWalletModal,
17
+ setOpenSolanaWalletModal,
18
+ openSuiWalletModal,
19
+ setOpenSuiWalletModal,
20
+ } = useWallet();
21
+
22
+ const ecosystem = openEVMWalletModal
23
+ ? Ecosystem.EVM
24
+ : openSolanaWalletModal
25
+ ? Ecosystem.SOLANA
26
+ : openSuiWalletModal
27
+ ? Ecosystem.SUI
28
+ : null;
29
+
30
+ const close = () => {
31
+ setOpenEVMWalletModal(false);
32
+ setOpenSolanaWalletModal(false);
33
+ setOpenSuiWalletModal(false);
34
+ };
35
+
36
+ if (!ecosystem) {
37
+ return null;
38
+ }
39
+
40
+ return (
41
+ <div
42
+ className="fixed top-0 left-0 right-0 bottom-0 z-10 flex flex-col justify-end bg-[rgba(2,2,2,0.8)] sm:absolute sm:z-[2] sm:justify-start sm:bg-transparent"
43
+ onMouseDown={(e) => {
44
+ if (e.target === e.currentTarget) {
45
+ e.stopPropagation();
46
+ e.nativeEvent.stopImmediatePropagation();
47
+ e.preventDefault();
48
+ close();
49
+ }
50
+ }}
51
+ >
52
+ <div className="flex flex-col w-full h-[85vh] max-h-full overflow-hidden p-4 pt-2.5 rounded-t-[24px] border-t border-solid border-t_text_primary border-opacity-10 bg-gradient-to-r from-t_bg_secondary/50 to-t_bg_secondary/50 bg-t_bg_primary sm:h-full sm:p-0 sm:rounded-none sm:border-0 sm:bg-none sm:bg-transparent">
53
+ <div className="sm:hidden mx-auto mb-4 h-1 w-8 rounded-full bg-t_bg_tertiary bg-opacity-10 shrink-0" />
54
+ <WalletPicker ecosystem={ecosystem} onClose={close} />
55
+ </div>
56
+ </div>
57
+ );
58
+ };
59
+
60
+ /** True while any of the wallet picker modals is requested open. */
61
+ export const useWalletPickerOpen = () => {
62
+ const { openEVMWalletModal, openSolanaWalletModal, openSuiWalletModal } =
63
+ useWallet();
64
+ return openEVMWalletModal || openSolanaWalletModal || openSuiWalletModal;
65
+ };
@@ -6,6 +6,7 @@ import { HistoryView } from "./HistoryView";
6
6
  import { PickerView } from "./PickerView";
7
7
  import { SettingsView } from "./SettingsView";
8
8
  import { SwapView } from "./SwapView";
9
+ import { WalletPickerView, useWalletPickerOpen } from "./WalletPickerView";
9
10
  import { UnifiedRoute } from "@src/models";
10
11
 
11
12
  type Props = {
@@ -14,15 +15,14 @@ type Props = {
14
15
  };
15
16
  export const Swap = ({ onClose }: Props) => {
16
17
  const { tab, activePicker } = useSwapContext();
18
+ const walletPickerOpen = useWalletPickerOpen();
17
19
 
18
- const view = useMemo(() => {
20
+ const overlayView = useMemo(() => {
19
21
  return tab === "Settings" ? (
20
22
  <SettingsView />
21
23
  ) : tab === "History" ? (
22
24
  <HistoryView />
23
- ) : (
24
- <SwapView />
25
- );
25
+ ) : null;
26
26
  }, [tab]);
27
27
 
28
28
  return (
@@ -35,13 +35,30 @@ export const Swap = ({ onClose }: Props) => {
35
35
  defining the widget height for the picker to fill. */}
36
36
  <div className="relative flex flex-col flex-1 min-h-0">
37
37
  {activePicker && <PickerView />}
38
+ <WalletPickerView />
38
39
  <div
39
40
  className={`flex flex-col gap-6 flex-1 min-h-0 ${
40
- activePicker ? "sm:invisible" : ""
41
+ activePicker || walletPickerOpen ? "sm:invisible" : ""
41
42
  }`}
42
43
  >
43
44
  <Header onClose={onClose} />
44
- <div className="flex flex-col flex-1 min-h-0">{view}</div>
45
+ {/* SwapView stays in the layout on every tab (visibility only), so
46
+ it keeps defining one shared widget height; Settings/History
47
+ render as an overlay filling that height. */}
48
+ <div className="relative flex flex-col flex-1 min-h-0">
49
+ <div
50
+ className={`flex flex-col flex-1 min-h-0 ${
51
+ overlayView ? "invisible" : ""
52
+ }`}
53
+ >
54
+ <SwapView />
55
+ </div>
56
+ {overlayView && (
57
+ <div className="absolute inset-0 flex flex-col min-h-0">
58
+ {overlayView}
59
+ </div>
60
+ )}
61
+ </div>
45
62
  </div>
46
63
  </div>
47
64
  <PoweredBy />
@@ -10,17 +10,15 @@ const ToggleButton = ({ checked, onClick }: Props) => {
10
10
  role="switch"
11
11
  aria-checked={checked}
12
12
  onClick={onClick}
13
- className={`relative inline-flex items-center w-12 h-6 p-[3px] rounded-full cursor-pointer transition-colors border-none ${
13
+ className={`relative inline-flex items-center w-10 h-5 p-0.5 rounded-full cursor-pointer transition-opacity border-none bg-gradient-to-r ${
14
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"
15
+ ? "from-t_main_accent_light/25 to-t_main_accent_dark/25"
16
+ : "from-t_main_accent_light/20 to-t_main_accent_dark/20 opacity-50"
17
17
  }`}
18
18
  >
19
19
  <span
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"
20
+ className={`w-4 h-4 rounded-full transition-transform bg-gradient-to-r from-t_main_accent_light to-t_main_accent_dark ${
21
+ checked ? "translate-x-5" : "translate-x-0"
24
22
  }`}
25
23
  ></span>
26
24
  </button>
@@ -32,7 +32,7 @@ export const TokenLogo = ({
32
32
  <img
33
33
  src={token.image}
34
34
  alt={token.name}
35
- className={`border border-solid border-t_text_primary border-opacity-10 rounded-2xl ${className}`}
35
+ className={`rounded-full ${className}`}
36
36
  onError={() => setErrorOccured(true)}
37
37
  />
38
38
  ) : (
@@ -38,11 +38,11 @@ export const TxModal = ({
38
38
  onMouseDown={onBackdropClick}
39
39
  >
40
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 ${
41
+ className={`relative rounded-[32px] p-6 sm:p-8 w-full min-w-[340px] overflow-auto max-w-x_modal backdrop-blur-[32px] bg-t_bg_secondary bg-opacity-75 border border-solid ${
42
42
  type === "error"
43
- ? "border-t_error_dark"
43
+ ? "border-[#F44336]"
44
44
  : type === "success"
45
- ? "border-t_success_dark"
45
+ ? "border-[#6AE89B]"
46
46
  : type === "warning"
47
47
  ? "border-t_warning_dark"
48
48
  : type === "waiting"
@@ -50,7 +50,17 @@ export const TxModal = ({
50
50
  : "border-t_text_primary border-opacity-10"
51
51
  } ${className}`}
52
52
  >
53
- {children}
53
+ {(type === "error" || type === "success") && (
54
+ <div
55
+ aria-hidden
56
+ className={`absolute inset-0 rounded-[inherit] pointer-events-none ${
57
+ type === "error"
58
+ ? "tx-modal-glow-error"
59
+ : "tx-modal-glow-success"
60
+ }`}
61
+ />
62
+ )}
63
+ <div className="relative">{children}</div>
54
64
  </div>
55
65
  </div>,
56
66
  xpayShadowRoot!,
@@ -36,13 +36,30 @@
36
36
  }
37
37
 
38
38
  .gradient-sections-separator-container {
39
- @apply bg-gradient-to-r from-transparent via-t_bg_tertiary/25 to-transparent;
39
+ @apply bg-gradient-to-r from-transparent via-t_bg_tertiary/10 to-transparent;
40
40
  }
41
41
 
42
42
  .x-border {
43
43
  @apply border border-solid border-t_text_primary border-opacity-10;
44
44
  }
45
45
 
46
+ /* Corner glow of the transaction result modal, fading towards the center */
47
+ .tx-modal-glow-success {
48
+ background: radial-gradient(
49
+ 120% 60% at 0% 0%,
50
+ rgba(76, 175, 80, 0.25) 0%,
51
+ transparent 45%
52
+ );
53
+ }
54
+
55
+ .tx-modal-glow-error {
56
+ background: radial-gradient(
57
+ 120% 60% at 0% 0%,
58
+ rgba(244, 67, 54, 0.25) 0%,
59
+ transparent 45%
60
+ );
61
+ }
62
+
46
63
  .xpay-tx-status {
47
64
  @apply fixed bottom-5 right-2 flex flex-col gap-3 pl-9 items-end w-full z-50;
48
65
  }
@@ -49,6 +49,10 @@ export const MINIMUM_DISPLAYED_TOKEN_AMOUNT = 0.0001;
49
49
  export const DEFAULT_SOURCE_CHAIN_ID = "1";
50
50
  export const DEFAULT_SOURCE_TOKEN_ADDR = constants.AddressZero;
51
51
  export const DEFAULT_DESTINATION_CHAIN_ID = "1";
52
+ // Default bridge route: Ethereum -> Base; the token defaults to XSWAP via
53
+ // getDefaultBridgeTokenForChain.
54
+ export const DEFAULT_BRIDGE_SOURCE_CHAIN_ID = "1";
55
+ export const DEFAULT_BRIDGE_DESTINATION_CHAIN_ID = "8453";
52
56
  export const DEFAULT_DESTINATION_TOKEN_ADDR =
53
57
  "0x8fe815417913a93ea99049fc0718ee1647a2a07c"; // XSWAP token
54
58
  export const CCIP_EXPLORER = "https://ccip.chain.link/";