@rhinestone/deposit-modal 0.8.1 → 0.9.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 (65) hide show
  1. package/README.md +193 -29
  2. package/dist/{chunk-2JPB3PLB.mjs → DepositModalReown-6KUAO5ZC.mjs} +56 -4
  3. package/dist/{chunk-Q3W53BKR.cjs → DepositModalReown-XC5RIU7Z.cjs} +62 -10
  4. package/dist/{caip-C_ZYFIGa.d.cts → caip-523Zrc3r.d.cts} +1 -3
  5. package/dist/{caip-C_ZYFIGa.d.ts → caip-523Zrc3r.d.ts} +1 -3
  6. package/dist/{chunk-D3Y7ZBED.cjs → chunk-22RV33LK.cjs} +2170 -1460
  7. package/dist/chunk-4WB2FHGC.mjs +865 -0
  8. package/dist/chunk-A223BLVC.mjs +801 -0
  9. package/dist/{chunk-HQWZCOMS.cjs → chunk-DIX7M3SP.cjs} +232 -601
  10. package/dist/{chunk-T43VUEJH.mjs → chunk-E4G5BOZP.mjs} +167 -536
  11. package/dist/chunk-H577RJN5.cjs +801 -0
  12. package/dist/{chunk-DABKCJVL.mjs → chunk-ILT2PITN.mjs} +60 -3
  13. package/dist/{chunk-7KHEIMWD.mjs → chunk-KKHLNFSA.mjs} +2436 -1726
  14. package/dist/chunk-LGVJWVSS.mjs +81 -0
  15. package/dist/chunk-NEXUCY4B.cjs +11 -0
  16. package/dist/chunk-NMIMRASD.cjs +1785 -0
  17. package/dist/chunk-OSI2CFGL.mjs +11 -0
  18. package/dist/chunk-PAGMU4RQ.cjs +865 -0
  19. package/dist/chunk-T7LGQFP3.cjs +81 -0
  20. package/dist/chunk-VN4BLZYC.cjs +2273 -0
  21. package/dist/chunk-VOGZAZB2.mjs +2273 -0
  22. package/dist/chunk-WYXBY2MQ.mjs +1785 -0
  23. package/dist/{chunk-4NN7UTWQ.cjs → chunk-YEBXUUH3.cjs} +63 -6
  24. package/dist/claim.cjs +10 -0
  25. package/dist/claim.d.cts +8 -0
  26. package/dist/claim.d.ts +8 -0
  27. package/dist/claim.mjs +10 -0
  28. package/dist/constants.cjs +3 -3
  29. package/dist/constants.d.cts +4 -2
  30. package/dist/constants.d.ts +4 -2
  31. package/dist/constants.mjs +5 -5
  32. package/dist/deposit.cjs +8 -6
  33. package/dist/deposit.d.cts +2 -2
  34. package/dist/deposit.d.ts +2 -2
  35. package/dist/deposit.mjs +7 -5
  36. package/dist/index.cjs +22 -12
  37. package/dist/index.d.cts +15 -2
  38. package/dist/index.d.ts +15 -2
  39. package/dist/index.mjs +21 -11
  40. package/dist/polymarket.cjs +5 -6
  41. package/dist/polymarket.mjs +2 -3
  42. package/dist/server.cjs +96 -0
  43. package/dist/server.d.cts +65 -0
  44. package/dist/server.d.ts +65 -0
  45. package/dist/server.mjs +96 -0
  46. package/dist/styles.css +263 -12
  47. package/dist/types-C0SGf-21.d.cts +606 -0
  48. package/dist/types-C0SGf-21.d.ts +606 -0
  49. package/dist/withdraw.cjs +6 -5
  50. package/dist/withdraw.d.cts +3 -6
  51. package/dist/withdraw.d.ts +3 -6
  52. package/dist/withdraw.mjs +5 -4
  53. package/package.json +53 -6
  54. package/dist/DepositModalReown-4BSHOQ5Y.mjs +0 -63
  55. package/dist/DepositModalReown-UND3DEJH.cjs +0 -63
  56. package/dist/WithdrawModalReown-FVXSSGY5.mjs +0 -46
  57. package/dist/WithdrawModalReown-TVZWJKQI.cjs +0 -46
  58. package/dist/chunk-7OKA6GNA.cjs +0 -4537
  59. package/dist/chunk-NASHLEVQ.mjs +0 -4537
  60. package/dist/chunk-O5OKA27M.mjs +0 -800
  61. package/dist/chunk-U7SVYWVD.cjs +0 -800
  62. package/dist/chunk-WK5AFRSP.mjs +0 -295
  63. package/dist/chunk-XRWQMIBY.cjs +0 -295
  64. package/dist/types--LQWg_4W.d.cts +0 -468
  65. package/dist/types--LQWg_4W.d.ts +0 -468
@@ -1,4537 +0,0 @@
1
- import {
2
- CHAIN_BY_ID,
3
- HYPERCORE_CHAIN_ID,
4
- HYPERCORE_MAINNET_CAIP2,
5
- HYPERCORE_SOURCE_TOKENS,
6
- NATIVE_TOKEN_ADDRESS,
7
- findTokenDecimals,
8
- getChainIcon,
9
- getChainName,
10
- getExplorerTxUrl,
11
- getSolanaTokenByMint,
12
- getSupportedChainIds,
13
- getTokenAddress,
14
- getTokenDecimalsByAddress,
15
- getTokenSymbol,
16
- isHyperCoreCaip2,
17
- isRegistryTokenOnChain,
18
- isSolanaCaip2,
19
- parseEvmChainId,
20
- toEvmCaip2,
21
- tokenIconUrl
22
- } from "./chunk-O5OKA27M.mjs";
23
-
24
- // src/components/ui/Modal.tsx
25
- import {
26
- useEffect,
27
- useRef,
28
- useCallback
29
- } from "react";
30
- import { createPortal } from "react-dom";
31
- import { jsx } from "react/jsx-runtime";
32
- function getFocusableElements(container) {
33
- const elements = container.querySelectorAll(
34
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
35
- );
36
- return Array.from(elements).filter(
37
- (el) => !el.hasAttribute("disabled") && el.offsetParent !== null
38
- );
39
- }
40
- function Modal({
41
- isOpen,
42
- onClose,
43
- children,
44
- className = "",
45
- inline = false,
46
- closeOnOverlayClick = false
47
- }) {
48
- const overlayRef = useRef(null);
49
- const contentRef = useRef(null);
50
- const previousActiveElement = useRef(null);
51
- useEffect(() => {
52
- if (isOpen) {
53
- previousActiveElement.current = document.activeElement;
54
- }
55
- }, [isOpen]);
56
- useEffect(() => {
57
- if (!isOpen && previousActiveElement.current) {
58
- previousActiveElement.current.focus();
59
- previousActiveElement.current = null;
60
- }
61
- }, [isOpen]);
62
- useEffect(() => {
63
- if (isOpen && contentRef.current) {
64
- const focusable = getFocusableElements(contentRef.current);
65
- if (focusable.length > 0) {
66
- focusable[0].focus();
67
- } else {
68
- contentRef.current.focus();
69
- }
70
- }
71
- }, [isOpen]);
72
- useEffect(() => {
73
- if (isOpen && !inline) {
74
- const originalOverflow = document.body.style.overflow;
75
- document.body.style.overflow = "hidden";
76
- return () => {
77
- document.body.style.overflow = originalOverflow;
78
- };
79
- }
80
- }, [isOpen, inline]);
81
- const handleKeyDown = useCallback(
82
- (event) => {
83
- if (event.key === "Escape") {
84
- event.preventDefault();
85
- onClose();
86
- return;
87
- }
88
- if (event.key === "Tab" && contentRef.current) {
89
- const focusable = getFocusableElements(contentRef.current);
90
- if (focusable.length === 0) return;
91
- const firstElement = focusable[0];
92
- const lastElement = focusable[focusable.length - 1];
93
- if (event.shiftKey) {
94
- if (document.activeElement === firstElement) {
95
- event.preventDefault();
96
- lastElement.focus();
97
- }
98
- } else {
99
- if (document.activeElement === lastElement) {
100
- event.preventDefault();
101
- firstElement.focus();
102
- }
103
- }
104
- }
105
- },
106
- [onClose]
107
- );
108
- const handleOverlayClick = useCallback(
109
- (event) => {
110
- if (closeOnOverlayClick && event.target === overlayRef.current) {
111
- onClose();
112
- }
113
- },
114
- [closeOnOverlayClick, onClose]
115
- );
116
- if (!isOpen) return null;
117
- if (inline) {
118
- return /* @__PURE__ */ jsx(
119
- "div",
120
- {
121
- ref: contentRef,
122
- className: `rs-modal-content rs-modal-content--inline ${className}`,
123
- tabIndex: -1,
124
- children
125
- }
126
- );
127
- }
128
- return createPortal(
129
- /* @__PURE__ */ jsx(
130
- "div",
131
- {
132
- ref: overlayRef,
133
- className: `rs-modal-overlay ${isOpen ? "rs-modal-overlay--open" : ""}`,
134
- onClick: handleOverlayClick,
135
- onKeyDown: handleKeyDown,
136
- role: "dialog",
137
- "aria-modal": "true",
138
- "aria-labelledby": "rs-modal-title",
139
- children: /* @__PURE__ */ jsx(
140
- "div",
141
- {
142
- ref: contentRef,
143
- className: `rs-modal-content ${className}`,
144
- tabIndex: -1,
145
- children
146
- }
147
- )
148
- }
149
- ),
150
- document.body
151
- );
152
- }
153
- Modal.displayName = "Modal";
154
-
155
- // src/components/ui/Icons.tsx
156
- import {
157
- Wallet,
158
- ExternalLink,
159
- Coins,
160
- Check,
161
- ChevronRight,
162
- ChevronLeft,
163
- ChevronDown,
164
- X,
165
- HandCoins,
166
- History,
167
- Info,
168
- Copy,
169
- ArrowRight,
170
- ArrowUpRight,
171
- AlertTriangle,
172
- Percent,
173
- Clock,
174
- CirclePlus,
175
- CircleArrowOutUpLeft,
176
- CreditCard,
177
- Landmark,
178
- Unplug
179
- } from "lucide-react";
180
- import { jsx as jsx2, jsxs } from "react/jsx-runtime";
181
- var WalletIcon = Wallet;
182
- var ExternalLinkIcon = ExternalLink;
183
- var CheckIcon = Check;
184
- function TransferCryptoIcon() {
185
- return /* @__PURE__ */ jsx2(
186
- "svg",
187
- {
188
- width: "24",
189
- height: "24",
190
- viewBox: "8 8 24 24",
191
- fill: "none",
192
- xmlns: "http://www.w3.org/2000/svg",
193
- "aria-hidden": "true",
194
- children: /* @__PURE__ */ jsx2(
195
- "path",
196
- {
197
- d: "M26.08 18.37C27.03 18.72 27.87 19.30 28.53 20.07C29.19 20.83 29.65 21.75 29.86 22.73C30.07 23.72 30.03 24.74 29.74 25.71C29.45 26.68 28.92 27.55 28.20 28.26C27.48 28.97 26.59 29.49 25.62 29.76C24.65 30.04 23.63 30.06 22.64 29.83C21.66 29.61 20.75 29.14 20.00 28.47C19.24 27.80 18.67 26.95 18.33 26.00M15 14H16V18M24.70 21.87L25.40 22.58L22.58 25.40M22 16C22 19.31 19.31 22 16 22C12.68 22 10 19.31 10 16C10 12.68 12.68 10 16 10C19.31 10 22 12.68 22 16Z",
198
- stroke: "currentColor",
199
- strokeWidth: "2",
200
- strokeLinecap: "round",
201
- strokeLinejoin: "round"
202
- }
203
- )
204
- }
205
- );
206
- }
207
- var ChevronRightIcon = ChevronRight;
208
- var ChevronLeftIcon = ChevronLeft;
209
- var ChevronDownIcon = ChevronDown;
210
- var CloseIcon = X;
211
- var HandCoinsIcon = HandCoins;
212
- var HistoryIcon = History;
213
- var InfoIcon = Info;
214
- var CopyIcon = Copy;
215
- var ArrowUpRightIcon = ArrowUpRight;
216
- var AlertTriangleIcon = AlertTriangle;
217
- var PercentIcon = Percent;
218
- var ClockIcon = Clock;
219
- var PlusCircleIcon = CirclePlus;
220
- var CircleArrowOutUpLeftIcon = CircleArrowOutUpLeft;
221
- var CardIcon = CreditCard;
222
- var BankIcon = Landmark;
223
- var UnplugIcon = Unplug;
224
- function AppleIcon() {
225
- return /* @__PURE__ */ jsxs(
226
- "svg",
227
- {
228
- width: "24",
229
- height: "24",
230
- viewBox: "0 0 24 24",
231
- fill: "none",
232
- xmlns: "http://www.w3.org/2000/svg",
233
- "aria-hidden": "true",
234
- children: [
235
- /* @__PURE__ */ jsx2(
236
- "path",
237
- {
238
- d: "M16.36 1.43c0 1.14-.49 2.27-1.18 3.08-.74.9-1.99 1.57-2.98 1.57-.12 0-.23-.02-.3-.03-.01-.06-.04-.22-.04-.39 0-1.15.57-2.27 1.2-2.98.8-.94 2.15-1.64 3.25-1.68.03.13.05.28.05.43z",
239
- stroke: "currentColor",
240
- strokeWidth: "1.6",
241
- strokeLinejoin: "round"
242
- }
243
- ),
244
- /* @__PURE__ */ jsx2(
245
- "path",
246
- {
247
- d: "M20.93 17.14c-.03.07-.46 1.58-1.52 3.12-.94 1.34-1.94 2.71-3.43 2.71-1.51 0-1.9-.88-3.63-.88-1.7 0-2.3.91-3.67.91-1.38 0-2.33-1.26-3.43-2.8-1.29-1.82-2.32-4.63-2.32-7.28 0-4.28 2.8-6.55 5.55-6.55 1.45 0 2.68.95 3.6.95.86 0 2.22-1.01 3.9-1.01.61 0 2.89.06 4.37 2.19-.13.09-2.38 1.37-2.38 4.19 0 3.26 2.85 4.42 2.96 4.45z",
248
- stroke: "currentColor",
249
- strokeWidth: "1.6",
250
- strokeLinejoin: "round"
251
- }
252
- )
253
- ]
254
- }
255
- );
256
- }
257
-
258
- // src/components/ui/Callout.tsx
259
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
260
- function CircleAlertIcon() {
261
- return /* @__PURE__ */ jsx3(
262
- "svg",
263
- {
264
- width: "16",
265
- height: "16",
266
- viewBox: "0 0 16 16",
267
- fill: "none",
268
- xmlns: "http://www.w3.org/2000/svg",
269
- "aria-hidden": "true",
270
- children: /* @__PURE__ */ jsx3(
271
- "path",
272
- {
273
- d: "M10 5.99L6 9.99M6 5.99L10 9.99M14.66 7.99C14.66 11.68 11.68 14.66 8 14.66C4.31 14.66 1.33 11.68 1.33 7.99C1.33 4.31 4.31 1.33 8 1.33C11.68 1.33 14.66 4.31 14.66 7.99Z",
274
- stroke: "currentColor",
275
- strokeWidth: "1.33",
276
- strokeLinecap: "round",
277
- strokeLinejoin: "round"
278
- }
279
- )
280
- }
281
- );
282
- }
283
- function Callout({ variant = "error", children, role }) {
284
- return /* @__PURE__ */ jsxs2(
285
- "div",
286
- {
287
- className: `rs-callout rs-callout--${variant}`,
288
- role: role ?? (variant === "error" ? "alert" : "status"),
289
- children: [
290
- /* @__PURE__ */ jsx3("span", { className: "rs-callout-icon", children: variant === "error" ? /* @__PURE__ */ jsx3(CircleAlertIcon, {}) : /* @__PURE__ */ jsx3(AlertTriangleIcon, {}) }),
291
- /* @__PURE__ */ jsx3("span", { className: "rs-callout-text", children })
292
- ]
293
- }
294
- );
295
- }
296
- Callout.displayName = "Callout";
297
-
298
- // src/core/useLatestRef.ts
299
- import { useEffect as useEffect2, useRef as useRef2 } from "react";
300
- function useLatestRef(value) {
301
- const ref = useRef2(value);
302
- useEffect2(() => {
303
- ref.current = value;
304
- }, [value]);
305
- return ref;
306
- }
307
-
308
- // src/core/debug.ts
309
- function truncateString(value, max = 240) {
310
- if (value.length <= max) return value;
311
- return `${value.slice(0, max)}...`;
312
- }
313
- function normalizeForLog(value, depth = 0) {
314
- if (depth > 3) return "[MaxDepth]";
315
- if (value === null || value === void 0) return value;
316
- if (typeof value === "bigint") return value.toString();
317
- if (typeof value === "string") return truncateString(value);
318
- if (typeof value === "number" || typeof value === "boolean") return value;
319
- if (value instanceof Error) {
320
- return {
321
- name: value.name,
322
- message: value.message,
323
- stack: value.stack ? truncateString(value.stack, 600) : void 0
324
- };
325
- }
326
- if (Array.isArray(value)) {
327
- return value.slice(0, 12).map((entry) => normalizeForLog(entry, depth + 1));
328
- }
329
- if (typeof value === "object") {
330
- const input = value;
331
- const output = {};
332
- for (const [key, raw] of Object.entries(input)) {
333
- const keyLower = key.toLowerCase();
334
- if (keyLower.includes("signature") || keyLower.includes("privatekey") || keyLower.includes("sessiondetails")) {
335
- output[key] = "[Redacted]";
336
- continue;
337
- }
338
- output[key] = normalizeForLog(raw, depth + 1);
339
- }
340
- return output;
341
- }
342
- return String(value);
343
- }
344
- function debugLog(enabled, scope, message, data) {
345
- if (!enabled) return;
346
- if (data === void 0) {
347
- console.log(`[deposit-modal:${scope}] ${message}`);
348
- return;
349
- }
350
- console.log(
351
- `[deposit-modal:${scope}] ${message}`,
352
- normalizeForLog(data)
353
- );
354
- }
355
- function debugError(enabled, scope, message, error, data) {
356
- if (!enabled) return;
357
- const payload = data === void 0 ? { error: normalizeForLog(error) } : { error: normalizeForLog(error), meta: normalizeForLog(data) };
358
- console.error(`[deposit-modal:${scope}] ${message}`, payload);
359
- }
360
-
361
- // src/core/deposit-asset-helpers.ts
362
- function getAssetId(asset) {
363
- return `${asset.chainId}:${asset.token.toLowerCase()}`;
364
- }
365
- function isEvmAddress(value) {
366
- return /^0x[a-fA-F0-9]{40}$/.test(value);
367
- }
368
- function portfolioTokenToAsset(token) {
369
- if (typeof token.chainId !== "number") return null;
370
- if (!isEvmAddress(token.address)) return null;
371
- return {
372
- id: getAssetId({ chainId: token.chainId, token: token.address }),
373
- chainId: token.chainId,
374
- token: token.address,
375
- symbol: token.symbol,
376
- name: token.name,
377
- decimals: token.decimals,
378
- balance: token.balance,
379
- balanceUsd: token.balanceUsd
380
- };
381
- }
382
- function safeBigInt(value) {
383
- if (!value) return BigInt(0);
384
- try {
385
- return BigInt(value);
386
- } catch {
387
- return BigInt(0);
388
- }
389
- }
390
- function portfolioToAssets(tokens) {
391
- return tokens.map(portfolioTokenToAsset).filter((token) => token !== null).sort((a, b) => {
392
- const balanceA = safeBigInt(a.balance);
393
- const balanceB = safeBigInt(b.balance);
394
- if (balanceB > balanceA) return 1;
395
- if (balanceB < balanceA) return -1;
396
- return 0;
397
- });
398
- }
399
- function isNativeAsset(asset) {
400
- return asset.token.toLowerCase() === "0x0000000000000000000000000000000000000000";
401
- }
402
-
403
- // src/core/deposit-service.ts
404
- function depositRowToEvent(row) {
405
- const status = row.status;
406
- if (!status) return void 0;
407
- const deposit = {
408
- transactionHash: row.txHash,
409
- chain: row.chain,
410
- amount: row.sourceAmount ?? row.amount,
411
- asset: row.token,
412
- token: row.token
413
- };
414
- const source = row.sourceTxHash ? { transactionHash: row.sourceTxHash, chain: row.chain } : { transactionHash: row.txHash, chain: row.chain };
415
- const destination = row.destinationTxHash ? {
416
- transactionHash: row.destinationTxHash,
417
- chain: row.targetChain,
418
- amount: row.destinationAmount ?? void 0
419
- } : void 0;
420
- const time = row.completedAt ?? row.createdAt ?? void 0;
421
- if (status === "completed") {
422
- return {
423
- type: "bridge-complete",
424
- time: time ?? void 0,
425
- data: {
426
- deposit,
427
- source,
428
- ...destination && { destination }
429
- }
430
- };
431
- }
432
- if (status === "failed" || status === "refunded") {
433
- return {
434
- type: "bridge-failed",
435
- time: time ?? void 0,
436
- data: {
437
- deposit,
438
- source,
439
- ...row.errorCode && { error: { code: row.errorCode } }
440
- }
441
- };
442
- }
443
- if (status === "processing") {
444
- return {
445
- type: "bridge-started",
446
- time: time ?? void 0,
447
- data: {
448
- deposit,
449
- source
450
- }
451
- };
452
- }
453
- return {
454
- type: "deposit-received",
455
- time: time ?? void 0,
456
- data: {
457
- transactionHash: row.txHash,
458
- chain: row.chain,
459
- amount: row.amount,
460
- token: row.token
461
- }
462
- };
463
- }
464
- function jsonReplacer(_key, value) {
465
- return typeof value === "bigint" ? value.toString() : value;
466
- }
467
- function asRecord(value) {
468
- return typeof value === "object" && value !== null ? value : null;
469
- }
470
- function toBigInt(value) {
471
- if (typeof value === "bigint") return value;
472
- if (typeof value === "number" && Number.isInteger(value)) return BigInt(value);
473
- if (typeof value === "string" && value.trim() !== "") return BigInt(value);
474
- throw new Error("Invalid bigint value");
475
- }
476
- function normalizeSessionTypedData(raw) {
477
- const data = structuredClone(raw);
478
- const domain = asRecord(data.domain);
479
- if (domain && domain.chainId !== void 0 && domain.chainId !== null) {
480
- domain.chainId = toBigInt(domain.chainId);
481
- }
482
- const message = asRecord(data.message);
483
- if (!message || !Array.isArray(message.sessionsAndChainIds)) {
484
- return data;
485
- }
486
- for (const entry of message.sessionsAndChainIds) {
487
- const chainSession = asRecord(entry);
488
- if (!chainSession) continue;
489
- if (chainSession.chainId !== void 0 && chainSession.chainId !== null) {
490
- chainSession.chainId = toBigInt(chainSession.chainId);
491
- }
492
- const session = asRecord(chainSession.session);
493
- if (!session) continue;
494
- if (session.nonce !== void 0 && session.nonce !== null) {
495
- session.nonce = toBigInt(session.nonce);
496
- }
497
- if (session.expires !== void 0 && session.expires !== null) {
498
- session.expires = toBigInt(session.expires);
499
- }
500
- }
501
- return data;
502
- }
503
- function normalizeSetupAccountResponse(raw) {
504
- const data = raw;
505
- return {
506
- smartAccount: data.smartAccount,
507
- isRegistered: data.isRegistered,
508
- targetChain: data.targetChain,
509
- targetToken: data.targetToken,
510
- needsRegistration: data.needsRegistration,
511
- solanaDepositAddress: data.solanaDepositAddress,
512
- accountParams: data.accountParams,
513
- sessionDetailsUnsigned: data.sessionDetailsUnsigned ? {
514
- hashesAndChainIds: data.sessionDetailsUnsigned.hashesAndChainIds.map(
515
- (h) => ({
516
- chainId: toBigInt(h.chainId),
517
- sessionDigest: h.sessionDigest
518
- })
519
- ),
520
- data: normalizeSessionTypedData(data.sessionDetailsUnsigned.data)
521
- } : void 0
522
- };
523
- }
524
- function buildSessionDetails(unsigned, signature) {
525
- return {
526
- hashesAndChainIds: unsigned.hashesAndChainIds.map((h) => ({
527
- chainId: toBigInt(h.chainId),
528
- sessionDigest: h.sessionDigest
529
- })),
530
- signature
531
- };
532
- }
533
- function createDepositService(baseUrl, options) {
534
- const normalizedBaseUrl = baseUrl.replace(/\/$/, "");
535
- const debug = options?.debug === true;
536
- const scope = options?.debugScope ?? "service";
537
- function apiUrl(path) {
538
- const normalizedPath = path.startsWith("/") ? path : `/${path}`;
539
- return `${normalizedBaseUrl}${normalizedPath}`;
540
- }
541
- function shortRef(value) {
542
- if (value.length <= 20) return value;
543
- return `${value.slice(0, 10)}...${value.slice(-8)}`;
544
- }
545
- const PORTFOLIO_CACHE_TTL_MS = 3e4;
546
- const portfolioCache = /* @__PURE__ */ new Map();
547
- let topTokensPromise = null;
548
- function cachedPortfolio(key, fetcher, forceRefresh = false) {
549
- const now = Date.now();
550
- const entry = portfolioCache.get(key);
551
- if (!forceRefresh && entry && entry.expiresAt > now) {
552
- debugLog(debug, scope, "portfolio:cache-hit", { key });
553
- return entry.promise;
554
- }
555
- let promise;
556
- promise = fetcher().catch((err) => {
557
- if (portfolioCache.get(key)?.promise === promise) {
558
- portfolioCache.delete(key);
559
- }
560
- throw err;
561
- });
562
- portfolioCache.set(key, {
563
- promise,
564
- expiresAt: now + PORTFOLIO_CACHE_TTL_MS
565
- });
566
- return promise;
567
- }
568
- return {
569
- async setupAccount(params) {
570
- const url = apiUrl("/setup-account");
571
- debugLog(debug, scope, "setupAccount:request", {
572
- url,
573
- ownerAddress: params.ownerAddress,
574
- targetChain: params.targetChain,
575
- targetToken: params.targetToken,
576
- recipient: params.recipient ? shortRef(params.recipient) : void 0,
577
- forceRegister: params.forceRegister
578
- });
579
- const response = await fetch(url, {
580
- method: "POST",
581
- headers: { "Content-Type": "application/json" },
582
- body: JSON.stringify(params)
583
- });
584
- if (!response.ok) {
585
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
586
- debugError(
587
- debug,
588
- scope,
589
- "setupAccount:failed",
590
- error,
591
- { status: response.status, ownerAddress: params.ownerAddress }
592
- );
593
- const detail = Array.isArray(error.details) ? error.details.map((d) => d?.message).filter(Boolean).join("; ") : void 0;
594
- const base = error.error || `Setup account failed: ${response.status}`;
595
- throw new Error(detail ? `${base}: ${detail}` : base);
596
- }
597
- const normalized = normalizeSetupAccountResponse(await response.json());
598
- debugLog(debug, scope, "setupAccount:success", {
599
- smartAccount: normalized.smartAccount,
600
- needsRegistration: normalized.needsRegistration,
601
- isRegistered: normalized.isRegistered,
602
- hasSolanaDepositAddress: Boolean(normalized.solanaDepositAddress)
603
- });
604
- return normalized;
605
- },
606
- async registerAccount(params) {
607
- const { eoaAddress, sessionOwner, ...account } = params;
608
- const url = apiUrl("/register");
609
- debugLog(debug, scope, "registerAccount:request", {
610
- url,
611
- address: params.address,
612
- targetChain: params.target.chain,
613
- targetToken: params.target.token,
614
- eoaAddress,
615
- sessionOwner
616
- });
617
- const response = await fetch(url, {
618
- method: "POST",
619
- headers: { "Content-Type": "application/json" },
620
- body: JSON.stringify(
621
- {
622
- account,
623
- eoaAddress,
624
- sessionOwner
625
- },
626
- jsonReplacer
627
- )
628
- });
629
- if (!response.ok) {
630
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
631
- debugError(
632
- debug,
633
- scope,
634
- "registerAccount:failed",
635
- error,
636
- { status: response.status, address: params.address }
637
- );
638
- throw new Error(
639
- error.error || `Registration failed: ${response.status}`
640
- );
641
- }
642
- const result = await response.json();
643
- debugLog(debug, scope, "registerAccount:success", {
644
- address: params.address,
645
- evmDepositAddress: result?.evmDepositAddress,
646
- hasSolanaDepositAddress: Boolean(result?.solanaDepositAddress)
647
- });
648
- return result;
649
- },
650
- async fetchPortfolio(address, options2) {
651
- return cachedPortfolio(`evm:${address.toLowerCase()}`, async () => {
652
- const url = apiUrl(`/portfolio/${address}?includeUnsupported=true`);
653
- debugLog(debug, scope, "fetchPortfolio:request", { url, address });
654
- const response = await fetch(url, {
655
- method: "GET",
656
- headers: { "Content-Type": "application/json" }
657
- });
658
- if (!response.ok) {
659
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
660
- debugError(
661
- debug,
662
- scope,
663
- "fetchPortfolio:failed",
664
- error,
665
- { status: response.status, address }
666
- );
667
- throw new Error(
668
- error.error || `Portfolio fetch failed: ${response.status}`
669
- );
670
- }
671
- const data = await response.json();
672
- const direct = normalizeDirectPortfolio(data);
673
- if (direct.tokens.length > 0) {
674
- debugLog(debug, scope, "fetchPortfolio:success", {
675
- address,
676
- source: "direct",
677
- tokenCount: direct.tokens.length,
678
- totalUsd: direct.totalUsd
679
- });
680
- return direct;
681
- }
682
- const portfolioData = extractOrchestratorPortfolio(data);
683
- if (portfolioData) {
684
- const normalized = normalizeOrchestratorPortfolio(portfolioData);
685
- debugLog(debug, scope, "fetchPortfolio:success", {
686
- address,
687
- source: "orchestrator",
688
- tokenCount: normalized.tokens.length,
689
- totalUsd: normalized.totalUsd
690
- });
691
- return normalized;
692
- }
693
- debugLog(debug, scope, "fetchPortfolio:empty", { address });
694
- return { tokens: [], totalUsd: 0 };
695
- }, options2?.forceRefresh);
696
- },
697
- async fetchSolanaPortfolio(address, options2) {
698
- return cachedPortfolio(`sol:${address}`, async () => {
699
- const url = apiUrl(`/portfolio/solana/${address}`);
700
- debugLog(debug, scope, "fetchSolanaPortfolio:request", { url, address });
701
- const response = await fetch(url, {
702
- method: "GET",
703
- headers: { "Content-Type": "application/json" }
704
- });
705
- if (!response.ok) {
706
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
707
- debugError(
708
- debug,
709
- scope,
710
- "fetchSolanaPortfolio:failed",
711
- error,
712
- { status: response.status, address }
713
- );
714
- throw new Error(
715
- error.error || `Solana portfolio fetch failed: ${response.status}`
716
- );
717
- }
718
- const data = await response.json();
719
- const normalized = normalizeDirectPortfolio(data);
720
- debugLog(debug, scope, "fetchSolanaPortfolio:success", {
721
- address,
722
- tokenCount: normalized.tokens.length,
723
- totalUsd: normalized.totalUsd
724
- });
725
- return normalized;
726
- }, options2?.forceRefresh);
727
- },
728
- async checkAccount(address) {
729
- const url = apiUrl(`/check/${address}`);
730
- debugLog(debug, scope, "checkAccount:request", { url, address });
731
- const response = await fetch(url, {
732
- method: "GET",
733
- headers: { "Content-Type": "application/json" }
734
- });
735
- if (!response.ok) {
736
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
737
- debugError(
738
- debug,
739
- scope,
740
- "checkAccount:failed",
741
- error,
742
- { status: response.status, address }
743
- );
744
- throw new Error(error.error || `Account check failed: ${response.status}`);
745
- }
746
- const data = await response.json();
747
- const result = {
748
- isRegistered: data?.isRegistered === true,
749
- targetChain: data?.targetChain,
750
- targetToken: data?.targetToken
751
- };
752
- debugLog(debug, scope, "checkAccount:success", {
753
- address,
754
- isRegistered: result.isRegistered,
755
- targetChain: result.targetChain,
756
- targetToken: result.targetToken
757
- });
758
- return result;
759
- },
760
- async fetchStatus(address, txHash) {
761
- const normalized = txHash.startsWith("0x") || txHash.startsWith("0X") ? txHash.toLowerCase() : txHash;
762
- const txHashParam = encodeURIComponent(normalized);
763
- const url = apiUrl(
764
- `/deposits?account=${encodeURIComponent(address)}&txHash=${txHashParam}&limit=1`
765
- );
766
- const response = await fetch(url, {
767
- method: "GET",
768
- headers: { "Content-Type": "application/json" },
769
- cache: "no-store"
770
- });
771
- if (!response.ok) {
772
- debugLog(debug, scope, "fetchStatus:miss", {
773
- address,
774
- txHash: shortRef(normalized),
775
- status: response.status
776
- });
777
- return { lastEvent: void 0 };
778
- }
779
- const body = await response.json();
780
- const row = body.deposits?.[0];
781
- const lastEvent = row ? depositRowToEvent(row) : void 0;
782
- debugLog(debug, scope, "fetchStatus:success", {
783
- address,
784
- txHash: shortRef(normalized),
785
- eventType: lastEvent?.type
786
- });
787
- return { lastEvent };
788
- },
789
- async fetchLatestStatus(address) {
790
- const url = apiUrl(
791
- `/deposits?account=${encodeURIComponent(address)}&limit=1`
792
- );
793
- const response = await fetch(url, {
794
- method: "GET",
795
- headers: { "Content-Type": "application/json" },
796
- cache: "no-store"
797
- });
798
- if (!response.ok) {
799
- debugLog(debug, scope, "fetchLatestStatus:miss", {
800
- address,
801
- status: response.status
802
- });
803
- return { lastEvent: void 0 };
804
- }
805
- const body = await response.json();
806
- const row = body.deposits?.[0];
807
- const lastEvent = row ? depositRowToEvent(row) : void 0;
808
- debugLog(debug, scope, "fetchLatestStatus:success", {
809
- address,
810
- eventType: lastEvent?.type
811
- });
812
- return { lastEvent };
813
- },
814
- async relayWithdraw(params) {
815
- const { smartAccount, chainId, safeAddress, safeTransaction, signature } = params;
816
- const url = apiUrl(`/safe/withdraw`);
817
- debugLog(debug, scope, "relayWithdraw:request", {
818
- url,
819
- smartAccount,
820
- chainId,
821
- safeAddress,
822
- to: safeTransaction.to
823
- });
824
- const response = await fetch(url, {
825
- method: "POST",
826
- headers: { "Content-Type": "application/json" },
827
- body: JSON.stringify(
828
- {
829
- chainId,
830
- safeAddress,
831
- safeTransaction: {
832
- to: safeTransaction.to,
833
- value: safeTransaction.value.toString(),
834
- data: safeTransaction.data,
835
- operation: safeTransaction.operation,
836
- safeTxGas: safeTransaction.safeTxGas.toString(),
837
- baseGas: safeTransaction.baseGas.toString(),
838
- gasPrice: safeTransaction.gasPrice.toString(),
839
- gasToken: safeTransaction.gasToken,
840
- refundReceiver: safeTransaction.refundReceiver,
841
- nonce: safeTransaction.nonce.toString()
842
- },
843
- signature
844
- },
845
- jsonReplacer
846
- )
847
- });
848
- if (!response.ok) {
849
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
850
- debugError(
851
- debug,
852
- scope,
853
- "relayWithdraw:failed",
854
- error,
855
- {
856
- status: response.status,
857
- smartAccount,
858
- chainId,
859
- safeAddress,
860
- signature
861
- }
862
- );
863
- throw new Error(
864
- error.error || `Relay withdraw failed: ${response.status}`
865
- );
866
- }
867
- const result = await response.json();
868
- debugLog(debug, scope, "relayWithdraw:success", {
869
- smartAccount,
870
- chainId,
871
- safeAddress,
872
- txHash: result?.txHash ? shortRef(result.txHash) : void 0
873
- });
874
- return result;
875
- },
876
- async submitPolymarketWithdraw(params) {
877
- const { depositWallet, owner, nonce, deadline, calls, signature } = params;
878
- const url = apiUrl(`/polymarket/withdraw`);
879
- debugLog(debug, scope, "submitPolymarketWithdraw:request", {
880
- url,
881
- depositWallet,
882
- owner,
883
- nonce,
884
- callCount: calls.length
885
- });
886
- const response = await fetch(url, {
887
- method: "POST",
888
- headers: { "Content-Type": "application/json" },
889
- body: JSON.stringify({
890
- depositWallet,
891
- owner,
892
- nonce,
893
- deadline,
894
- calls,
895
- signature
896
- })
897
- });
898
- if (!response.ok) {
899
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
900
- debugError(debug, scope, "submitPolymarketWithdraw:failed", error, {
901
- status: response.status,
902
- depositWallet,
903
- owner
904
- });
905
- throw new Error(
906
- error.error || `Polymarket withdraw failed: ${response.status}`
907
- );
908
- }
909
- const result = await response.json();
910
- debugLog(debug, scope, "submitPolymarketWithdraw:success", {
911
- depositWallet,
912
- txHash: result?.txHash ? shortRef(result.txHash) : void 0
913
- });
914
- return result;
915
- },
916
- async fetchDepositHistory(params) {
917
- const searchParams = new URLSearchParams({ recipient: params.recipient });
918
- searchParams.set("limit", String(params.limit ?? 20));
919
- if (params.cursor) {
920
- searchParams.set("cursor", params.cursor);
921
- }
922
- const url = apiUrl(`/deposits?${searchParams.toString()}`);
923
- debugLog(debug, scope, "fetchDepositHistory:request", {
924
- url,
925
- recipient: shortRef(params.recipient),
926
- cursor: params.cursor
927
- });
928
- const response = await fetch(url, {
929
- method: "GET",
930
- headers: { "Content-Type": "application/json" },
931
- cache: "no-store"
932
- });
933
- if (!response.ok) {
934
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
935
- debugError(
936
- debug,
937
- scope,
938
- "fetchDepositHistory:failed",
939
- error,
940
- { status: response.status, recipient: shortRef(params.recipient) }
941
- );
942
- throw new Error(
943
- error.error || `Deposit history fetch failed: ${response.status}`
944
- );
945
- }
946
- const data = await response.json();
947
- const deposits = Array.isArray(data?.deposits) ? data.deposits : [];
948
- const nextCursor = data?.nextCursor ?? data?.next_cursor ?? null;
949
- debugLog(debug, scope, "fetchDepositHistory:success", {
950
- recipient: shortRef(params.recipient),
951
- count: deposits.length,
952
- hasMore: Boolean(nextCursor)
953
- });
954
- return { deposits, nextCursor };
955
- },
956
- async checkLiquidity(params) {
957
- if (params.destinationChainId === "solana") {
958
- const token = getSolanaTokenByMint(params.destinationToken);
959
- return {
960
- hasLiquidity: true,
961
- symbol: token?.symbol ?? "Token",
962
- decimals: token?.decimals ?? 9,
963
- unlimited: true,
964
- maxAmount: null
965
- };
966
- }
967
- const searchParams = new URLSearchParams({
968
- sourceChainId: String(params.sourceChainId),
969
- sourceToken: params.sourceToken,
970
- destinationChainId: String(params.destinationChainId),
971
- destinationToken: params.destinationToken,
972
- amount: params.amount
973
- });
974
- const url = apiUrl(`/liquidity?${searchParams.toString()}`);
975
- debugLog(debug, scope, "checkLiquidity:request", {
976
- url,
977
- sourceChainId: params.sourceChainId,
978
- destinationChainId: params.destinationChainId,
979
- amount: params.amount
980
- });
981
- const response = await fetch(url, {
982
- method: "GET",
983
- headers: { "Content-Type": "application/json" },
984
- cache: "no-store"
985
- });
986
- if (!response.ok) {
987
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
988
- debugError(debug, scope, "checkLiquidity:failed", error, {
989
- status: response.status
990
- });
991
- throw new Error(
992
- error.error || `Liquidity check failed: ${response.status}`
993
- );
994
- }
995
- const data = await response.json();
996
- const result = {
997
- hasLiquidity: data.hasLiquidity === true,
998
- symbol: typeof data.symbol === "string" ? data.symbol : "",
999
- decimals: typeof data.decimals === "number" ? data.decimals : 0,
1000
- unlimited: data.unlimited === true,
1001
- maxAmount: typeof data.maxAmount === "string" ? data.maxAmount : null
1002
- };
1003
- debugLog(debug, scope, "checkLiquidity:success", {
1004
- hasLiquidity: result.hasLiquidity,
1005
- unlimited: result.unlimited,
1006
- maxAmount: result.maxAmount
1007
- });
1008
- return result;
1009
- },
1010
- async getQuotePreview(params) {
1011
- const url = apiUrl("/quotes/preview");
1012
- const body = {
1013
- account: params.account,
1014
- // HyperCore has its own CAIP-2 namespace — never the eip155 placeholder.
1015
- sourceChainId: params.sourceChainId === "hypercore" ? HYPERCORE_MAINNET_CAIP2 : `eip155:${params.sourceChainId}`,
1016
- sourceToken: params.sourceToken,
1017
- amount: params.amount
1018
- };
1019
- debugLog(debug, scope, "getQuotePreview:request", {
1020
- url,
1021
- sourceChainId: body.sourceChainId,
1022
- sourceToken: params.sourceToken,
1023
- amount: params.amount
1024
- });
1025
- try {
1026
- const response = await fetch(url, {
1027
- method: "POST",
1028
- headers: { "Content-Type": "application/json" },
1029
- body: JSON.stringify(body),
1030
- cache: "no-store"
1031
- });
1032
- if (!response.ok) {
1033
- debugLog(debug, scope, "getQuotePreview:unavailable", {
1034
- status: response.status
1035
- });
1036
- return null;
1037
- }
1038
- const quote = await response.json();
1039
- debugLog(debug, scope, "getQuotePreview:success", {
1040
- settlementLayer: quote.settlementLayer,
1041
- totalUsd: quote.fees?.totalUsd
1042
- });
1043
- return quote;
1044
- } catch (error) {
1045
- debugError(debug, scope, "getQuotePreview:error", error);
1046
- return null;
1047
- }
1048
- },
1049
- async fetchPrices(symbols) {
1050
- const list = symbols.filter((s) => s.length > 0);
1051
- if (list.length === 0) return {};
1052
- const url = apiUrl(
1053
- `/prices?${new URLSearchParams({ symbols: list.join(",") }).toString()}`
1054
- );
1055
- try {
1056
- const response = await fetch(url, {
1057
- method: "GET",
1058
- headers: { "Content-Type": "application/json" },
1059
- cache: "no-store"
1060
- });
1061
- if (!response.ok) {
1062
- debugError(debug, scope, "fetchPrices:failed", {
1063
- status: response.status
1064
- });
1065
- return {};
1066
- }
1067
- const data = await response.json();
1068
- return Object.fromEntries(
1069
- Object.entries(data.prices ?? {}).map(([symbol, price]) => [
1070
- symbol.toUpperCase(),
1071
- price
1072
- ])
1073
- );
1074
- } catch (err) {
1075
- debugError(debug, scope, "fetchPrices:error", err);
1076
- return {};
1077
- }
1078
- },
1079
- async fetchPricesByAddress(caip2Ids) {
1080
- const list = caip2Ids.filter((id) => id.length > 0);
1081
- if (list.length === 0) return {};
1082
- const url = apiUrl(
1083
- `/prices?${new URLSearchParams({ addresses: list.join(",") }).toString()}`
1084
- );
1085
- try {
1086
- const response = await fetch(url, {
1087
- method: "GET",
1088
- headers: { "Content-Type": "application/json" },
1089
- cache: "no-store"
1090
- });
1091
- if (!response.ok) {
1092
- debugError(debug, scope, "fetchPricesByAddress:failed", {
1093
- status: response.status
1094
- });
1095
- return {};
1096
- }
1097
- const data = await response.json();
1098
- return data.prices ?? {};
1099
- } catch (err) {
1100
- debugError(debug, scope, "fetchPricesByAddress:error", err);
1101
- return {};
1102
- }
1103
- },
1104
- async getSwappedWidgetUrl(params) {
1105
- const url = apiUrl("/onramp/swapped/widget-url");
1106
- debugLog(debug, scope, "getSwappedWidgetUrl:request", {
1107
- smartAccount: shortRef(params.smartAccount),
1108
- method: params.method
1109
- });
1110
- const response = await fetch(url, {
1111
- method: "POST",
1112
- headers: { "Content-Type": "application/json" },
1113
- body: JSON.stringify(params)
1114
- });
1115
- if (!response.ok) {
1116
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
1117
- debugError(debug, scope, "getSwappedWidgetUrl:failed", error, {
1118
- status: response.status
1119
- });
1120
- throw new Error(
1121
- error.error || `Swapped widget URL failed: ${response.status}`
1122
- );
1123
- }
1124
- const body = await response.json();
1125
- if (typeof body.url !== "string" || typeof body.currencyCode !== "string" || typeof body.externalCustomerId !== "string") {
1126
- throw new Error("Swapped widget URL: malformed response");
1127
- }
1128
- return {
1129
- url: body.url,
1130
- currencyCode: body.currencyCode,
1131
- sandbox: body.sandbox === true,
1132
- externalCustomerId: body.externalCustomerId,
1133
- expiresAt: body.expiresAt
1134
- };
1135
- },
1136
- async getSwappedConnectUrl(params) {
1137
- const url = apiUrl("/onramp/swapped/connect-url");
1138
- debugLog(debug, scope, "getSwappedConnectUrl:request", {
1139
- smartAccount: shortRef(params.smartAccount),
1140
- connection: params.connection
1141
- });
1142
- const response = await fetch(url, {
1143
- method: "POST",
1144
- headers: { "Content-Type": "application/json" },
1145
- body: JSON.stringify(params)
1146
- });
1147
- if (!response.ok) {
1148
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
1149
- debugError(debug, scope, "getSwappedConnectUrl:failed", error, {
1150
- status: response.status
1151
- });
1152
- throw new Error(
1153
- error.error || `Swapped Connect URL failed: ${response.status}`
1154
- );
1155
- }
1156
- const body = await response.json();
1157
- if (typeof body.url !== "string" || typeof body.currencyCode !== "string" || typeof body.externalCustomerId !== "string") {
1158
- throw new Error("Swapped Connect URL: malformed response");
1159
- }
1160
- return {
1161
- url: body.url,
1162
- currencyCode: body.currencyCode,
1163
- sandbox: body.sandbox === true,
1164
- externalCustomerId: body.externalCustomerId,
1165
- expiresAt: body.expiresAt
1166
- };
1167
- },
1168
- async getSwappedConnectExchanges() {
1169
- const url = apiUrl("/onramp/swapped/connect-exchanges");
1170
- debugLog(debug, scope, "getSwappedConnectExchanges:request");
1171
- const response = await fetch(url, {
1172
- method: "GET",
1173
- headers: { "Content-Type": "application/json" },
1174
- cache: "no-store"
1175
- });
1176
- if (!response.ok) {
1177
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
1178
- debugError(debug, scope, "getSwappedConnectExchanges:failed", error, {
1179
- status: response.status
1180
- });
1181
- throw new Error(
1182
- error.error || `Swapped Connect exchanges failed: ${response.status}`
1183
- );
1184
- }
1185
- const body = await response.json();
1186
- const rawExchanges = Array.isArray(body.exchanges) ? body.exchanges : null;
1187
- const exchanges = [];
1188
- let hasMalformedExchange = rawExchanges === null;
1189
- for (const exchange of rawExchanges ?? []) {
1190
- if (!exchange || typeof exchange !== "object") {
1191
- hasMalformedExchange = true;
1192
- continue;
1193
- }
1194
- const raw = exchange;
1195
- const connection = typeof raw.connection === "string" ? raw.connection : "";
1196
- const name = typeof raw.name === "string" ? raw.name : "";
1197
- const logoUrl = typeof raw.logoUrl === "string" || raw.logoUrl === null ? raw.logoUrl : null;
1198
- if (!connection || !name) {
1199
- hasMalformedExchange = true;
1200
- continue;
1201
- }
1202
- exchanges.push({ connection, name, logoUrl });
1203
- }
1204
- if (hasMalformedExchange || typeof body.fetchedAt !== "string" || typeof body.expiresAt !== "string") {
1205
- throw new Error("Swapped Connect exchanges: malformed response");
1206
- }
1207
- return {
1208
- exchanges,
1209
- fetchedAt: body.fetchedAt,
1210
- expiresAt: body.expiresAt,
1211
- stale: body.stale === true ? true : void 0
1212
- };
1213
- },
1214
- getTopTokens() {
1215
- if (!topTokensPromise) {
1216
- topTokensPromise = (async () => {
1217
- try {
1218
- const response = await fetch(apiUrl("/tokens"), {
1219
- method: "GET",
1220
- headers: { "Content-Type": "application/json" }
1221
- });
1222
- if (!response.ok) {
1223
- debugLog(debug, scope, "getTopTokens:unavailable", {
1224
- status: response.status
1225
- });
1226
- return null;
1227
- }
1228
- const data = await response.json();
1229
- const tokens = data.tokens ?? null;
1230
- debugLog(debug, scope, "getTopTokens:success", {
1231
- chains: tokens ? Object.keys(tokens).length : 0
1232
- });
1233
- return tokens;
1234
- } catch (error) {
1235
- debugError(debug, scope, "getTopTokens:error", error);
1236
- return null;
1237
- }
1238
- })();
1239
- }
1240
- return topTokensPromise;
1241
- },
1242
- async getSetup() {
1243
- const url = apiUrl("/setup");
1244
- try {
1245
- const response = await fetch(url, {
1246
- method: "GET",
1247
- headers: { "Content-Type": "application/json" },
1248
- cache: "no-store"
1249
- });
1250
- if (!response.ok) {
1251
- debugLog(debug, scope, "getSetup:unavailable", {
1252
- status: response.status
1253
- });
1254
- return null;
1255
- }
1256
- const data = await response.json();
1257
- debugLog(debug, scope, "getSetup:success", {
1258
- hasWhitelist: Boolean(data.depositWhitelist),
1259
- whitelistChains: data.depositWhitelist ? Object.keys(data.depositWhitelist).length : 0,
1260
- minDepositUsd: data.minDepositUsd
1261
- });
1262
- return data;
1263
- } catch (error) {
1264
- debugError(debug, scope, "getSetup:error", error);
1265
- return null;
1266
- }
1267
- },
1268
- async fetchSwappedOrderStatus(smartAccount) {
1269
- const url = apiUrl(
1270
- `/onramp/swapped/status/${encodeURIComponent(smartAccount)}`
1271
- );
1272
- const response = await fetch(url, {
1273
- method: "GET",
1274
- headers: { "Content-Type": "application/json" },
1275
- cache: "no-store"
1276
- });
1277
- if (!response.ok) return null;
1278
- let body = null;
1279
- try {
1280
- body = await response.json();
1281
- } catch {
1282
- return null;
1283
- }
1284
- if (!body || body.ok !== true) return null;
1285
- const status = typeof body.status === "string" ? body.status : null;
1286
- const orderId = typeof body.orderId === "string" ? body.orderId : null;
1287
- if (!status || !orderId) return null;
1288
- const numericOrNull = (v) => {
1289
- if (typeof v === "number") {
1290
- return Number.isFinite(v) ? v : null;
1291
- }
1292
- if (typeof v === "string" && v.trim().length > 0) {
1293
- const parsed = Number(v);
1294
- return Number.isFinite(parsed) ? parsed : null;
1295
- }
1296
- return null;
1297
- };
1298
- return {
1299
- orderId,
1300
- status,
1301
- orderCrypto: typeof body.orderCrypto === "string" ? body.orderCrypto : null,
1302
- orderCryptoAmount: typeof body.orderCryptoAmount === "string" ? body.orderCryptoAmount : null,
1303
- transactionId: typeof body.transactionId === "string" ? body.transactionId : null,
1304
- receivedAt: typeof body.receivedAt === "string" ? body.receivedAt : null,
1305
- paidAmountUsd: numericOrNull(body.paidAmountUsd),
1306
- paidAmountEur: numericOrNull(body.paidAmountEur),
1307
- onrampFeeUsd: numericOrNull(body.onrampFeeUsd),
1308
- paymentMethod: typeof body.paymentMethod === "string" ? body.paymentMethod : null
1309
- };
1310
- }
1311
- };
1312
- }
1313
- function normalizeDirectPortfolio(data) {
1314
- const rawTokens = extractArray(data, "tokens") ?? extractArray(
1315
- data?.data,
1316
- "tokens"
1317
- ) ?? [];
1318
- const totalUsd = extractNumber(data, "totalUsd") ?? extractNumber(data?.data, "totalUsd") ?? 0;
1319
- const tokens = rawTokens.map((token) => normalizeDirectToken(token)).filter((token) => Boolean(token));
1320
- return { tokens, totalUsd };
1321
- }
1322
- function extractOrchestratorPortfolio(data) {
1323
- const portfolio = extractArray(data, "portfolio") ?? extractArray(
1324
- data?.data,
1325
- "portfolio"
1326
- );
1327
- if (!portfolio || !Array.isArray(portfolio)) return null;
1328
- return { portfolio };
1329
- }
1330
- function normalizeOrchestratorPortfolio(data) {
1331
- const tokens = [];
1332
- for (const tokenData of data.portfolio || []) {
1333
- const chainBalances = tokenData.tokenChainBalance ?? tokenData.chainBalances ?? [];
1334
- for (const chainBalance of chainBalances) {
1335
- const unlocked = chainBalance.balance?.unlocked ?? "0";
1336
- const normalizedName = tokenData.tokenName.trim();
1337
- const isNativeSymbol = normalizedName.toUpperCase() === "ETH" || normalizedName.toUpperCase() === "ETHER";
1338
- const tokenAddress = chainBalance.tokenAddress ?? extractTokenAddress(tokenData, chainBalance.chainId) ?? getTokenAddress(tokenData.tokenName, chainBalance.chainId);
1339
- const resolvedTokenAddress = isNativeSymbol ? NATIVE_TOKEN_ADDRESS : tokenAddress;
1340
- if (!resolvedTokenAddress) {
1341
- continue;
1342
- }
1343
- const registrySymbol = getTokenSymbol(resolvedTokenAddress, chainBalance.chainId);
1344
- const symbol = registrySymbol !== "Token" ? registrySymbol : normalizedName || "Token";
1345
- const decimals = registrySymbol !== "Token" ? getTokenDecimalsByAddress(resolvedTokenAddress, chainBalance.chainId) : tokenData.tokenDecimals ?? 18;
1346
- tokens.push({
1347
- chainId: chainBalance.chainId,
1348
- address: resolvedTokenAddress,
1349
- symbol,
1350
- name: symbol,
1351
- decimals,
1352
- balance: unlocked,
1353
- balanceUsd: 0
1354
- });
1355
- }
1356
- }
1357
- return {
1358
- tokens,
1359
- totalUsd: 0
1360
- };
1361
- }
1362
- function normalizeDirectToken(token) {
1363
- const rawChainId = extractNumber(token, "chainId") ?? extractNumber(token.chain, "id");
1364
- const rawChainString = extractString(token, "chainId") ?? extractString(token.chain, "id");
1365
- const chainId = rawChainId ?? (rawChainString ? isSolanaCaip2(rawChainString) || rawChainString.toLowerCase() === "solana" ? "solana" : (
1366
- // HyperCore (`hypercore:mainnet`) is a non-EVM source; keep its USDC
1367
- // instead of dropping it as an unparseable chain string.
1368
- isHyperCoreCaip2(rawChainString) || rawChainString.toLowerCase() === "hypercore" ? "hypercore" : parseEvmChainId(rawChainString)
1369
- ) : null);
1370
- if (chainId === null) return null;
1371
- const registryChainId = typeof chainId === "number" ? chainId : chainId === "hypercore" ? HYPERCORE_CHAIN_ID : void 0;
1372
- const symbol = extractString(token, "symbol") ?? extractString(token, "tokenSymbol") ?? extractString(token, "tokenName") ?? extractString(token, "name");
1373
- if (!symbol) return null;
1374
- const balanceValue = extractString(token, "balance") ?? extractString(token, "amount") ?? extractString(token, "value") ?? extractString(token, "rawBalance") ?? extractNumber(token, "balance")?.toString() ?? extractNumber(token, "amount")?.toString() ?? extractNumber(token, "value")?.toString() ?? extractNumber(token, "rawBalance")?.toString();
1375
- if (!balanceValue) return null;
1376
- const address = extractString(token, "address") ?? extractString(token, "tokenAddress") ?? extractString(
1377
- token.token,
1378
- "address"
1379
- ) ?? (registryChainId !== void 0 ? getTokenAddress(symbol, registryChainId) : void 0);
1380
- if (!address) return null;
1381
- const balanceUsd = extractNumber(token, "balanceUsd") ?? extractNumber(token, "usdValue") ?? extractNumber(token, "valueUsd") ?? extractNumericString(token, "balanceUsd") ?? extractNumericString(token, "usdValue") ?? extractNumericString(token, "valueUsd") ?? 0;
1382
- const isSolanaToken = chainId === "solana";
1383
- const registrySymbol = isSolanaToken ? "Token" : getTokenSymbol(address, registryChainId);
1384
- const resolvedSymbol = isSolanaToken ? symbol : registrySymbol !== "Token" ? registrySymbol : symbol;
1385
- const backendDecimals = extractNumber(token, "decimals") ?? extractNumber(token, "tokenDecimals");
1386
- const resolvedDecimals = !isSolanaToken && registrySymbol !== "Token" ? getTokenDecimalsByAddress(address, registryChainId) : backendDecimals ?? 18;
1387
- return {
1388
- chainId,
1389
- address,
1390
- symbol: resolvedSymbol,
1391
- name: resolvedSymbol,
1392
- decimals: resolvedDecimals,
1393
- balance: balanceValue,
1394
- balanceUsd
1395
- };
1396
- }
1397
- function extractTokenAddress(tokenData, chainId) {
1398
- const token = tokenData;
1399
- return token.tokenAddress ?? token.address ?? token.addresses?.[chainId] ?? token.token?.address ?? token.token?.addresses?.[chainId];
1400
- }
1401
- function extractArray(data, key) {
1402
- if (!data || typeof data !== "object") return null;
1403
- const record = data;
1404
- const value = record[key];
1405
- return Array.isArray(value) ? value : null;
1406
- }
1407
- function extractNumber(data, key) {
1408
- if (!data || typeof data !== "object") return null;
1409
- const record = data;
1410
- const value = record[key];
1411
- return typeof value === "number" ? value : null;
1412
- }
1413
- function extractString(data, key) {
1414
- if (!data || typeof data !== "object") return null;
1415
- const record = data;
1416
- const value = record[key];
1417
- return typeof value === "string" ? value : null;
1418
- }
1419
- function extractNumericString(data, key) {
1420
- const value = extractString(data, key);
1421
- if (!value) return null;
1422
- const parsed = Number(value);
1423
- return Number.isFinite(parsed) ? parsed : null;
1424
- }
1425
-
1426
- // src/core/formatters.ts
1427
- var currencyFormatter = new Intl.NumberFormat("en-US", {
1428
- style: "currency",
1429
- currency: "USD",
1430
- maximumFractionDigits: 2
1431
- });
1432
- var tokenFormatter = new Intl.NumberFormat("en-US", {
1433
- minimumFractionDigits: 2,
1434
- maximumFractionDigits: 5
1435
- });
1436
- function isUnsupportedChainSwitchError(error) {
1437
- if (!error) return false;
1438
- const name = error instanceof Error ? error.name : "";
1439
- const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
1440
- return name === "SwitchChainNotSupportedError" || message.includes("does not support programmatic chain switching") || message.includes("switch chain not supported") || message.includes("method not found") || message.includes("does not exist") || message.includes("is not available");
1441
- }
1442
- function formatUserError(raw) {
1443
- const lower = raw.toLowerCase();
1444
- if (lower.includes("user rejected") || lower.includes("user denied")) {
1445
- return "Transaction cancelled";
1446
- }
1447
- if (lower.includes("insufficient funds")) {
1448
- return "Insufficient funds for this transaction";
1449
- }
1450
- if (lower.includes("nonce too low") || lower.includes("nonce too high")) {
1451
- return "Transaction conflict \u2014 please try again";
1452
- }
1453
- if (lower.includes("execution reverted")) {
1454
- return "Transaction would fail on-chain";
1455
- }
1456
- if (lower.includes("timed out") || lower.includes("took too long")) {
1457
- return "Request timed out \u2014 please try again";
1458
- }
1459
- if (lower.includes("econnrefused") || lower.includes("econnreset") || lower.includes("enotfound") || lower.includes("fetch failed")) {
1460
- return "Service unavailable \u2014 please try again";
1461
- }
1462
- if (lower.includes("recent blockhash") || lower.includes("latest blockhash")) {
1463
- return "Solana RPC unavailable \u2014 please retry";
1464
- }
1465
- if (lower.includes("network") || lower.includes("disconnected")) {
1466
- return "Network error \u2014 check your connection";
1467
- }
1468
- if (lower.includes("rate limit") || lower.includes("429")) {
1469
- return "Rate limited \u2014 please try again shortly";
1470
- }
1471
- let cleaned = raw;
1472
- const stripMarkers = [
1473
- "\n\nRequest Arguments:",
1474
- "\nRaw Call Arguments:",
1475
- "\nRequest body:",
1476
- "\nContract Call:",
1477
- "\nDocs:",
1478
- "\nDetails:",
1479
- "\nVersion:",
1480
- "\nURL:"
1481
- ];
1482
- for (const marker of stripMarkers) {
1483
- const idx = cleaned.indexOf(marker);
1484
- if (idx !== -1) {
1485
- cleaned = cleaned.slice(0, idx).trim();
1486
- }
1487
- }
1488
- cleaned = cleaned.replace(/https?:\/\/\S+/g, "").trim();
1489
- if (cleaned.length === 0) {
1490
- return "An unexpected error occurred";
1491
- }
1492
- if (cleaned.length > 120) {
1493
- return cleaned.slice(0, 120) + "...";
1494
- }
1495
- return cleaned;
1496
- }
1497
-
1498
- // src/core/rpc.ts
1499
- import { createContext, useContext, useMemo } from "react";
1500
- function rpcUrlFor(rpcUrls, chain) {
1501
- const url = rpcUrls?.[chain]?.trim();
1502
- return url ? url : void 0;
1503
- }
1504
- var RpcUrlsContext = createContext(void 0);
1505
- var RpcUrlsProvider = RpcUrlsContext.Provider;
1506
- function useRpcUrls() {
1507
- return useContext(RpcUrlsContext);
1508
- }
1509
- function rpcUrlsKey(rpcUrls) {
1510
- if (!rpcUrls) return "";
1511
- return Object.entries(rpcUrls).map(([chain, url]) => [chain, url?.trim() ?? ""]).filter(([, url]) => url !== "").map(([chain, url]) => `${chain}=${url}`).sort().join("|");
1512
- }
1513
- function useStableRpcUrls(rpcUrls) {
1514
- const key = rpcUrlsKey(rpcUrls);
1515
- return useMemo(() => rpcUrls, [key]);
1516
- }
1517
-
1518
- // src/core/public-client.ts
1519
- import { createPublicClient, http } from "viem";
1520
- import { hyperliquid } from "viem/chains";
1521
- var clientCache = /* @__PURE__ */ new Map();
1522
- function getPublicClient(chainId, rpcUrls) {
1523
- const url = rpcUrlFor(rpcUrls, chainId);
1524
- const cacheKey = `${chainId}|${url ?? ""}`;
1525
- let client = clientCache.get(cacheKey);
1526
- if (!client) {
1527
- const chain = CHAIN_BY_ID[chainId];
1528
- client = createPublicClient({
1529
- chain,
1530
- transport: http(url)
1531
- });
1532
- clientCache.set(cacheKey, client);
1533
- }
1534
- return client;
1535
- }
1536
- var hyperEvmClientCache = /* @__PURE__ */ new Map();
1537
- function getHyperEvmReadClient(rpcUrls) {
1538
- const url = rpcUrlFor(rpcUrls, hyperliquid.id);
1539
- const cacheKey = url ?? "";
1540
- let client = hyperEvmClientCache.get(cacheKey);
1541
- if (!client) {
1542
- client = createPublicClient({
1543
- chain: hyperliquid,
1544
- transport: http(url)
1545
- });
1546
- hyperEvmClientCache.set(cacheKey, client);
1547
- }
1548
- return client;
1549
- }
1550
-
1551
- // src/core/theme.ts
1552
- var RADIUS_SCALE = {
1553
- none: { sm: "0", md: "0", lg: "0" },
1554
- sm: { sm: "4px", md: "6px", lg: "8px" },
1555
- md: { sm: "8px", md: "10px", lg: "14px" },
1556
- lg: { sm: "10px", md: "14px", lg: "18px" },
1557
- full: { sm: "9999px", md: "9999px", lg: "9999px" }
1558
- };
1559
- function setVar(targets, prop, value) {
1560
- for (const el of targets) {
1561
- el.style.setProperty(prop, value);
1562
- }
1563
- }
1564
- function clearVar(targets, prop) {
1565
- for (const el of targets) {
1566
- el.style.removeProperty(prop);
1567
- }
1568
- }
1569
- function normalizeHex(input) {
1570
- const v = input.trim().replace(/^#/, "");
1571
- if (/^[0-9a-fA-F]{3}$/.test(v)) {
1572
- return v.split("").map((c) => c + c).join("").toLowerCase();
1573
- }
1574
- if (/^[0-9a-fA-F]{6}$/.test(v)) return v.toLowerCase();
1575
- return null;
1576
- }
1577
- function hexToHsl(hex) {
1578
- const normalized = normalizeHex(hex);
1579
- if (!normalized) return null;
1580
- const r = parseInt(normalized.slice(0, 2), 16) / 255;
1581
- const g = parseInt(normalized.slice(2, 4), 16) / 255;
1582
- const b = parseInt(normalized.slice(4, 6), 16) / 255;
1583
- const max = Math.max(r, g, b);
1584
- const min = Math.min(r, g, b);
1585
- const l = (max + min) / 2;
1586
- let h = 0;
1587
- let s = 0;
1588
- if (max !== min) {
1589
- const d = max - min;
1590
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1591
- switch (max) {
1592
- case r:
1593
- h = (g - b) / d + (g < b ? 6 : 0);
1594
- break;
1595
- case g:
1596
- h = (b - r) / d + 2;
1597
- break;
1598
- case b:
1599
- h = (r - g) / d + 4;
1600
- break;
1601
- }
1602
- h *= 60;
1603
- }
1604
- return { h, s: s * 100, l: l * 100 };
1605
- }
1606
- var clamp = (n, lo, hi) => Math.max(lo, Math.min(hi, n));
1607
- var hsl = ({ h, s, l }) => `hsl(${h.toFixed(1)} ${clamp(s, 0, 100).toFixed(1)}% ${clamp(l, 0, 100).toFixed(1)}%)`;
1608
- function deriveCustomPrimary(baseHex) {
1609
- const base = hexToHsl(baseHex);
1610
- if (!base) return null;
1611
- const { h, s, l } = base;
1612
- const direction = l < 25 ? 1 : -1;
1613
- const hoverL = clamp(l + 8 * direction, 4, 96);
1614
- const activeL = clamp(l + 14 * direction, 2, 98);
1615
- const disabledBg = {
1616
- h,
1617
- s: clamp(s * 0.25, 0, 20),
1618
- l: clamp(l > 75 ? l - 15 : 88, 12, 92)
1619
- };
1620
- const disabledFg = {
1621
- h,
1622
- s: clamp(s * 0.35, 0, 25),
1623
- l: clamp(l > 75 ? 35 : 45, 30, 60)
1624
- };
1625
- const norm = normalizeHex(baseHex);
1626
- const ch = (i) => {
1627
- const v = parseInt(norm.slice(i, i + 2), 16) / 255;
1628
- return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
1629
- };
1630
- const y = 0.2126 * ch(0) + 0.7152 * ch(2) + 0.0722 * ch(4);
1631
- const foreground = y > 0.45 ? "#18181b" : "#fafafa";
1632
- return {
1633
- base: hsl({ h, s, l }),
1634
- hover: hsl({ h, s, l: hoverL }),
1635
- active: hsl({ h, s, l: activeL }),
1636
- disabledBg: hsl(disabledBg),
1637
- disabledFg: hsl(disabledFg),
1638
- foreground
1639
- };
1640
- }
1641
- var CUSTOM_PRIMARY_VARS = [
1642
- "--rs-primary",
1643
- "--rs-primary-hover",
1644
- "--rs-primary-active",
1645
- "--rs-primary-disabled-bg",
1646
- "--rs-primary-disabled-fg",
1647
- "--rs-primary-foreground",
1648
- "--rs-border-accent"
1649
- ];
1650
- function applyTheme(element, theme) {
1651
- if (!element) return;
1652
- const parent = element.parentElement;
1653
- const targets = parent?.classList.contains("rs-modal-content") ? [element, parent] : [element];
1654
- if (theme?.mode) {
1655
- for (const t of targets) t.setAttribute("data-theme", theme.mode);
1656
- } else {
1657
- for (const t of targets) t.removeAttribute("data-theme");
1658
- }
1659
- if (theme?.fontColor) {
1660
- setVar(targets, "--rs-foreground", theme.fontColor);
1661
- }
1662
- if (theme?.iconColor) {
1663
- setVar(targets, "--rs-icon", theme.iconColor);
1664
- }
1665
- if (theme?.ctaColor) {
1666
- const derived = deriveCustomPrimary(theme.ctaColor);
1667
- if (derived) {
1668
- setVar(targets, "--rs-primary", derived.base);
1669
- setVar(
1670
- targets,
1671
- "--rs-primary-hover",
1672
- theme.ctaHoverColor ?? derived.hover
1673
- );
1674
- setVar(targets, "--rs-primary-active", derived.active);
1675
- setVar(targets, "--rs-primary-disabled-bg", derived.disabledBg);
1676
- setVar(targets, "--rs-primary-disabled-fg", derived.disabledFg);
1677
- setVar(targets, "--rs-primary-foreground", derived.foreground);
1678
- setVar(targets, "--rs-border-accent", derived.base);
1679
- } else {
1680
- setVar(targets, "--rs-primary", theme.ctaColor);
1681
- setVar(targets, "--rs-border-accent", theme.ctaColor);
1682
- setVar(
1683
- targets,
1684
- "--rs-primary-hover",
1685
- theme.ctaHoverColor ?? theme.ctaColor
1686
- );
1687
- }
1688
- } else {
1689
- for (const v of CUSTOM_PRIMARY_VARS) clearVar(targets, v);
1690
- if (theme?.ctaHoverColor) {
1691
- setVar(targets, "--rs-primary-hover", theme.ctaHoverColor);
1692
- }
1693
- }
1694
- if (theme?.borderColor) {
1695
- setVar(targets, "--rs-border", theme.borderColor);
1696
- setVar(targets, "--rs-border-surface", theme.borderColor);
1697
- }
1698
- if (theme?.backgroundColor) {
1699
- setVar(targets, "--rs-background", theme.backgroundColor);
1700
- }
1701
- if (theme?.radius) {
1702
- const scale = RADIUS_SCALE[theme.radius];
1703
- setVar(targets, "--rs-radius-sm", scale.sm);
1704
- setVar(targets, "--rs-radius-md", scale.md);
1705
- setVar(targets, "--rs-radius-lg", scale.lg);
1706
- setVar(targets, "--rs-radius", scale.md);
1707
- }
1708
- }
1709
-
1710
- // src/components/ui/BodyHeader.tsx
1711
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1712
- function BodyHeader({
1713
- icon,
1714
- title,
1715
- subtitle,
1716
- variant = "default",
1717
- aside
1718
- }) {
1719
- const iconClasses = [
1720
- "rs-body-header-icon",
1721
- variant === "success" ? "rs-body-header-icon--success" : "",
1722
- variant === "error" ? "rs-body-header-icon--error" : ""
1723
- ].filter(Boolean).join(" ");
1724
- return /* @__PURE__ */ jsxs3("div", { className: "rs-body-header", children: [
1725
- /* @__PURE__ */ jsx4("div", { className: iconClasses, children: icon }),
1726
- /* @__PURE__ */ jsxs3("div", { className: "rs-body-header-main", children: [
1727
- /* @__PURE__ */ jsxs3("div", { className: "rs-body-header-text", children: [
1728
- /* @__PURE__ */ jsx4("h2", { className: "rs-body-header-title", children: title }),
1729
- subtitle && /* @__PURE__ */ jsx4("p", { className: "rs-body-header-subtitle", children: subtitle })
1730
- ] }),
1731
- aside && /* @__PURE__ */ jsx4("div", { className: "rs-body-header-aside", children: aside })
1732
- ] })
1733
- ] });
1734
- }
1735
- BodyHeader.displayName = "BodyHeader";
1736
-
1737
- // src/components/ui/PoweredBy.tsx
1738
- import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1739
- var rhinestoneLogo = /* @__PURE__ */ jsxs4(
1740
- "svg",
1741
- {
1742
- className: "rs-powered-by-logo",
1743
- viewBox: "0 0 72 16",
1744
- fill: "none",
1745
- xmlns: "http://www.w3.org/2000/svg",
1746
- "aria-hidden": "true",
1747
- children: [
1748
- /* @__PURE__ */ jsxs4("g", { fill: "currentColor", clipPath: "url(#rs-pb-clip)", children: [
1749
- /* @__PURE__ */ jsx5(
1750
- "path",
1751
- {
1752
- opacity: "0.5",
1753
- fillRule: "evenodd",
1754
- clipRule: "evenodd",
1755
- d: "M10.48 14.82a4.3 4.3 0 0 1-2.9 1 4.3 4.3 0 0 1-2.4-1 25 25 0 0 1-2.08-1.95l-.13-.13c-.78-.78-1.46-1.46-1.94-2.08a4.3 4.3 0 0 1-1-2.9c.05-.96.48-1.72 1-2.4a25 25 0 0 1 1.94-2.08l.07-.06.06-.07a25 25 0 0 1 2.08-1.94 4.3 4.3 0 0 1 2.9-1c.96.05 1.73.48 2.4 1 .62.49 1.3 1.17 2.08 1.94l.13.13c.77.78 1.46 1.46 1.94 2.09a4.3 4.3 0 0 1 1 2.9 4.3 4.3 0 0 1-1 2.39c-.48.62-1.17 1.3-1.94 2.08l-.07.07-.06.06c-.78.78-1.46 1.46-2.08 1.94m-8.9-6.63c.07 1.02.9 1.86 2.56 3.52s2.5 2.5 3.53 2.56h.32c1.03-.06 1.86-.9 3.53-2.56s2.5-2.5 2.56-3.52v-.33c-.07-1.03-.9-1.86-2.56-3.52-1.67-1.67-2.5-2.5-3.53-2.56h-.32c-1.03.06-1.86.89-3.53 2.56-1.66 1.66-2.5 2.5-2.56 3.52z"
1756
- }
1757
- ),
1758
- /* @__PURE__ */ jsx5("path", { d: "M3.66 8.01q.02-.27.28-.35a4.6 4.6 0 0 0 2.53-1.48q.72-.8 1-2.05a.4.4 0 0 1 .36-.29c.17 0 .32.12.36.29a4.6 4.6 0 0 0 1.47 2.52c.55.49 1.21.8 2.06 1a.4.4 0 0 1 .28.36.4.4 0 0 1-.28.36 4.6 4.6 0 0 0-2.53 1.47 4.6 4.6 0 0 0-1 2.06.4.4 0 0 1-.36.28.4.4 0 0 1-.36-.28A4.6 4.6 0 0 0 6 9.38a4.6 4.6 0 0 0-2.06-1.01.4.4 0 0 1-.28-.36m26.46-3.44c0 .51.38.87.96.87s.95-.36.95-.87c0-.52-.37-.86-.95-.86s-.96.34-.96.86m.2 1.44v5.33h1.53V6.01zm-4.4 5.33h-1.55V3.88h1.54v2.98c.25-.5.8-1.01 1.6-1.01 1.29 0 1.87.83 1.87 2.28v3.21h-1.54V8.3c0-.77-.34-1.16-.92-1.16-.67 0-1 .53-1 1.3zm-4.45 0h-1.54V6.01h1.54l-.27 1.22a.1.1 0 0 0 .02.1.1.1 0 0 0 .1.04q.09 0 .1-.09c.24-.84.93-1.36 1.64-1.36q.4.01.57.05v1.42l-.67-.04c-.67 0-1.5.31-1.5 2zm13 0h-1.55V6.01h1.54l-.02.9a1.8 1.8 0 0 1 1.61-1.06c1.3 0 1.88.83 1.88 2.28v3.21H36.4V8.3c0-.77-.35-1.16-.93-1.16-.67 0-1 .53-1 1.3z" }),
1759
- /* @__PURE__ */ jsx5(
1760
- "path",
1761
- {
1762
- fillRule: "evenodd",
1763
- clipRule: "evenodd",
1764
- d: "M38.74 8.69c0 1.63 1.01 2.82 2.7 2.82 1.51 0 2.32-.82 2.55-1.73l-1.43-.26c-.1.37-.47.82-1.12.82-.67 0-1.23-.6-1.24-1.31H44q.05-.19.06-.56a2.55 2.55 0 0 0-2.6-2.63c-1.5 0-2.72 1.2-2.72 2.85m3.82-.58h-2.3a1.2 1.2 0 0 1 1.18-1.13c.6 0 1.14.45 1.12 1.13"
1765
- }
1766
- ),
1767
- /* @__PURE__ */ jsx5("path", { d: "M47.1 11.51c-1.2 0-2.33-.41-2.55-1.65l1.43-.21q.27.8 1.1.79c.5 0 .77-.24.77-.55 0-.27-.2-.45-.75-.55l-.5-.1c-1.1-.24-1.77-.74-1.77-1.63 0-1.06.91-1.78 2.25-1.78 1.26 0 2.2.59 2.32 1.68l-1.41.22c-.07-.52-.43-.82-.91-.82-.5 0-.75.26-.75.57 0 .25.17.42.63.51l.5.1c1.28.26 1.94.77 1.94 1.75 0 1.01-1.03 1.66-2.3 1.66" }),
1768
- /* @__PURE__ */ jsx5(
1769
- "path",
1770
- {
1771
- fillRule: "evenodd",
1772
- clipRule: "evenodd",
1773
- d: "M54.44 8.68c0 1.53 1.08 2.83 2.78 2.83s2.79-1.3 2.79-2.83c0-1.55-1.1-2.84-2.79-2.84-1.7 0-2.78 1.29-2.78 2.84m4.02 0c0 .98-.59 1.45-1.24 1.45-.64 0-1.23-.47-1.23-1.45 0-.97.59-1.47 1.23-1.47.65 0 1.24.48 1.24 1.47"
1774
- }
1775
- ),
1776
- /* @__PURE__ */ jsx5("path", { d: "M62.4 11.34h-1.53V6.01h1.54l-.02.9a1.8 1.8 0 0 1 1.6-1.06c1.3 0 1.89.83 1.89 2.28v3.21h-1.54V8.3c0-.77-.34-1.16-.93-1.16-.66 0-1 .53-1 1.3z" }),
1777
- /* @__PURE__ */ jsx5(
1778
- "path",
1779
- {
1780
- fillRule: "evenodd",
1781
- clipRule: "evenodd",
1782
- d: "M66.68 8.69c0 1.63 1.02 2.82 2.71 2.82 1.51 0 2.31-.82 2.55-1.73l-1.44-.26c-.1.37-.47.82-1.12.82-.67 0-1.23-.6-1.24-1.31h3.8q.06-.19.06-.56a2.55 2.55 0 0 0-2.6-2.63c-1.5 0-2.72 1.2-2.72 2.85m3.82-.58h-2.3a1.2 1.2 0 0 1 1.18-1.13c.6 0 1.15.45 1.12 1.13"
1783
- }
1784
- ),
1785
- /* @__PURE__ */ jsx5("path", { d: "M52.44 9.05V7.26h1.53V6h-1.53V4.42h-1.53V6h-1.1v1.26h1.1v1.85l.02.49a1.9 1.9 0 0 0 1.67 1.67c.22.03.47.03.62.03h.65V9.87h-.61c-.4 0-.59 0-.7-.12-.12-.11-.12-.3-.12-.64z" })
1786
- ] }),
1787
- /* @__PURE__ */ jsx5("defs", { children: /* @__PURE__ */ jsx5("clipPath", { id: "rs-pb-clip", children: /* @__PURE__ */ jsx5("path", { fill: "#fff", d: "M0 0h72v16H0z" }) }) })
1788
- ]
1789
- }
1790
- );
1791
- function PoweredBy() {
1792
- return /* @__PURE__ */ jsxs4("div", { className: "rs-powered-by", "aria-label": "Powered by Rhinestone", children: [
1793
- /* @__PURE__ */ jsx5("span", { children: "Powered by" }),
1794
- /* @__PURE__ */ jsx5(
1795
- "a",
1796
- {
1797
- className: "rs-powered-by-link",
1798
- href: "https://www.rhinestone.dev",
1799
- target: "_blank",
1800
- rel: "noopener noreferrer",
1801
- children: rhinestoneLogo
1802
- }
1803
- )
1804
- ] });
1805
- }
1806
- PoweredBy.displayName = "PoweredBy";
1807
-
1808
- // src/components/ui/Spinner.tsx
1809
- import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1810
- function Spinner({ className }) {
1811
- return /* @__PURE__ */ jsxs5(
1812
- "svg",
1813
- {
1814
- className: `rs-spinner ${className || ""}`,
1815
- fill: "none",
1816
- viewBox: "0 0 20 21",
1817
- children: [
1818
- /* @__PURE__ */ jsx6(
1819
- "path",
1820
- {
1821
- d: "M10 0.5C8.02 0.5 6.08 1.08 4.44 2.18C2.79 3.28 1.51 4.84 0.76 6.67C0.00 8.50 -0.19 10.51 0.19 12.45C0.57 14.39 1.53 16.17 2.92 17.57C4.32 18.96 6.10 19.92 8.04 20.30C9.98 20.69 11.99 20.49 13.82 19.73C15.65 18.98 17.21 17.70 18.31 16.05C19.41 14.41 20 12.47 20 10.5C20 7.84 18.94 5.30 17.07 3.42C15.19 1.55 12.65 0.5 10 0.5ZM10 17.77C8.56 17.77 7.15 17.34 5.95 16.54C4.76 15.74 3.83 14.61 3.28 13.28C2.73 11.95 2.58 10.49 2.86 9.08C3.14 7.67 3.84 6.37 4.85 5.35C5.87 4.34 7.17 3.64 8.58 3.36C9.99 3.08 11.45 3.23 12.78 3.78C14.11 4.33 15.24 5.26 16.04 6.45C16.84 7.65 17.27 9.06 17.27 10.5C17.27 12.42 16.50 14.27 15.14 15.64C13.77 17.00 11.92 17.77 10 17.77Z",
1822
- fill: "currentColor",
1823
- opacity: 0.3
1824
- }
1825
- ),
1826
- /* @__PURE__ */ jsx6(
1827
- "path",
1828
- {
1829
- d: "M10 3.22C11.74 3.22 13.42 3.84 14.75 4.95C16.08 6.07 16.96 7.61 17.25 9.31C17.30 9.64 17.46 9.94 17.71 10.15C17.96 10.37 18.28 10.49 18.62 10.5C18.82 10.50 19.01 10.45 19.20 10.37C19.38 10.29 19.54 10.16 19.67 10.01C19.80 9.86 19.89 9.68 19.95 9.49C20.00 9.30 20.01 9.10 19.98 8.90C19.59 6.56 18.38 4.42 16.55 2.88C14.72 1.34 12.40 0.5 10 0.5C7.59 0.5 5.27 1.34 3.44 2.88C1.61 4.42 0.40 6.56 0.01 8.90C-0.01 9.10 -0.00 9.30 0.04 9.49C0.10 9.68 0.19 9.86 0.32 10.01C0.45 10.16 0.61 10.29 0.79 10.37C0.98 10.45 1.17 10.50 1.37 10.5C1.71 10.49 2.03 10.37 2.28 10.15C2.53 9.94 2.69 9.64 2.74 9.31C3.03 7.61 3.91 6.07 5.24 4.95C6.57 3.84 8.25 3.22 10 3.22Z",
1830
- fill: "currentColor"
1831
- }
1832
- )
1833
- ]
1834
- }
1835
- );
1836
- }
1837
-
1838
- // src/components/steps/ConnectStep.tsx
1839
- import { useEffect as useEffect3, useState } from "react";
1840
-
1841
- // src/components/ui/ListRow.tsx
1842
- import { Fragment, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1843
- function ListRow({
1844
- leading,
1845
- leadingMedia,
1846
- title,
1847
- subtitle,
1848
- meta,
1849
- trailing,
1850
- action,
1851
- className = "",
1852
- onClick,
1853
- disabled,
1854
- ...props
1855
- }) {
1856
- const inner = /* @__PURE__ */ jsxs6(Fragment, { children: [
1857
- leadingMedia ? /* @__PURE__ */ jsx7("span", { className: "rs-list-row-leading rs-list-row-leading--media", children: /* @__PURE__ */ jsx7("img", { src: leadingMedia, alt: "" }) }) : leading ? /* @__PURE__ */ jsx7("span", { className: "rs-list-row-leading", children: leading }) : null,
1858
- /* @__PURE__ */ jsxs6("div", { className: "rs-list-row-body", children: [
1859
- /* @__PURE__ */ jsxs6("div", { className: "rs-list-row-text", children: [
1860
- /* @__PURE__ */ jsx7("span", { className: "rs-list-row-title", children: title }),
1861
- subtitle && /* @__PURE__ */ jsx7("span", { className: "rs-list-row-subtitle", children: subtitle })
1862
- ] }),
1863
- action ? /* @__PURE__ */ jsx7(
1864
- "button",
1865
- {
1866
- type: "button",
1867
- className: "rs-list-row-action",
1868
- disabled,
1869
- onClick: (e) => {
1870
- e.stopPropagation();
1871
- action.onClick();
1872
- },
1873
- children: action.label
1874
- }
1875
- ) : meta && /* @__PURE__ */ jsx7("div", { className: "rs-list-row-meta", children: meta })
1876
- ] }),
1877
- /* @__PURE__ */ jsx7("span", { className: "rs-list-row-chevron", children: trailing ?? /* @__PURE__ */ jsx7(ChevronRightIcon, {}) })
1878
- ] });
1879
- if (action) {
1880
- const handleKey = (e) => {
1881
- if (disabled) return;
1882
- if (e.key === "Enter" || e.key === " ") {
1883
- e.preventDefault();
1884
- onClick?.(e);
1885
- }
1886
- };
1887
- return /* @__PURE__ */ jsx7(
1888
- "div",
1889
- {
1890
- className: `rs-list-row ${className}`.trim(),
1891
- role: "button",
1892
- tabIndex: disabled ? -1 : 0,
1893
- "aria-disabled": disabled || void 0,
1894
- onClick: disabled ? void 0 : (e) => onClick?.(e),
1895
- onKeyDown: handleKey,
1896
- children: inner
1897
- }
1898
- );
1899
- }
1900
- return /* @__PURE__ */ jsx7(
1901
- "button",
1902
- {
1903
- type: "button",
1904
- className: `rs-list-row ${className}`.trim(),
1905
- onClick,
1906
- disabled,
1907
- ...props,
1908
- children: inner
1909
- }
1910
- );
1911
- }
1912
- ListRow.displayName = "ListRow";
1913
-
1914
- // src/components/ui/SegmentedToggle.tsx
1915
- import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1916
- var SEGMENTED_INSET_PX = 2;
1917
- function SegmentedToggle({
1918
- options,
1919
- value,
1920
- onChange,
1921
- ariaLabel
1922
- }) {
1923
- const activeIndex = Math.max(
1924
- 0,
1925
- options.findIndex((opt) => opt.value === value)
1926
- );
1927
- const count = Math.max(options.length, 1);
1928
- const totalInsetPx = SEGMENTED_INSET_PX * (count + 1);
1929
- const offsetPercent = activeIndex / count * 100;
1930
- const offsetCorrectionPx = activeIndex * SEGMENTED_INSET_PX / count;
1931
- const segmentedStyle = {
1932
- "--rs-segmented-count": count,
1933
- "--rs-segmented-index": activeIndex,
1934
- "--rs-segmented-inset": `${SEGMENTED_INSET_PX}px`,
1935
- "--rs-segmented-thumb-width": `calc((100% - ${totalInsetPx}px) / ${count})`,
1936
- "--rs-segmented-thumb-offset": `calc(${offsetPercent}% - ${offsetCorrectionPx}px)`
1937
- };
1938
- return /* @__PURE__ */ jsxs7(
1939
- "div",
1940
- {
1941
- className: "rs-segmented",
1942
- role: "tablist",
1943
- "aria-label": ariaLabel,
1944
- style: segmentedStyle,
1945
- children: [
1946
- /* @__PURE__ */ jsx8(
1947
- "span",
1948
- {
1949
- className: "rs-segmented-thumb",
1950
- "data-value": value,
1951
- "aria-hidden": "true"
1952
- }
1953
- ),
1954
- options.map((opt) => {
1955
- const active = opt.value === value;
1956
- return /* @__PURE__ */ jsx8(
1957
- "button",
1958
- {
1959
- type: "button",
1960
- role: "tab",
1961
- "aria-selected": active,
1962
- className: `rs-segmented-option${active ? " rs-segmented-option--active" : ""}`,
1963
- onClick: () => onChange(opt.value),
1964
- children: opt.label
1965
- },
1966
- opt.value
1967
- );
1968
- })
1969
- ]
1970
- }
1971
- );
1972
- }
1973
- SegmentedToggle.displayName = "SegmentedToggle";
1974
-
1975
- // src/components/ui/WalletBadgeIcons/RabbyIcon.tsx
1976
- import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1977
- function RabbyIcon() {
1978
- return /* @__PURE__ */ jsxs8(
1979
- "svg",
1980
- {
1981
- width: "20",
1982
- height: "20",
1983
- viewBox: "0 0 20 20",
1984
- fill: "none",
1985
- xmlns: "http://www.w3.org/2000/svg",
1986
- children: [
1987
- /* @__PURE__ */ jsxs8("g", { clipPath: "url(#rs-rabby-clip)", children: [
1988
- /* @__PURE__ */ jsx9(
1989
- "mask",
1990
- {
1991
- id: "rs-rabby-mask",
1992
- style: { maskType: "luminance" },
1993
- maskUnits: "userSpaceOnUse",
1994
- x: "0",
1995
- y: "0",
1996
- width: "20",
1997
- height: "20",
1998
- children: /* @__PURE__ */ jsx9(
1999
- "path",
2000
- {
2001
- d: "M20 10C20 4.47 15.52 0 10 0C4.47 0 0 4.47 0 10C0 15.52 4.47 20 10 20C15.52 20 20 15.52 20 10Z",
2002
- fill: "white"
2003
- }
2004
- )
2005
- }
2006
- ),
2007
- /* @__PURE__ */ jsxs8("g", { mask: "url(#rs-rabby-mask)", children: [
2008
- /* @__PURE__ */ jsx9(
2009
- "path",
2010
- {
2011
- d: "M20 10C20 4.47 15.52 0 10 0C4.47 0 0 4.47 0 10C0 15.52 4.47 20 10 20C15.52 20 20 15.52 20 10Z",
2012
- fill: "#7084FF"
2013
- }
2014
- ),
2015
- /* @__PURE__ */ jsx9(
2016
- "path",
2017
- {
2018
- d: "M17.25 10.86C17.82 9.57 14.98 5.97 12.26 4.47C10.55 3.31 8.77 3.47 8.41 3.98C7.62 5.10 11.03 6.05 13.32 7.16C12.83 7.37 12.36 7.76 12.09 8.25C11.24 7.31 9.37 6.51 7.18 7.16C5.70 7.59 4.47 8.62 3.99 10.18C3.85 10.11 3.70 10.09 3.54 10.10C3.39 10.11 3.24 10.16 3.11 10.25C2.98 10.33 2.87 10.45 2.80 10.58C2.72 10.72 2.69 10.87 2.69 11.03C2.69 11.55 3.10 11.96 3.62 11.96C3.71 11.96 4.01 11.90 4.01 11.90L8.77 11.93C6.87 14.96 5.36 15.41 5.36 15.93C5.36 16.46 6.80 16.32 7.34 16.12C9.93 15.18 12.71 12.26 13.19 11.42C15.19 11.67 16.87 11.70 17.25 10.86Z",
2019
- fill: "url(#rs-rabby-grad0)"
2020
- }
2021
- ),
2022
- /* @__PURE__ */ jsx9(
2023
- "path",
2024
- {
2025
- fillRule: "evenodd",
2026
- clipRule: "evenodd",
2027
- d: "M13.31 7.15L13.32 7.16C13.42 7.11 13.41 6.96 13.38 6.83C13.31 6.55 12.16 5.41 11.07 4.90C9.60 4.20 8.51 4.23 8.35 4.56C8.65 5.18 10.04 5.76 11.50 6.36C12.12 6.62 12.75 6.88 13.31 7.15Z",
2028
- fill: "url(#rs-rabby-grad1)"
2029
- }
2030
- ),
2031
- /* @__PURE__ */ jsx9(
2032
- "path",
2033
- {
2034
- fillRule: "evenodd",
2035
- clipRule: "evenodd",
2036
- d: "M11.45 13.38C11.11 13.26 10.77 13.15 10.43 13.07C10.84 12.33 10.92 11.25 10.54 10.56C10.00 9.60 9.32 9.08 7.73 9.08C6.87 9.08 4.53 9.38 4.48 11.34C4.48 11.54 4.48 11.73 4.50 11.90L8.77 11.93C8.20 12.85 7.66 13.53 7.18 14.05C7.75 14.19 8.22 14.32 8.65 14.43C9.06 14.54 9.43 14.63 9.82 14.73C10.41 14.30 10.96 13.83 11.45 13.38Z",
2037
- fill: "url(#rs-rabby-grad2)"
2038
- }
2039
- ),
2040
- /* @__PURE__ */ jsx9(
2041
- "path",
2042
- {
2043
- d: "M3.94 11.70C4.11 13.19 4.96 13.77 6.68 13.94C8.40 14.12 9.39 14.00 10.71 14.12C11.81 14.22 12.79 14.78 13.15 14.59C13.48 14.42 13.30 13.78 12.86 13.38C12.29 12.85 11.50 12.49 10.12 12.36C10.39 11.60 10.32 10.54 9.89 9.96C9.27 9.12 8.13 8.75 6.68 8.91C5.17 9.08 3.72 9.83 3.94 11.70Z",
2044
- fill: "url(#rs-rabby-grad3)"
2045
- }
2046
- )
2047
- ] })
2048
- ] }),
2049
- /* @__PURE__ */ jsxs8("defs", { children: [
2050
- /* @__PURE__ */ jsxs8(
2051
- "linearGradient",
2052
- {
2053
- id: "rs-rabby-grad0",
2054
- x1: "7.00",
2055
- y1: "9.72",
2056
- x2: "17.13",
2057
- y2: "12.58",
2058
- gradientUnits: "userSpaceOnUse",
2059
- children: [
2060
- /* @__PURE__ */ jsx9("stop", { stopColor: "white" }),
2061
- /* @__PURE__ */ jsx9("stop", { offset: "1", stopColor: "white" })
2062
- ]
2063
- }
2064
- ),
2065
- /* @__PURE__ */ jsxs8(
2066
- "linearGradient",
2067
- {
2068
- id: "rs-rabby-grad1",
2069
- x1: "15.42",
2070
- y1: "9.53",
2071
- x2: "8.09",
2072
- y2: "2.21",
2073
- gradientUnits: "userSpaceOnUse",
2074
- children: [
2075
- /* @__PURE__ */ jsx9("stop", { stopColor: "#8697FF" }),
2076
- /* @__PURE__ */ jsx9("stop", { offset: "1", stopColor: "#8697FF", stopOpacity: "0" })
2077
- ]
2078
- }
2079
- ),
2080
- /* @__PURE__ */ jsxs8(
2081
- "linearGradient",
2082
- {
2083
- id: "rs-rabby-grad2",
2084
- x1: "11.65",
2085
- y1: "13.64",
2086
- x2: "4.63",
2087
- y2: "9.61",
2088
- gradientUnits: "userSpaceOnUse",
2089
- children: [
2090
- /* @__PURE__ */ jsx9("stop", { stopColor: "#8697FF" }),
2091
- /* @__PURE__ */ jsx9("stop", { offset: "1", stopColor: "#8697FF", stopOpacity: "0" })
2092
- ]
2093
- }
2094
- ),
2095
- /* @__PURE__ */ jsxs8(
2096
- "linearGradient",
2097
- {
2098
- id: "rs-rabby-grad3",
2099
- x1: "7.61",
2100
- y1: "9.64",
2101
- x2: "12.37",
2102
- y2: "15.67",
2103
- gradientUnits: "userSpaceOnUse",
2104
- children: [
2105
- /* @__PURE__ */ jsx9("stop", { stopColor: "white" }),
2106
- /* @__PURE__ */ jsx9("stop", { offset: "0.98", stopColor: "#D1D8FF" })
2107
- ]
2108
- }
2109
- ),
2110
- /* @__PURE__ */ jsx9("clipPath", { id: "rs-rabby-clip", children: /* @__PURE__ */ jsx9("rect", { width: "20", height: "20", fill: "white" }) })
2111
- ] })
2112
- ]
2113
- }
2114
- );
2115
- }
2116
-
2117
- // src/components/ui/WalletBadgeIcons/PhantomIcon.tsx
2118
- import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
2119
- function PhantomIcon() {
2120
- return /* @__PURE__ */ jsxs9(
2121
- "svg",
2122
- {
2123
- width: "20",
2124
- height: "20",
2125
- viewBox: "0 0 20 20",
2126
- fill: "none",
2127
- xmlns: "http://www.w3.org/2000/svg",
2128
- children: [
2129
- /* @__PURE__ */ jsx10(
2130
- "path",
2131
- {
2132
- d: "M15.18 0H4.81C2.15 0 0 2.15 0 4.81V15.18C0 17.84 2.15 20 4.81 20H15.18C17.84 20 20 17.84 20 15.18V4.81C20 2.15 17.84 0 15.18 0Z",
2133
- fill: "#AB9FF2"
2134
- }
2135
- ),
2136
- /* @__PURE__ */ jsx10(
2137
- "path",
2138
- {
2139
- fillRule: "evenodd",
2140
- clipRule: "evenodd",
2141
- d: "M8.61 12.94C7.77 14.23 6.37 15.85 4.50 15.85C3.62 15.85 2.77 15.49 2.77 13.91C2.77 9.89 8.26 3.67 13.35 3.67C16.25 3.67 17.40 5.68 17.40 7.96C17.40 10.89 15.50 14.24 13.61 14.24C13.01 14.24 12.72 13.91 12.72 13.39C12.72 13.25 12.74 13.10 12.79 12.94C12.14 14.04 10.90 15.07 9.73 15.07C8.88 15.07 8.45 14.53 8.45 13.78C8.45 13.51 8.51 13.23 8.61 12.94ZM15.49 7.88C15.49 8.54 15.10 8.88 14.66 8.88C14.21 8.88 13.83 8.54 13.83 7.88C13.83 7.21 14.21 6.88 14.66 6.88C15.10 6.88 15.49 7.22 15.49 7.88ZM13.00 7.88C13.00 8.54 12.60 8.88 12.17 8.88C11.72 8.88 11.33 8.54 11.33 7.88C11.33 7.22 11.72 6.88 12.17 6.88C12.60 6.88 13.00 7.22 13.00 7.88",
2142
- fill: "#FFFDF8"
2143
- }
2144
- )
2145
- ]
2146
- }
2147
- );
2148
- }
2149
-
2150
- // src/components/ui/WalletBadgeIcons/WalletConnectIcon.tsx
2151
- import { jsx as jsx11, jsxs as jsxs10 } from "react/jsx-runtime";
2152
- function WalletConnectIcon() {
2153
- return /* @__PURE__ */ jsxs10(
2154
- "svg",
2155
- {
2156
- width: "20",
2157
- height: "20",
2158
- viewBox: "0 0 20 20",
2159
- fill: "none",
2160
- xmlns: "http://www.w3.org/2000/svg",
2161
- children: [
2162
- /* @__PURE__ */ jsx11("rect", { width: "20", height: "20", rx: "2.5", fill: "#3B99FC" }),
2163
- /* @__PURE__ */ jsx11(
2164
- "path",
2165
- {
2166
- d: "M6.18 7.96a5.36 5.36 0 0 1 7.64 0l.25.26a.26.26 0 0 1 0 .37l-.87.87a.13.13 0 0 1-.19 0l-.35-.35a3.74 3.74 0 0 0-5.32 0l-.38.37a.13.13 0 0 1-.19 0l-.86-.86a.26.26 0 0 1 0-.37l.27-.29Zm9.43 1.79.78.78a.26.26 0 0 1 0 .37l-3.54 3.54a.26.26 0 0 1-.37 0l-2.51-2.5a.07.07 0 0 0-.09 0l-2.51 2.5a.26.26 0 0 1-.37 0L3.46 10.9a.26.26 0 0 1 0-.37l.78-.78a.26.26 0 0 1 .37 0l2.5 2.5a.07.07 0 0 0 .1 0L9.72 9.75a.26.26 0 0 1 .37 0l2.5 2.5a.07.07 0 0 0 .1 0l2.5-2.5a.26.26 0 0 1 .37 0Z",
2167
- fill: "#fff"
2168
- }
2169
- )
2170
- ]
2171
- }
2172
- );
2173
- }
2174
-
2175
- // src/components/ui/WalletBadgeIcons/EthBadgeIcon.tsx
2176
- import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
2177
- function EthBadgeIcon() {
2178
- return /* @__PURE__ */ jsxs11(
2179
- "svg",
2180
- {
2181
- width: "20",
2182
- height: "20",
2183
- viewBox: "0 0 20 20",
2184
- fill: "none",
2185
- xmlns: "http://www.w3.org/2000/svg",
2186
- children: [
2187
- /* @__PURE__ */ jsx12(
2188
- "path",
2189
- {
2190
- d: "M9.99 19.93C15.48 19.93 19.93 15.48 19.93 9.99C19.93 4.51 15.48 0.06 9.99 0.06C4.51 0.06 0.06 4.51 0.06 9.99C0.06 15.48 4.51 19.93 9.99 19.93Z",
2191
- fill: "#E3E3E3"
2192
- }
2193
- ),
2194
- /* @__PURE__ */ jsx12("path", { d: "M10.00 2.18L14.69 9.99L10.02 7.98L10.00 2.18Z", fill: "#2F3030" }),
2195
- /* @__PURE__ */ jsx12("path", { d: "M5.31 9.99L9.98 2.18L10.00 7.98L5.31 9.99Z", fill: "#828384" }),
2196
- /* @__PURE__ */ jsx12("path", { d: "M9.98 12.80L5.31 10.04L10.00 8.11L9.98 12.80Z", fill: "#343535" }),
2197
- /* @__PURE__ */ jsx12("path", { d: "M14.69 10.04L10.02 8.11L10.00 12.80L14.69 10.04Z", fill: "#131313" }),
2198
- /* @__PURE__ */ jsx12("path", { d: "M10.00 14.00L14.69 11.24L10.00 17.80V14.00Z", fill: "#2F3030" }),
2199
- /* @__PURE__ */ jsx12("path", { d: "M10.00 14.00L5.31 11.24L10.00 17.80V14.00Z", fill: "#828384" })
2200
- ]
2201
- }
2202
- );
2203
- }
2204
-
2205
- // src/components/ui/WalletBadgeIcons/SolBadgeIcon.tsx
2206
- import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
2207
- function SolBadgeIcon() {
2208
- return /* @__PURE__ */ jsxs12(
2209
- "svg",
2210
- {
2211
- width: "20",
2212
- height: "20",
2213
- viewBox: "0 0 20 20",
2214
- fill: "none",
2215
- xmlns: "http://www.w3.org/2000/svg",
2216
- children: [
2217
- /* @__PURE__ */ jsx13("rect", { width: "20", height: "20", rx: "10", fill: "#0C0C0C" }),
2218
- /* @__PURE__ */ jsx13(
2219
- "path",
2220
- {
2221
- fillRule: "evenodd",
2222
- clipRule: "evenodd",
2223
- d: "M4.62 9.04H13.87C13.99 9.04 14.10 9.08 14.18 9.17L15.64 10.64C15.91 10.91 15.72 11.38 15.34 11.38H6.08C5.97 11.38 5.86 11.33 5.78 11.25L4.31 9.78C4.04 9.51 4.23 9.04 4.62 9.04ZM4.31 7.09L5.77 5.62C5.86 5.53 5.97 5.49 6.08 5.49H15.33C15.71 5.49 15.91 5.95 15.63 6.22L14.17 7.70C14.09 7.78 13.98 7.82 13.87 7.82H4.62C4.23 7.82 4.04 7.36 4.31 7.09ZM15.64 13.34L14.17 14.81C14.09 14.89 13.98 14.94 13.87 14.94H4.62C4.23 14.94 4.04 14.48 4.31 14.20L5.77 12.73C5.86 12.65 5.97 12.60 6.08 12.60H15.33C15.72 12.6 15.91 13.06 15.64 13.34Z",
2224
- fill: "url(#rs-sol-badge-grad)"
2225
- }
2226
- ),
2227
- /* @__PURE__ */ jsx13("defs", { children: /* @__PURE__ */ jsxs12(
2228
- "linearGradient",
2229
- {
2230
- id: "rs-sol-badge-grad",
2231
- x1: "4.85",
2232
- y1: "15.34",
2233
- x2: "15.11",
2234
- y2: "5.08",
2235
- gradientUnits: "userSpaceOnUse",
2236
- children: [
2237
- /* @__PURE__ */ jsx13("stop", { stopColor: "#CB4EE8" }),
2238
- /* @__PURE__ */ jsx13("stop", { offset: "1", stopColor: "#10F4B1" })
2239
- ]
2240
- }
2241
- ) })
2242
- ]
2243
- }
2244
- );
2245
- }
2246
-
2247
- // src/components/ui/WalletBadgeIcons/BaseBadgeIcon.tsx
2248
- import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
2249
- function BaseBadgeIcon() {
2250
- return /* @__PURE__ */ jsxs13(
2251
- "svg",
2252
- {
2253
- width: "20",
2254
- height: "20",
2255
- viewBox: "0 0 111 111",
2256
- fill: "none",
2257
- xmlns: "http://www.w3.org/2000/svg",
2258
- children: [
2259
- /* @__PURE__ */ jsx14("circle", { cx: "55.5", cy: "55.5", r: "55.5", fill: "#0052FF" }),
2260
- /* @__PURE__ */ jsx14(
2261
- "path",
2262
- {
2263
- d: "M54.92 93.4c20.94 0 37.92-16.97 37.92-37.92S75.86 17.55 54.92 17.55c-19.49 0-35.57 14.72-37.65 33.64h49.82v5.54h-49.82C19.35 75.67 35.42 93.4 54.92 93.4z",
2264
- fill: "#fff"
2265
- }
2266
- )
2267
- ]
2268
- }
2269
- );
2270
- }
2271
-
2272
- // src/components/ui/WalletBadgeIcons/index.tsx
2273
- import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
2274
- function WalletBadgeIcons() {
2275
- return /* @__PURE__ */ jsxs14("span", { className: "rs-list-row-meta-icons", children: [
2276
- /* @__PURE__ */ jsx15("span", { children: /* @__PURE__ */ jsx15(RabbyIcon, {}) }),
2277
- /* @__PURE__ */ jsx15("span", { children: /* @__PURE__ */ jsx15(PhantomIcon, {}) }),
2278
- /* @__PURE__ */ jsx15("span", { children: /* @__PURE__ */ jsx15(WalletConnectIcon, {}) })
2279
- ] });
2280
- }
2281
- WalletBadgeIcons.displayName = "WalletBadgeIcons";
2282
- function ChainBadgeIcons() {
2283
- return /* @__PURE__ */ jsxs14("span", { className: "rs-list-row-meta-icons", children: [
2284
- /* @__PURE__ */ jsx15("span", { children: /* @__PURE__ */ jsx15(EthBadgeIcon, {}) }),
2285
- /* @__PURE__ */ jsx15("span", { children: /* @__PURE__ */ jsx15(SolBadgeIcon, {}) }),
2286
- /* @__PURE__ */ jsx15("span", { children: /* @__PURE__ */ jsx15(BaseBadgeIcon, {}) })
2287
- ] });
2288
- }
2289
- ChainBadgeIcons.displayName = "ChainBadgeIcons";
2290
-
2291
- // src/components/ui/ExchangeLogos.tsx
2292
- import { jsx as jsx16 } from "react/jsx-runtime";
2293
- var EXCHANGE_LOGO_SOURCES = {
2294
- binance: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwIiBoZWlnaHQ9IjI1MCIgdmlld0JveD0iMCAwIDI1MCAyNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyNTAiIGhlaWdodD0iMjUwIiBmaWxsPSIjMEMwRTEyIi8+CjxwYXRoIGQ9Ik05Mi4zMDEgMTExLjczNkwxMjUuMzE5IDc4LjczMTdMMTU4LjM1MSAxMTEuNzYzTDE3Ny41NTIgOTIuNTQ4NkwxMjUuMzE5IDQwLjMwMjJMNzMuMDg2MyA5Mi41MzUyTDkyLjMwMSAxMTEuNzM2WiIgZmlsbD0iI0YzQkEyRiIvPgo8cGF0aCBkPSJNNDAuMzAzIDEyNS4zMDhMNTkuNTEwNyAxMDYuMUw3OC43MTg0IDEyNS4zMDhMNTkuNTEwNyAxNDQuNTE2TDQwLjMwMyAxMjUuMzA4WiIgZmlsbD0iI0YzQkEyRiIvPgo8cGF0aCBkPSJNOTIuMzAxMiAxMzguODczTDEyNS4zMTkgMTcxLjg5MUwxNTguMzUxIDEzOC44NkwxNzcuNTY2IDE1OC4wNDhMMTc3LjU1MiAxNTguMDYxTDEyNS4zMTkgMjEwLjMwOEw3My4wODY0IDE1OC4wODhMNzMuMDU5NiAxNTguMDYxTDkyLjMwMTIgMTM4Ljg3M1oiIGZpbGw9IiNGM0JBMkYiLz4KPHBhdGggZD0iTTE3MS44ODcgMTI1LjMxMkwxOTEuMDk1IDEwNi4xMDVMMjEwLjMwMyAxMjUuMzEyTDE5MS4wOTUgMTQ0LjUyTDE3MS44ODcgMTI1LjMxMloiIGZpbGw9IiNGM0JBMkYiLz4KPHBhdGggZD0iTTE0NC44MDMgMTI1LjI5OEwxMjUuMzE5IDEwNS44MDJMMTEwLjkxMiAxMjAuMjA5TDEwOS4yNDcgMTIxLjg2MUwxMDUuODM2IDEyNS4yNzJMMTA1LjgwOSAxMjUuMjk4TDEwNS44MzYgMTI1LjMzOUwxMjUuMzE5IDE0NC44MDlMMTQ0LjgwMyAxMjUuMzEyTDE0NC44MTYgMTI1LjI5OEgxNDQuODAzWiIgZmlsbD0iI0YzQkEyRiIvPgo8L3N2Zz4K",
2295
- bitfinex: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwIiBoZWlnaHQ9IjI1MCIgdmlld0JveD0iMCAwIDI1MCAyNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyNTAiIGhlaWdodD0iMjUwIiBmaWxsPSJ1cmwoI3BhaW50MF9saW5lYXJfNDc2OV8xNTk5NjEpIi8+CjxwYXRoIGQ9Ik00Ni40NDQ4IDE4NS42MTJDNTQuMjc0NSAxOTMuOTE1IDk3LjMyOTcgMjMzLjcwMSAxNjQuOTA0IDE4Ny41MjRDMjEzLjc3OCAxNDkuNDcxIDIxMi41NTIgNjYuOTczIDIwNy44NjEgNDIuMDQ1NUMyMDYuMjI2IDQ1LjY3NDMgMTQ5LjUyMiAxNjkuOTY5IDQ2LjQ0NDggMTg1LjYxMlpNMjA3Ljg2MSA0Mi4wMjkxQzIwNy4yNTYgNDEuNzgzOSAxNDQuMzkgMzMuMjE4NyA4Mi4yNDI0IDczLjI0OThDNDMuNjQ5NiA5OC4wOTU2IDM4LjUzMzQgMTM0LjQ4MiA0MC4yOTg3IDE1OC43ODhDMTMwLjY0MyAxNDguNjIxIDIwNS44MDEgNDQuODg5NyAyMDcuODYxIDQyLjAyOTFaIiBmaWxsPSIjMDJDQTlCIi8+CjxwYXRoIGQ9Ik0yMDcuODYxIDQyLjAyOTFDMjA3LjI1NiA0MS43ODM5IDE0NC4zOSAzMy4yMTg3IDgyLjI0MjQgNzMuMjQ5OEM0My42NDk2IDk4LjA5NTYgMzguNTMzNCAxMzQuNDgyIDQwLjI5ODcgMTU4Ljc4OEMxMzAuNjQzIDE0OC42MjEgMjA1LjgwMSA0NC44ODk3IDIwNy44NjEgNDIuMDI5MVoiIGZpbGw9IiMwMkNBOUIiLz4KPGRlZnM+CjxsaW5lYXJHcmFkaWVudCBpZD0icGFpbnQwX2xpbmVhcl80NzY5XzE1OTk2MSIgeDE9IjI1MCIgeTE9IjcuNTI1MDllLTA2IiB4Mj0iMy4wMDAwMSIgeTI9IjI1Mi41IiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSI+CjxzdG9wIHN0b3AtY29sb3I9IiNCMDJDMkQiLz4KPHN0b3Agb2Zmc2V0PSIwLjMyMTEzMSIgc3RvcC1jb2xvcj0iIzE3MzU1QSIvPgo8c3RvcCBvZmZzZXQ9IjAuNzUiIHN0b3AtY29sb3I9IiMxRTQ0NzQiLz4KPHN0b3Agb2Zmc2V0PSIxIiBzdG9wLWNvbG9yPSIjMDQ3RTYxIi8+CjwvbGluZWFyR3JhZGllbnQ+CjwvZGVmcz4KPC9zdmc+Cg==",
2296
- btcturk: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwIiBoZWlnaHQ9IjI1MCIgdmlld0JveD0iMCAwIDI1MCAyNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyNTAiIGhlaWdodD0iMjUwIiBmaWxsPSJ3aGl0ZSIvPgo8ZyBjbGlwLXBhdGg9InVybCgjY2xpcDBfNDc2OV8xNTk5NzgpIj4KPHBhdGggZD0iTTE0NC44NTIgMTg4LjY4MkMxMzQuOTQ3IDE5NS42ODYgMTI5LjA4NyAyMDQuNDQ3IDEzMS44MyAyMDguMjQzQzEzNC41NzMgMjEyLjA0IDE0NC43MTYgMjA5LjQ1NiAxNTQuNjIxIDIwMi40NjNDMTY0LjUyNyAxOTUuNDcxIDE3MC4zNjMgMTg2LjcxIDE2Ny42NDMgMTgyLjkwMkMxNjYuODA1IDE4MS43NjkgMTY1LjIyOSAxODEuMTQ1IDE2My4xNjcgMTgxLjE0NUMxNTguNjMzIDE4MS4xNDUgMTUxLjY2MyAxODMuODc3IDE0NC44NTIgMTg4LjY4MlpNOTAuNDUxOSAxNzMuNzIyQzcxLjMwOTkgMTgxLjY2NyA1OC4wMzg2IDE5My40NDIgNjAuNzkyNiAyMDAuMTI5QzYzLjU0NjYgMjA2LjgxNSA4MS4yOTQ2IDIwNS44NTIgMTAwLjQ1OSAxOTcuOTUzQzExOS42MjQgMTkwLjA1MyAxMzIuODM5IDE3OC4yNjcgMTMwLjA4NSAxNzEuNTM1QzEyOC44NDkgMTY4LjU0MyAxMjQuNjQ1IDE2Ny4wOTIgMTE4LjY2MSAxNjcuMDkyQzExMS4yMjYgMTY3LjA5MiAxMDEuMDQ5IDE2OS4zNTkgOTAuNDUxOSAxNzMuNzIyWk0xNzguMjE3IDE2NS43ODlDMTc0LjgxNyAxNzIuMjM3IDE3My43NzUgMTc4LjM0NiAxNzUuODQ5IDE3OS4zODlDMTc3LjkyMyAxODAuNDMxIDE4Mi4zMiAxNzYuMTI1IDE4NS42OTcgMTY5LjY3NkMxODkuMDc1IDE2My4yMjcgMTkwLjE0IDE1Ny4xMTkgMTg4LjA2NiAxNTYuMDc2QzE4Ny44NDkgMTU1Ljk2NCAxODcuNjA3IDE1NS45MDkgMTg3LjM2MyAxNTUuOTE3QzE4NS4wOTcgMTU1LjkxNyAxODEuMjQzIDE2MC4wMDkgMTc4LjIxNyAxNjUuNzg5Wk0xNTAuNTc1IDE0Ny45MjdDMTQ0LjAxMyAxNTEuNzEzIDE0MC41OTEgMTU4LjA1OSAxNDIuOTE0IDE2Mi4wOTRDMTQ1LjIzNyAxNjYuMTI5IDE1Mi40MzQgMTY2LjMyMSAxNTguOTk2IDE2Mi41MzZDMTY1LjU1OCAxNTguNzUxIDE2OC45ODEgMTUyLjQwNCAxNjYuNjU3IDE0OC4zNjlDMTY1LjQ0NSAxNDYuMjczIDE2Mi45MTcgMTQ1LjIwNyAxNTkuODU3IDE0NS4yMDdDMTU2LjU4NSAxNDUuMzAyIDE1My4zOTIgMTQ2LjIzOSAxNTAuNTg3IDE0Ny45MjdNMTc0Ljg0IDEzOS4zMjVDMTcyLjkzNiAxNDIuNjIzIDE3My4wNjEgMTQ2LjI3MyAxNzUuMTIzIDE0Ny40NjNDMTc3LjE4NiAxNDguNjUzIDE4MC40MDUgMTQ2Ljk1MyAxODIuMzA5IDE0My42NDNDMTg0LjIxMyAxNDAuMzM0IDE4NC4wODggMTM2LjY5NiAxODIuMDE0IDEzNS41MDZDMTgxLjU3IDEzNS4yNDggMTgxLjA2NSAxMzUuMTE1IDE4MC41NTIgMTM1LjEyMUMxNzguNjI1IDEzNS4xMjEgMTc2LjMzNiAxMzYuNzMgMTc0Ljg4NSAxMzkuMzI1TTE1MC40MDUgMTI1LjE3QzE1MC40MDUgMTI5LjExNCAxNTQuMDMyIDEzMi4zMjEgMTU4LjUwOSAxMzIuMzIxQzE2Mi45ODUgMTMyLjMyMSAxNjYuNjEyIDEyOS4xMTQgMTY2LjYxMiAxMjUuMTdDMTY2LjYxMiAxMjEuMjI2IDE2Mi45ODUgMTE4LjAxOSAxNTguNTA5IDExOC4wMTlDMTU0LjAzMiAxMTguMDE5IDE1MC40MDUgMTIxLjIxNSAxNTAuNDA1IDEyNS4xN1pNOTYuMzExMyAxMjUuMTdDOTYuMzExMyAxMzQuMDIxIDEwNi4yOTYgMTQxLjE5NSAxMTguNjE1IDE0MS4xOTVDMTMwLjkzNSAxNDEuMTk1IDE0MC44OTcgMTM0LjA2NyAxNDAuODk3IDEyNS4xN0MxNDAuODk3IDExNi4yNzMgMTMwLjkzNSAxMDkuMTMzIDExOC42MTUgMTA5LjEzM0MxMDYuMjk2IDEwOS4xMzMgOTYuMzExMyAxMTYuMzE5IDk2LjMxMTMgMTI1LjE3Wk0xNzUuMzUgMTAyLjUwM0MxNzMuMjg3IDEwMy42MzcgMTczLjE2MyAxMDcuMzQzIDE3NS4wNjcgMTEwLjY0MUMxNzYuOTcxIDExMy45MzkgMTgwLjE3OCAxMTUuNjYxIDE4Mi4yNTIgMTE0LjQ2QzE4NC4zMjYgMTEzLjI1OSAxODQuNDM5IDEwOS42MzIgMTgyLjUzNSAxMDYuMzIzQzE4MS4wMzkgMTAzLjczOSAxNzguNzM5IDEwMi4xMTggMTc2Ljg2OSAxMDIuMTE4QzE3Ni4zNTIgMTAyLjExNyAxNzUuODQ1IDEwMi4yNDkgMTc1LjM5NSAxMDIuNTAzTTE0My4xNjMgODcuOTA2QzE0MC44OTcgOTEuOTQwNyAxNDQuMjk3IDk4LjI4NzMgMTUwLjgyNSAxMDIuMDczQzE1Ny4zNTMgMTA1Ljg1OCAxNjQuNTgzIDEwNS42NjUgMTY2LjkwNyAxMDEuNjMxQzE2OS4yMyA5Ny41OTYgMTY1Ljc3MyA5MS4yNjA3IDE1OS4yNDUgODcuNDY0QzE1Ni40MzUgODUuNzc4NCAxNTMuMjM5IDg0Ljg0NTUgMTQ5Ljk2MyA4NC43NTUzQzE0Ni44OTIgODQuNzU1MyAxNDQuMzY1IDg1LjgwOTMgMTQzLjE2MyA4Ny45MDZaTTE3NS44MDMgNzAuNkMxNzMuNzQxIDcxLjczMzMgMTc0Ljc5NSA3Ny43OTY3IDE3OC4xNzIgODQuMkMxODEuNTQ5IDkwLjYwMzMgMTg1Ljk1OCA5NS4wMDA3IDE4OC4wMzIgOTMuOTEyN0MxOTAuMTA2IDkyLjgyNDcgMTg5LjAyOSA4Ni43MTYgMTg1LjY1MiA4MC4zMTI3QzE4Mi42MjYgNzQuNTMyNyAxNzguNzYxIDcwLjQ0MTMgMTc2LjUwNiA3MC40NDEzQzE3Ni4yNjMgNzAuNDQxMiAxNzYuMDIzIDcwLjQ5NTQgMTc1LjgwMyA3MC42Wk02MC43OTI2IDQ5LjkxNjdDNTguMDM4NiA1Ni42MDMzIDcxLjMyMTMgNjguNDM1MyA5MC40NTE5IDc2LjMzNDdDMTA5LjU4MyA4NC4yMzQgMTI3LjI5NyA4NS4yMDg3IDEzMC4wODUgNzguNTMzM0MxMzIuODczIDcxLjg1OCAxMTkuNTU2IDYwLjAwMzMgMTAwLjQyNSA1Mi4xMDRDODkuODI4NiA0Ny43MjkzIDc5LjY5NjYgNDUuNDc0IDcyLjIxNjYgNDUuNDc0QzY2LjIzMjYgNDUuNDc0IDYyLjAxNjYgNDYuOTM2IDYwLjc5MjYgNDkuOTE2N1pNMTMxLjcyOCA0MS43NTY3QzEyOS4wNDIgNDUuNTY0NyAxMzQuOTAxIDU0LjMxNCAxNDQuODA3IDYxLjMxOEMxNTQuNzEyIDY4LjMyMiAxNjQuOTIzIDcwLjkwNiAxNjcuNTk4IDY3LjA5OEMxNzAuMjczIDYzLjI5IDE2NC40MjUgNTQuNTQwNyAxNTQuNDk3IDQ3LjUzNjdDMTQ3LjY5NyA0Mi43MzEzIDE0MC43NjEgNDAgMTM2LjIwNSA0MEMxMzQuMTQyIDQwIDEzMi41NjcgNDAuNTY2NyAxMzEuNjcxIDQxLjc1NjciIGZpbGw9ImJsYWNrIi8+CjwvZz4KPGRlZnM+CjxjbGlwUGF0aCBpZD0iY2xpcDBfNDc2OV8xNTk5NzgiPgo8cmVjdCB3aWR0aD0iMTI4LjY5IiBoZWlnaHQ9IjE3MCIgZmlsbD0id2hpdGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDYwLjQzMDEgNDApIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg==",
2297
- bybit: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwIiBoZWlnaHQ9IjI1MCIgdmlld0JveD0iMCAwIDI1MCAyNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyNTAiIGhlaWdodD0iMjUwIiBmaWxsPSJibGFjayIvPgo8cGF0aCBkPSJNMTY4LjI2IDE0Mi45NDhWOTFIMTc4LjY0M1YxNDIuOTQ4SDE2OC4yNloiIGZpbGw9IiNGN0E2MDAiLz4KPHBhdGggZD0iTTQ3LjI1NzkgMTU4LjM3OEgyNVYxMDYuNDMxSDQ2LjM2MzhDNTYuNzQ2NCAxMDYuNDMxIDYyLjc5NDkgMTEyLjEyMyA2Mi43OTQ5IDEyMS4wMjNDNjIuNzk0OSAxMjYuNzg1IDU4LjkwODkgMTMwLjUxIDU2LjIxOTcgMTMxLjc1QzU5LjQzMTEgMTMzLjIwNyA2My41Mzg5IDEzNi40OTEgNjMuNTM4OSAxNDMuNDI0QzYzLjUzODkgMTUzLjEyNSA1Ni43NDY0IDE1OC4zNzggNDcuMjU3OSAxNTguMzc4Wk00NS41NDEzIDExNS40NzlIMzUuMzgyN1YxMjcuNDQ1SDQ1LjUzOUM0OS45NDQ4IDEyNy40NDUgNTIuNDA5OSAxMjUuMDM4IDUyLjQwOTkgMTIxLjQ1OUM1Mi40MDk5IDExNy44ODggNDkuOTQ3MSAxMTUuNDc5IDQ1LjU0MTMgMTE1LjQ3OVpNNDYuMjExMyAxMzYuNTY1SDM1LjM4NVYxNDkuMzM1SDQ2LjIxNTlDNTAuOTIyMSAxNDkuMzM1IDUzLjE1ODUgMTQ2LjQxNyA1My4xNTg1IDE0Mi45MTNDNTMuMTU4NSAxMzkuNDExIDUwLjkxNzQgMTM2LjU2NSA0Ni4yMTU5IDEzNi41NjVINDYuMjExM1pNOTUuMjA2OCAxMzcuMDc2VjE1OC4zNzhIODQuODk4VjEzNy4wNzZMNjguOTEyNyAxMDYuNDMxSDgwLjE5MThMOTAuMTI2MyAxMjcuMzcxTDk5LjkxMDYgMTA2LjQzMUgxMTEuMTg3TDk1LjIwNjggMTM3LjA3NlpNMTQwLjYyNCAxNTguMzc4SDExOC4zNjZWMTA2LjQzMUgxMzkuNzI3QzE1MC4xMSAxMDYuNDMxIDE1Ni4xNjEgMTEyLjEyMyAxNTYuMTYxIDEyMS4wMjNDMTU2LjE2MSAxMjYuNzg1IDE1Mi4yNzUgMTMwLjUxIDE0OS41ODUgMTMxLjc1QzE1Mi43OTcgMTMzLjIwNyAxNTYuOTA1IDEzNi40OTEgMTU2LjkwNSAxNDMuNDI0QzE1Ni45MDUgMTUzLjEyNSAxNTAuMTEyIDE1OC4zNzggMTQwLjYyNCAxNTguMzc4Wk0xMzguOTA3IDExNS40NzlIMTI4Ljc0OFYxMjcuNDQ1SDEzOC45MDdDMTQzLjMxMyAxMjcuNDQ1IDE0NS43NzggMTI1LjAzOCAxNDUuNzc4IDEyMS40NTlDMTQ1Ljc3OCAxMTcuODg4IDE0My4zMTMgMTE1LjQ3OSAxMzguOTA3IDExNS40NzlaTTEzOS41NzcgMTM2LjU2NUgxMjguNzQ2VjE0OS4zMzVIMTM5LjU3N0MxNDQuMjg1IDE0OS4zMzUgMTQ2LjUyMiAxNDYuNDE3IDE0Ni41MjIgMTQyLjkxM0MxNDYuNTIyIDEzOS40MTEgMTQ0LjI4NSAxMzYuNTY1IDEzOS41NzcgMTM2LjU2NVpNMjEyLjEwNiAxMTUuNDgxVjE1OC4zODNIMjAxLjcyM1YxMTUuNDc5SDE4Ny44MzNWMTA2LjQzMUgyMjZWMTE1LjQ3OUwyMTIuMTA2IDExNS40ODFaIiBmaWxsPSJ3aGl0ZSIvPgo8L3N2Zz4K",
2298
- coinbase: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwIiBoZWlnaHQ9IjI1MCIgdmlld0JveD0iMCAwIDI1MCAyNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyNTAiIGhlaWdodD0iMjUwIiBmaWxsPSIjMDA1MkZGIi8+CjxwYXRoIGQ9Ik0xMjUuMTYgMTY3LjVDMTAxLjYzNSAxNjcuNSA4Mi41OCAxNDguNDggODIuNTggMTI1QzgyLjU4IDEwMS41MiAxMDEuNjMgODIuNSAxMjUuMTYgODIuNUMxMzUuMjA3IDgyLjUwMTggMTQ0LjkyOCA4Ni4wNTg0IDE1Mi42MDQgOTIuNTQwMUMxNjAuMjggOTkuMDIxOSAxNjUuNDE1IDEwOC4wMTEgMTY3LjEgMTE3LjkxNUgyMTBDMjA2LjM4IDc0LjI4NSAxNjkuOCA0MCAxMjUuMTYgNDBDNzguMTQ1IDQwIDQwIDc4LjA3NSA0MCAxMjVDNDAgMTcxLjkyNSA3OC4xNDUgMjEwIDEyNS4xNiAyMTBDMTY5Ljc5NSAyMTAgMjA2LjM4IDE3NS43MTUgMjEwIDEzMi4wODVIMTY3LjFDMTY1LjQxNSAxNDEuOTg5IDE2MC4yOCAxNTAuOTc4IDE1Mi42MDQgMTU3LjQ2QzE0NC45MjggMTYzLjk0MiAxMzUuMjA3IDE2Ny40OTggMTI1LjE2IDE2Ny41WiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+Cg==",
2299
- gateio: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwIiBoZWlnaHQ9IjI1MCIgdmlld0JveD0iMCAwIDI1MCAyNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyNTAiIGhlaWdodD0iMjUwIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMTI1IDE3MS43MTNDOTkuMTcwMyAxNzEuNzEzIDc4LjI4NjYgMTUwLjgzIDc4LjI4NjYgMTI1Qzc4LjI4NjYgOTkuMTcwMyA5OS4xNzAzIDc4LjI4NjYgMTI1IDc4LjI4NjZWNDBDNzguMTAzNSA0MCA0MCA3OC4xMDM1IDQwIDEyNUM0MCAxNzEuODk3IDc4LjEwMzUgMjEwIDEyNSAyMTBDMTcxLjg5NyAyMTAgMjEwIDE3MS44OTcgMjEwIDEyNUgxNzEuNzEzQzE3MS43MTMgMTUwLjgzIDE1MC44MyAxNzEuNzEzIDEyNSAxNzEuNzEzWiIgZmlsbD0iIzIzNTRFNiIvPgo8cGF0aCBkPSJNMTcxLjcxMyA3OC4yODY2SDEyNVYxMjVIMTcxLjcxM1Y3OC4yODY2WiIgZmlsbD0iIzE3RTZBMSIvPgo8L3N2Zz4K",
2300
- htx: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwIiBoZWlnaHQ9IjI1MCIgdmlld0JveD0iMCAwIDI1MCAyNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyNTAiIGhlaWdodD0iMjUwIiBmaWxsPSJ3aGl0ZSIvPgo8cGF0aCBkPSJNMTQ0LjQ1IDkyLjI4OTJDMTQ0LjQ1IDY3Ljg5OCAxMzIuNTY3IDQ2Ljg5MTggMTIzLjUxNiA0MC4wNzM4QzEyMy41MTYgNDAuMDczOCAxMjIuODIgMzkuNjg5NyAxMjIuODkyIDQwLjY3NEMxMjIuMTQ4IDg3Ljc5OTkgOTguMDY4NyAxMDAuNTcyIDg0Ljg0MDggMTE3Ljc2MUM1NC4zMDM5IDE1Ny40NjggODIuNjgwMiAyMDAuOTkzIDExMS42MzMgMjA5LjAzNkMxMjcuNzY1IDIxMy41NDkgMTA3Ljg4OCAyMDEuMDY1IDEwNS4zMTkgMTc0LjcyOUMxMDIuMTc0IDE0Mi45NDQgMTQ0LjQ1IDExOC42NDkgMTQ0LjQ1IDkyLjI4OTJaIiBmaWxsPSIjMUIyMTQzIi8+CjxwYXRoIGQ9Ik0xNTguMzI2IDEwOC4zNUMxNTguMTM0IDEwOC4yMyAxNTcuODcgMTA4LjEzNCAxNTcuNzAyIDEwOC40NDZDMTU3LjE5OCAxMTQuMzc2IDE1MS4xNDggMTI3LjA1MiAxNDMuNDY2IDEzOC43MTlDMTE3LjQxOCAxNzguMjM1IDEzMi4yNTUgMTk3LjI5NyAxNDAuNjA5IDIwNy41NDhDMTQ1LjQ1OSAyMTMuNDc3IDE0MC42MDkgMjA3LjU0OCAxNTIuNzA5IDIwMS40NzRDMTY3LjY2NSAxOTIuMzk5IDE3Ny4zNjQgMTc2LjY5OCAxNzguODA0IDE1OS4yNjlDMTgxLjE4MSAxMzEuMTgxIDE2NC4zMjggMTEzLjQ4OCAxNTguMzI2IDEwOC4zNVoiIGZpbGw9IiMyQ0E2RTAiLz4KPC9zdmc+Cg==",
2301
- kraken: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwIiBoZWlnaHQ9IjI1MCIgdmlld0JveD0iMCAwIDI1MCAyNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyNTAiIGhlaWdodD0iMjUwIiBmaWxsPSIjNTg0MUQ4Ii8+CjxwYXRoIGQ9Ik0xMjYuMTMgNTcuMDQzNUM3OC44MTkxIDU3LjA0MzUgNDAgOTUuMjU2IDQwIDE0My4xNzNWMTgwLjE3M0M0MCAxODYuODQ1IDQ1LjQ1ODkgMTkyLjMwNCA1Mi4xMzEgMTkyLjMwNEM1OC44MDMgMTkyLjMwNCA2NC4yNjE5IDE4Ni44NDUgNjQuMjYxOSAxODAuMTczVjE0My4xNzNDNjQuMjYxOSAxMzYuNTAxIDY5LjcyMDkgMTMxLjA0MiA3Ni4zOTI5IDEzMS4wNDJDODMuMDY0OSAxMzEuMDQyIDg4LjUyMzkgMTM2LjUwMSA4OC41MjM5IDE0My4xNzNWMTgwLjE3M0M4OC41MjM5IDE4Ni44NDUgOTMuOTgyOCAxOTIuMzA0IDEwMC42NTUgMTkyLjMwNEMxMDcuMzI3IDE5Mi4zMDQgMTEyLjc4NiAxODYuODQ1IDExMi43ODYgMTgwLjE3M1YxNDMuMTczQzExMi43ODYgMTM2LjUwMSAxMTguMjQ1IDEzMS4wNDIgMTI0LjkxNyAxMzEuMDQyQzEzMS41ODkgMTMxLjA0MiAxMzcuMDQ4IDEzNi41MDEgMTM3LjA0OCAxNDMuMTczVjE4MC4xNzNDMTM3LjA0OCAxODYuODQ1IDE0Mi41MDcgMTkyLjMwNCAxNDkuMTc5IDE5Mi4zMDRDMTU1Ljg1MSAxOTIuMzA0IDE2MS4zMSAxODYuODQ1IDE2MS4zMSAxODAuMTczVjE0My4xNzNDMTYxLjMxIDEzNi41MDEgMTY2Ljc2OSAxMzEuMDQyIDE3My40NDEgMTMxLjA0MkMxODAuMTEzIDEzMS4wNDIgMTg1LjU3MiAxMzYuNTAxIDE4NS41NzIgMTQzLjE3M1YxODAuMTczQzE4NS41NzIgMTg2Ljg0NSAxOTEuMDMxIDE5Mi4zMDQgMTk3LjcwMyAxOTIuMzA0QzIwNC4zNzUgMTkyLjMwNCAyMDkuODM0IDE4Ni44NDUgMjA5LjgzNCAxODAuMTczVjE0My4xNzNDMjEyLjg2NiA5NS4yNTYgMTc0LjA0NyA1Ny4wNDM1IDEyNi4xMyA1Ny4wNDM1WiIgZmlsbD0id2hpdGUiLz4KPC9zdmc+Cg==",
2302
- kucoin: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjUwIiBoZWlnaHQ9IjI1MCIgdmlld0JveD0iMCAwIDI1MCAyNTAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyNTAiIGhlaWdodD0iMjUwIiBmaWxsPSIjMDBCNDdEIi8+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF80NzY5XzE2MDAyNCkiPgo8cGF0aCBkPSJNMTc3Ljg2MyAxNDMuNTFMMTQ2LjAwNyAxNzUuMjE3TDk1LjE1NSAxMjQuOTExTDE0NS45MSA3NC42ODU3TDE3Ny44NjMgMTA2LjQ4OUMxODMuNTMgMTEyLjEwOCAxOTIuNjgxIDExMi4xMDggMTk4LjMgMTA2LjQ0QzIwMy45MTggMTAwLjc3MiAyMDMuODkzIDkxLjYyMTYgMTk4LjI1MSA4Ni4wMDM1TDE1Ni4yNDkgNDQuMTk4M0MxNTAuNTgyIDM4LjU4MDIgMTQxLjQzIDM4LjYwNDcgMTM1LjgxMiA0NC4yNDczQzEzNS43ODkgNDQuMjcwNCAxMzQuNzg4IDQ1LjEwMiAxMzQuMzQgNDUuNTQ3NEw3NS45MDEgMTAzLjM1OFY2OC44MDUyQzc1LjkwMSA2MC44MzIzIDY5LjQyNDEgNTQuMzU1NCA2MS40NTA1IDU0LjM1NTRDNTMuNDc2OSA1NC4zNTU0IDQ3LjAyNDUgNjAuODMyMyA0NyA2OC44MDUyVjE4MS4wOTlDNDcgMTg5LjA3MyA1My40NzY5IDE5NS41NSA2MS40NTA1IDE5NS41NUM2OS40MjQxIDE5NS41NSA3NS45MDEgMTg5LjA3IDc1LjkwMSAxODEuMDk5VjE0Ni40N0wxMzQuMzQgMjA0LjI4MUMxMzQuNTkyIDIwNC41MzIgMTM1LjU3IDIwNS41MDggMTM1LjgxMiAyMDUuNzUzQzE0MS40MyAyMTEuMzk3IDE1MC41ODIgMjExLjQyIDE1Ni4yNDkgMjA1LjgwMkwxOTguMjUxIDE2My45OTZDMjAzLjg5NSAxNTguMzc4IDIwMy45MTggMTQ5LjIyNyAxOTguMyAxNDMuNTU5QzE5Mi42NTcgMTM3LjkyIDE4My41MDYgMTM3Ljg5MiAxNzcuODYzIDE0My41MVoiIGZpbGw9ImJsYWNrIi8+CjxwYXRoIGQ9Ik0xNDYuMTQxIDEzOS41ODVDMTU0LjE4OSAxMzkuNTg1IDE2MC43MTQgMTMzLjA2MSAxNjAuNzE0IDEyNS4wMTJDMTYwLjcxNCAxMTYuOTY0IDE1NC4xODkgMTEwLjQzOSAxNDYuMTQxIDExMC40MzlDMTM4LjA5MiAxMTAuNDM5IDEzMS41NjggMTE2Ljk2NCAxMzEuNTY4IDEyNS4wMTJDMTMxLjU2OCAxMzMuMDYxIDEzOC4wOTIgMTM5LjU4NSAxNDYuMTQxIDEzOS41ODVaIiBmaWxsPSJibGFjayIvPgo8L2c+CjxkZWZzPgo8Y2xpcFBhdGggaWQ9ImNsaXAwXzQ3NjlfMTYwMDI0Ij4KPHJlY3Qgd2lkdGg9IjE1NS40OTgiIGhlaWdodD0iMTcwIiBmaWxsPSJ3aGl0ZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNDcgNDApIi8+CjwvY2xpcFBhdGg+CjwvZGVmcz4KPC9zdmc+Cg=="
2303
- };
2304
- var EXCHANGE_LOGO_ALIASES = {
2305
- gate: "gateio"
2306
- };
2307
- function normalize(value) {
2308
- return value.toLowerCase().replace(/[^a-z0-9]/g, "");
2309
- }
2310
- function getLogoSource(value) {
2311
- const key = normalize(value);
2312
- return EXCHANGE_LOGO_SOURCES[EXCHANGE_LOGO_ALIASES[key] ?? key] ?? null;
2313
- }
2314
- function getExchangeLogoSrc(name, connection) {
2315
- return getLogoSource(name) ?? getLogoSource(connection ?? "");
2316
- }
2317
- function getExchangeLogo(name, connection) {
2318
- const src = getExchangeLogoSrc(name, connection);
2319
- return src ? /* @__PURE__ */ jsx16("img", { src, alt: "", loading: "lazy", decoding: "async" }) : null;
2320
- }
2321
-
2322
- // src/components/ui/BrandIcons.tsx
2323
- import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
2324
- function VisaMark() {
2325
- return /* @__PURE__ */ jsxs15(
2326
- "svg",
2327
- {
2328
- width: "38",
2329
- height: "24",
2330
- viewBox: "0 0 38 24",
2331
- fill: "none",
2332
- xmlns: "http://www.w3.org/2000/svg",
2333
- "aria-hidden": "true",
2334
- children: [
2335
- /* @__PURE__ */ jsx17("rect", { width: "38", height: "24", rx: "4.2985", fill: "white" }),
2336
- /* @__PURE__ */ jsx17(
2337
- "path",
2338
- {
2339
- d: "M18.3993 8.08878L16.6616 16.2114H14.5605L16.2984 8.08878H18.3993ZM27.2397 13.3336L28.3459 10.2833L28.9824 13.3336H27.2397ZM29.584 16.2114H31.5276L29.8316 8.08878H28.0376C27.6345 8.08878 27.2944 8.32324 27.143 8.6847L23.9906 16.2114H26.1972L26.6352 14.9985H29.331L29.584 16.2114ZM24.1001 13.5593C24.1091 11.4155 21.1354 11.2975 21.156 10.3398C21.1622 10.048 21.4401 9.7385 22.0471 9.65906C22.3486 9.61972 23.1777 9.58964 24.1192 10.0228L24.4878 8.30036C23.9821 8.1168 23.3314 7.94019 22.5221 7.94019C20.4454 7.94019 18.9836 9.04437 18.9713 10.6254C18.9582 11.7947 20.0148 12.4471 20.811 12.8359C21.6295 13.2341 21.9046 13.4891 21.901 13.8452C21.8956 14.3905 21.248 14.6306 20.6439 14.6401C19.5873 14.6568 18.9741 14.355 18.4854 14.1272L18.1047 15.907C18.5954 16.1325 19.5017 16.3284 20.4418 16.3384C22.6489 16.3384 24.0929 15.2478 24.1001 13.5593ZM15.3968 8.08878L11.9925 16.2114H9.77099L8.09583 9.72898C7.99402 9.32973 7.90559 9.18371 7.59631 9.01532C7.09165 8.74152 6.25741 8.48418 5.52344 8.32479L5.57357 8.08878H9.14885C9.6044 8.08878 10.0145 8.39214 10.1178 8.91685L11.0027 13.6174L13.1892 8.08878H15.3968Z",
2340
- fill: "#1434CB"
2341
- }
2342
- )
2343
- ]
2344
- }
2345
- );
2346
- }
2347
- function MastercardMark() {
2348
- return /* @__PURE__ */ jsxs15(
2349
- "svg",
2350
- {
2351
- width: "38",
2352
- height: "24",
2353
- viewBox: "0 0 38 24",
2354
- fill: "none",
2355
- xmlns: "http://www.w3.org/2000/svg",
2356
- "aria-hidden": "true",
2357
- children: [
2358
- /* @__PURE__ */ jsx17("rect", { width: "38", height: "24", rx: "4.2985", fill: "white" }),
2359
- /* @__PURE__ */ jsx17(
2360
- "path",
2361
- {
2362
- d: "M21.303 7.07157H15.8179V16.9284H21.303V7.07157Z",
2363
- fill: "#FF5F00"
2364
- }
2365
- ),
2366
- /* @__PURE__ */ jsx17(
2367
- "path",
2368
- {
2369
- d: "M16.1662 12C16.1653 11.0507 16.3804 10.1136 16.7953 9.25979C17.2101 8.40593 17.8137 7.65764 18.5605 7.07156C17.6357 6.34468 16.5251 5.89265 15.3556 5.76713C14.1861 5.6416 13.0048 5.84765 11.9469 6.36172C10.8889 6.87579 9.99698 7.67715 9.37294 8.67419C8.7489 9.67124 8.41797 10.8237 8.41797 12C8.41797 13.1762 8.7489 14.3287 9.37294 15.3257C9.99698 16.3228 10.8889 17.1241 11.9469 17.6382C13.0048 18.1523 14.1861 18.3583 15.3556 18.2328C16.5251 18.1073 17.6357 17.6553 18.5605 16.9284C17.8137 16.3423 17.2101 15.594 16.7953 14.7401C16.3805 13.8863 16.1653 12.9492 16.1662 12Z",
2370
- fill: "#EB001B"
2371
- }
2372
- ),
2373
- /* @__PURE__ */ jsx17(
2374
- "path",
2375
- {
2376
- d: "M28.7026 12C28.7027 13.1762 28.3718 14.3287 27.7478 15.3257C27.1238 16.3228 26.2318 17.1241 25.1739 17.6382C24.116 18.1523 22.9348 18.3583 21.7653 18.2328C20.5958 18.1073 19.4852 17.6553 18.5605 16.9284C19.3066 16.3417 19.9097 15.5933 20.3245 14.7396C20.7392 13.8858 20.9547 12.9491 20.9547 12C20.9547 11.0508 20.7392 10.1141 20.3245 9.26037C19.9097 8.40665 19.3066 7.65824 18.5605 7.07156C19.4852 6.34468 20.5958 5.89265 21.7653 5.76712C22.9348 5.6416 24.116 5.84765 25.1739 6.36173C26.2318 6.87581 27.1238 7.67717 27.7478 8.67421C28.3718 9.67126 28.7027 10.8238 28.7026 12Z",
2377
- fill: "#F79E1B"
2378
- }
2379
- ),
2380
- /* @__PURE__ */ jsx17(
2381
- "path",
2382
- {
2383
- d: "M28.1046 15.8844V15.6826H28.1859V15.6415H27.9787V15.6826H28.0601V15.8844H28.1046ZM28.5069 15.8844V15.6411H28.4434L28.3703 15.8084L28.2972 15.6411H28.2337V15.8844H28.2785V15.7009L28.347 15.8591H28.3936L28.4621 15.7005V15.8844H28.5069Z",
2384
- fill: "#F79E1B"
2385
- }
2386
- )
2387
- ]
2388
- }
2389
- );
2390
- }
2391
- function AmexMark() {
2392
- return /* @__PURE__ */ jsxs15(
2393
- "svg",
2394
- {
2395
- width: "38",
2396
- height: "24",
2397
- viewBox: "0 0 38 24",
2398
- fill: "none",
2399
- xmlns: "http://www.w3.org/2000/svg",
2400
- "aria-hidden": "true",
2401
- children: [
2402
- /* @__PURE__ */ jsx17("rect", { width: "38", height: "24", rx: "4.2985", fill: "#006FCF" }),
2403
- /* @__PURE__ */ jsx17(
2404
- "path",
2405
- {
2406
- fillRule: "evenodd",
2407
- clipRule: "evenodd",
2408
- d: "M37.268 4.34531H34.1845L32.5727 8.9706L30.8908 4.34531H27.7373V11.5472L24.5136 4.34531H21.9208L18.6971 11.7036H20.9395L21.5702 10.232H24.9341L25.5648 11.7036H29.7696V6.58776L31.6617 11.7036H33.4136L35.3057 6.58776V11.7036H37.268V12.8248H34.675L32.5727 15.1375L30.4003 12.8248H21.5003V20.1831H30.3303L32.5026 17.8004L34.675 20.1831H37.268V21.0939H34.1845L32.5026 19.272L30.8206 21.0939H20.379V12.6846H17.0151L21.2199 3.22388H25.2845L26.756 6.44759V3.22388H31.8019L32.6427 5.6767L33.4838 3.22388H37.268V4.34531ZM37.268 14.4366L35.3759 16.4689L37.268 18.5011V20.1831L33.8342 16.4689L37.268 12.8248V14.4366ZM27.7373 20.1831V18.4312H23.5325V17.3099H27.6671V15.628H23.5325V14.5068H27.7373V12.8248L31.2411 16.4689L27.7373 20.1831ZM22.2009 8.62005L23.1822 6.23742L24.1632 8.62005H22.2009Z",
2409
- fill: "white"
2410
- }
2411
- )
2412
- ]
2413
- }
2414
- );
2415
- }
2416
- function ExchangeBadgeImage({ name }) {
2417
- const src = getExchangeLogoSrc(name);
2418
- return src ? /* @__PURE__ */ jsx17("img", { src, alt: "", loading: "lazy", decoding: "async" }) : null;
2419
- }
2420
- function CardNetworkIcons() {
2421
- return /* @__PURE__ */ jsxs15("span", { className: "rs-list-row-meta-icons rs-list-row-meta-icons--cards", children: [
2422
- /* @__PURE__ */ jsx17("span", { className: "rs-card-network rs-card-network--amex", children: /* @__PURE__ */ jsx17(AmexMark, {}) }),
2423
- /* @__PURE__ */ jsx17("span", { className: "rs-card-network rs-card-network--visa", children: /* @__PURE__ */ jsx17(VisaMark, {}) }),
2424
- /* @__PURE__ */ jsx17("span", { className: "rs-card-network rs-card-network--mastercard", children: /* @__PURE__ */ jsx17(MastercardMark, {}) })
2425
- ] });
2426
- }
2427
- CardNetworkIcons.displayName = "CardNetworkIcons";
2428
- function ExchangeBadgeIcons() {
2429
- return /* @__PURE__ */ jsxs15("span", { className: "rs-list-row-meta-icons rs-list-row-meta-icons--exchanges", children: [
2430
- /* @__PURE__ */ jsx17("span", { children: /* @__PURE__ */ jsx17(ExchangeBadgeImage, { name: "Coinbase" }) }),
2431
- /* @__PURE__ */ jsx17("span", { children: /* @__PURE__ */ jsx17(ExchangeBadgeImage, { name: "Binance" }) }),
2432
- /* @__PURE__ */ jsx17("span", { children: /* @__PURE__ */ jsx17(ExchangeBadgeImage, { name: "Kraken" }) })
2433
- ] });
2434
- }
2435
- ExchangeBadgeIcons.displayName = "ExchangeBadgeIcons";
2436
-
2437
- // src/components/steps/ConnectStep.tsx
2438
- import { Fragment as Fragment2, jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
2439
- function formatBalanceUsd(value) {
2440
- if (!Number.isFinite(value) || value <= 0) return "$0.00";
2441
- return `$${value.toFixed(2)}`;
2442
- }
2443
- function rankUsd(value) {
2444
- return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
2445
- }
2446
- function rankCryptoRows(descriptors) {
2447
- return descriptors.map((descriptor, index) => ({ descriptor, index })).sort((a, b) => {
2448
- const first = a.descriptor;
2449
- const second = b.descriptor;
2450
- const firstHasFunds = first.isBalanceSource && first.resolved && first.balanceUsd > 0;
2451
- const secondHasFunds = second.isBalanceSource && second.resolved && second.balanceUsd > 0;
2452
- const firstTier = firstHasFunds ? 0 : first.isBalanceSource ? 2 : 1;
2453
- const secondTier = secondHasFunds ? 0 : second.isBalanceSource ? 2 : 1;
2454
- if (firstTier !== secondTier) return firstTier - secondTier;
2455
- if (firstTier === 0 && first.balanceUsd !== second.balanceUsd) {
2456
- return second.balanceUsd - first.balanceUsd;
2457
- }
2458
- return a.index - b.index;
2459
- }).map(({ descriptor }) => descriptor.node);
2460
- }
2461
- function fiatIcon(name) {
2462
- if (name === "apple") return /* @__PURE__ */ jsx18(AppleIcon, {});
2463
- if (name === "bank") return /* @__PURE__ */ jsx18(BankIcon, {});
2464
- return /* @__PURE__ */ jsx18(CardIcon, {});
2465
- }
2466
- function fiatMeta(name) {
2467
- if (name === "apple" || name === "bank") return void 0;
2468
- return /* @__PURE__ */ jsx18(CardNetworkIcons, {});
2469
- }
2470
- function shorten(addr) {
2471
- return addr.length > 12 ? `${addr.slice(0, 6)}...${addr.slice(-4)}` : addr;
2472
- }
2473
- function renderWalletLeading(row) {
2474
- if (row.icon) {
2475
- return /* @__PURE__ */ jsx18(
2476
- "img",
2477
- {
2478
- src: row.icon,
2479
- alt: "",
2480
- style: { width: 24, height: 24, borderRadius: 6 }
2481
- }
2482
- );
2483
- }
2484
- return /* @__PURE__ */ jsx18(WalletIcon, {});
2485
- }
2486
- var TRANSFER_CRYPTO_LEADING = /* @__PURE__ */ jsx18(TransferCryptoIcon, {});
2487
- var WALLET_LEADING = /* @__PURE__ */ jsx18(WalletIcon, {});
2488
- var EXCHANGE_LEADING = /* @__PURE__ */ jsx18(UnplugIcon, {});
2489
- var SMALL_SPINNER = /* @__PURE__ */ jsx18(Spinner, { className: "rs-spinner--sm" });
2490
- var CONNECT_META = /* @__PURE__ */ jsxs16(Fragment2, { children: [
2491
- /* @__PURE__ */ jsx18(WalletBadgeIcons, {}),
2492
- "+100"
2493
- ] });
2494
- var EXCHANGE_META = /* @__PURE__ */ jsxs16(Fragment2, { children: [
2495
- /* @__PURE__ */ jsx18(ExchangeBadgeIcons, {}),
2496
- "+6"
2497
- ] });
2498
- var EXTRA_CHAIN_COUNT = Math.max(0, getSupportedChainIds().length - 3);
2499
- var CHAIN_BADGE_META = /* @__PURE__ */ jsxs16(Fragment2, { children: [
2500
- /* @__PURE__ */ jsx18(ChainBadgeIcons, {}),
2501
- EXTRA_CHAIN_COUNT > 0 ? `+${EXTRA_CHAIN_COUNT}` : null
2502
- ] });
2503
- function renderRowTrailing(state) {
2504
- if (state === "loading") {
2505
- return SMALL_SPINNER;
2506
- }
2507
- return void 0;
2508
- }
2509
- function ConnectStep({
2510
- walletRows,
2511
- onConfirmWallet,
2512
- onSelectTransferCrypto,
2513
- transferCryptoState,
2514
- transferCryptoErrorReason,
2515
- onSelectPayWithCard,
2516
- fiatPaymentMethods,
2517
- onSelectFiatMethod,
2518
- onPrefetchFiatMethod,
2519
- onSelectFundFromExchange,
2520
- onRequestConnect,
2521
- onConnect,
2522
- onDisconnect,
2523
- dappImports,
2524
- onSelectDappImport,
2525
- title = "Deposit",
2526
- subtitle,
2527
- defaultMethodTab = "crypto"
2528
- }) {
2529
- const rows = walletRows ?? [];
2530
- const handleConnect = onConnect ?? onRequestConnect;
2531
- const hasReownWallet = rows.some(
2532
- (row) => row.kind === "external" || row.kind === "solana"
2533
- );
2534
- const showDappImports = (dappImports?.length ?? 0) > 0;
2535
- const defaultSubtitle = onSelectTransferCrypto ? "Add money to your balance" : "Choose a wallet to continue";
2536
- const cryptoDescriptors = [];
2537
- const pushAction = (node) => cryptoDescriptors.push({
2538
- node,
2539
- isBalanceSource: false,
2540
- resolved: false,
2541
- balanceUsd: 0
2542
- });
2543
- const pushBalanceSource = (node, resolved, balanceUsd) => cryptoDescriptors.push({
2544
- node,
2545
- isBalanceSource: true,
2546
- resolved,
2547
- balanceUsd: rankUsd(balanceUsd)
2548
- });
2549
- if (onSelectTransferCrypto) {
2550
- pushAction(
2551
- /* @__PURE__ */ jsx18(
2552
- ListRow,
2553
- {
2554
- leading: TRANSFER_CRYPTO_LEADING,
2555
- title: "Transfer crypto",
2556
- subtitle: transferCryptoState === "error" ? transferCryptoErrorReason ?? "Couldn't prepare account \u2014 tap to retry" : "Instant - No limit",
2557
- meta: CHAIN_BADGE_META,
2558
- onClick: onSelectTransferCrypto
2559
- },
2560
- "transfer-crypto"
2561
- )
2562
- );
2563
- }
2564
- for (const row of rows) {
2565
- const collapseToExternal = Boolean(onSelectTransferCrypto) && row.kind !== "solana";
2566
- const subtitleText = row.state === "loading" ? "Preparing\u2026" : row.state === "error" ? row.errorReason ?? "Couldn't prepare wallet \u2014 tap to retry" : row.balanceStatus === "ready" && row.balanceUsd != null ? formatBalanceUsd(row.balanceUsd) : row.balanceStatus === "loading" ? "Checking balance\u2026" : shorten(row.address);
2567
- pushBalanceSource(
2568
- /* @__PURE__ */ jsx18(
2569
- ListRow,
2570
- {
2571
- leading: renderWalletLeading(row),
2572
- title: collapseToExternal ? "External wallet" : row.label,
2573
- subtitle: subtitleText,
2574
- onClick: () => onConfirmWallet?.(row.id),
2575
- disabled: row.state === "loading",
2576
- trailing: renderRowTrailing(row.state)
2577
- },
2578
- row.id
2579
- ),
2580
- row.balanceStatus === "ready",
2581
- row.balanceUsd ?? 0
2582
- );
2583
- }
2584
- if (!hasReownWallet && handleConnect) {
2585
- pushAction(
2586
- /* @__PURE__ */ jsx18(
2587
- ListRow,
2588
- {
2589
- leading: WALLET_LEADING,
2590
- title: "Connect wallet",
2591
- subtitle: "Instant - No limit",
2592
- meta: CONNECT_META,
2593
- onClick: handleConnect
2594
- },
2595
- "connect-wallet"
2596
- )
2597
- );
2598
- }
2599
- if (onSelectFundFromExchange) {
2600
- pushAction(
2601
- /* @__PURE__ */ jsx18(
2602
- ListRow,
2603
- {
2604
- leading: EXCHANGE_LEADING,
2605
- title: "Connect exchange",
2606
- subtitle: "Instant - No limit",
2607
- meta: EXCHANGE_META,
2608
- onClick: onSelectFundFromExchange
2609
- },
2610
- "connect-exchange"
2611
- )
2612
- );
2613
- }
2614
- if (showDappImports) {
2615
- for (const row of dappImports ?? []) {
2616
- if (!hasReownWallet) {
2617
- pushBalanceSource(
2618
- /* @__PURE__ */ jsx18(
2619
- ListRow,
2620
- {
2621
- leading: row.icon,
2622
- title: row.label,
2623
- subtitle: "Connect wallet to view balance",
2624
- onClick: handleConnect,
2625
- disabled: !handleConnect
2626
- },
2627
- row.id
2628
- ),
2629
- false,
2630
- 0
2631
- );
2632
- continue;
2633
- }
2634
- if (row.status === "loading" || row.status === "needs-connect") {
2635
- pushBalanceSource(
2636
- /* @__PURE__ */ jsx18(
2637
- ListRow,
2638
- {
2639
- leading: row.icon,
2640
- title: row.label,
2641
- subtitle: "Checking balance\u2026",
2642
- disabled: true,
2643
- trailing: SMALL_SPINNER
2644
- },
2645
- row.id
2646
- ),
2647
- false,
2648
- 0
2649
- );
2650
- continue;
2651
- }
2652
- if (row.status.enabled) {
2653
- pushBalanceSource(
2654
- /* @__PURE__ */ jsx18(
2655
- ListRow,
2656
- {
2657
- leading: row.icon,
2658
- title: row.label,
2659
- subtitle: formatBalanceUsd(row.status.balanceUsd),
2660
- onClick: () => onSelectDappImport?.(row.id)
2661
- },
2662
- row.id
2663
- ),
2664
- true,
2665
- row.status.balanceUsd
2666
- );
2667
- continue;
2668
- }
2669
- if (row.status.retryable) {
2670
- pushBalanceSource(
2671
- /* @__PURE__ */ jsx18(
2672
- ListRow,
2673
- {
2674
- leading: row.icon,
2675
- title: row.label,
2676
- subtitle: row.status.reason,
2677
- onClick: () => onSelectDappImport?.(row.id)
2678
- },
2679
- row.id
2680
- ),
2681
- false,
2682
- 0
2683
- );
2684
- continue;
2685
- }
2686
- pushBalanceSource(
2687
- /* @__PURE__ */ jsx18(
2688
- ListRow,
2689
- {
2690
- leading: row.icon,
2691
- title: row.label,
2692
- subtitle: row.status.reason,
2693
- disabled: true
2694
- },
2695
- row.id
2696
- ),
2697
- false,
2698
- 0
2699
- );
2700
- }
2701
- }
2702
- const cryptoRows = rankCryptoRows(cryptoDescriptors);
2703
- const cashRows = [];
2704
- if (fiatPaymentMethods && fiatPaymentMethods.length > 0 && onSelectFiatMethod) {
2705
- for (const opt of fiatPaymentMethods) {
2706
- cashRows.push(
2707
- /* @__PURE__ */ jsx18(
2708
- ListRow,
2709
- {
2710
- leading: fiatIcon(opt.icon),
2711
- title: opt.label,
2712
- subtitle: opt.sublabel,
2713
- meta: fiatMeta(opt.icon),
2714
- onClick: () => onSelectFiatMethod(opt.method)
2715
- },
2716
- opt.method
2717
- )
2718
- );
2719
- }
2720
- } else if (onSelectPayWithCard) {
2721
- cashRows.push(
2722
- /* @__PURE__ */ jsx18(
2723
- ListRow,
2724
- {
2725
- leading: /* @__PURE__ */ jsx18(CardIcon, {}),
2726
- title: "Debit/Credit card",
2727
- subtitle: "Instant - $10,000 limit",
2728
- meta: /* @__PURE__ */ jsx18(CardNetworkIcons, {}),
2729
- onClick: onSelectPayWithCard
2730
- },
2731
- "pay-with-card"
2732
- )
2733
- );
2734
- }
2735
- const hasCrypto = cryptoRows.length > 0;
2736
- const hasCash = cashRows.length > 0;
2737
- const showToggle = hasCrypto && hasCash;
2738
- const [tab, setTab] = useState(defaultMethodTab);
2739
- const activeTab = showToggle ? tab : hasCash && !hasCrypto ? "cash" : "crypto";
2740
- const activeRows = activeTab === "cash" ? cashRows : cryptoRows;
2741
- useEffect3(() => {
2742
- if (activeTab !== "cash" || !onPrefetchFiatMethod || !fiatPaymentMethods) {
2743
- return;
2744
- }
2745
- for (const opt of fiatPaymentMethods) {
2746
- onPrefetchFiatMethod(opt.method);
2747
- }
2748
- }, [activeTab, onPrefetchFiatMethod, fiatPaymentMethods]);
2749
- return /* @__PURE__ */ jsxs16("div", { className: "rs-screen", children: [
2750
- /* @__PURE__ */ jsxs16("div", { className: "rs-screen-body rs-screen-body--gap-32", children: [
2751
- /* @__PURE__ */ jsx18(
2752
- BodyHeader,
2753
- {
2754
- icon: /* @__PURE__ */ jsx18(HandCoinsIcon, {}),
2755
- title,
2756
- subtitle: subtitle ?? defaultSubtitle,
2757
- aside: showToggle ? /* @__PURE__ */ jsx18(
2758
- SegmentedToggle,
2759
- {
2760
- ariaLabel: "Deposit method type",
2761
- value: activeTab,
2762
- onChange: setTab,
2763
- options: [
2764
- { value: "crypto", label: "Crypto" },
2765
- { value: "cash", label: "Cash" }
2766
- ]
2767
- }
2768
- ) : void 0
2769
- }
2770
- ),
2771
- /* @__PURE__ */ jsx18("div", { className: "rs-list", children: activeRows })
2772
- ] }),
2773
- onDisconnect && hasReownWallet && /* @__PURE__ */ jsx18("div", { className: "rs-screen-tight-row", children: /* @__PURE__ */ jsx18(
2774
- "button",
2775
- {
2776
- type: "button",
2777
- className: "rs-connect-wallet-manage",
2778
- onClick: onDisconnect,
2779
- children: "Disconnect wallet"
2780
- }
2781
- ) }),
2782
- /* @__PURE__ */ jsx18(PoweredBy, {})
2783
- ] });
2784
- }
2785
- ConnectStep.displayName = "ConnectStep";
2786
-
2787
- // src/components/ui/TokenIcon.tsx
2788
- import { useState as useState2 } from "react";
2789
- import { Fragment as Fragment3, jsx as jsx19 } from "react/jsx-runtime";
2790
- function preconnectIconCdn() {
2791
- if (typeof document === "undefined") return;
2792
- if (document.getElementById("rs-icon-cdn-preconnect")) return;
2793
- const link = document.createElement("link");
2794
- link.id = "rs-icon-cdn-preconnect";
2795
- link.rel = "preconnect";
2796
- link.href = "https://s3.rhinestone.dev";
2797
- link.crossOrigin = "anonymous";
2798
- document.head.appendChild(link);
2799
- }
2800
- preconnectIconCdn();
2801
- function TokenIcon({ symbol, className, fallback }) {
2802
- const [loadedSymbol, setLoadedSymbol] = useState2(null);
2803
- const [erroredSymbol, setErroredSymbol] = useState2(null);
2804
- if (erroredSymbol === symbol) {
2805
- return /* @__PURE__ */ jsx19(Fragment3, { children: fallback });
2806
- }
2807
- const loading = loadedSymbol !== symbol;
2808
- return /* @__PURE__ */ jsx19(
2809
- "img",
2810
- {
2811
- src: tokenIconUrl(symbol),
2812
- alt: "",
2813
- className: `rs-token-icon ${className ?? ""}`.trimEnd(),
2814
- decoding: "async",
2815
- "data-loading": loading ? "" : void 0,
2816
- onLoad: () => setLoadedSymbol(symbol),
2817
- onError: () => setErroredSymbol(symbol)
2818
- },
2819
- symbol
2820
- );
2821
- }
2822
- TokenIcon.displayName = "TokenIcon";
2823
-
2824
- // src/core/useTokenPrices.ts
2825
- import { useEffect as useEffect4, useState as useState3 } from "react";
2826
- function isErc20(token) {
2827
- return typeof token.chainId === "number" && !!token.address && token.address.toLowerCase() !== NATIVE_TOKEN_ADDRESS.toLowerCase();
2828
- }
2829
- function caip2For(token) {
2830
- return `${toEvmCaip2(token.chainId)}:${token.address.toLowerCase()}`;
2831
- }
2832
- async function fetchTokenPriceUsd(service, token) {
2833
- if (isErc20(token)) {
2834
- const caip2 = caip2For(token);
2835
- const prices2 = await service.fetchPricesByAddress([caip2]);
2836
- const price2 = prices2[caip2];
2837
- return typeof price2 === "number" && price2 > 0 ? price2 : null;
2838
- }
2839
- const symbol = token.symbol.toUpperCase();
2840
- const prices = await service.fetchPrices([symbol]);
2841
- const price = prices[symbol];
2842
- return typeof price === "number" && price > 0 ? price : null;
2843
- }
2844
- function useTokenPrices(service, tokens) {
2845
- const [prices, setPrices] = useState3({});
2846
- const defined = tokens.filter((t) => Boolean(t?.symbol));
2847
- const entries = [
2848
- ...new Map(
2849
- defined.map((token) => {
2850
- const erc20 = isErc20(token);
2851
- const caip2 = erc20 ? caip2For(token) : null;
2852
- const symbol = token.symbol.toUpperCase();
2853
- return [caip2 ?? `sym:${symbol}`, { symbol, caip2 }];
2854
- })
2855
- ).values()
2856
- ].sort(
2857
- (a, b) => (a.caip2 ?? a.symbol).localeCompare(b.caip2 ?? b.symbol)
2858
- );
2859
- const key = JSON.stringify(entries);
2860
- useEffect4(() => {
2861
- if (key === "[]") return;
2862
- let cancelled = false;
2863
- const parsed = JSON.parse(key);
2864
- const symbols = [
2865
- ...new Set(parsed.filter((e) => !e.caip2).map((e) => e.symbol))
2866
- ];
2867
- const caip2Ids = [
2868
- ...new Set(
2869
- parsed.filter((e) => e.caip2).map((e) => e.caip2)
2870
- )
2871
- ];
2872
- Promise.all([
2873
- symbols.length > 0 ? service.fetchPrices(symbols) : Promise.resolve({}),
2874
- caip2Ids.length > 0 ? service.fetchPricesByAddress(caip2Ids) : Promise.resolve({})
2875
- ]).then(([bySymbol, byAddress]) => {
2876
- if (cancelled) return;
2877
- const merged = { ...bySymbol };
2878
- for (const entry of parsed) {
2879
- if (!entry.caip2) continue;
2880
- const price = byAddress[entry.caip2];
2881
- if (typeof price === "number") merged[entry.symbol] = price;
2882
- }
2883
- setPrices(merged);
2884
- }).catch(() => {
2885
- });
2886
- return () => {
2887
- cancelled = true;
2888
- };
2889
- }, [service, key]);
2890
- return prices;
2891
- }
2892
-
2893
- // src/components/steps/ProcessingStep.tsx
2894
- import { useCallback as useCallback3, useEffect as useEffect6, useRef as useRef4, useState as useState6 } from "react";
2895
-
2896
- // src/components/ui/Button.tsx
2897
- import { Fragment as Fragment4, jsx as jsx20, jsxs as jsxs17 } from "react/jsx-runtime";
2898
- function Button({
2899
- children,
2900
- variant = "accent",
2901
- size = "default",
2902
- loading = false,
2903
- loadingText,
2904
- fullWidth = false,
2905
- disabled,
2906
- className = "",
2907
- ...props
2908
- }) {
2909
- const classes = [
2910
- "rs-button",
2911
- `rs-button--${variant}`,
2912
- `rs-button--size-${size}`,
2913
- fullWidth ? "rs-button--full-width" : "",
2914
- className
2915
- ].filter(Boolean).join(" ");
2916
- const showInlineLoadingText = loading && loadingText !== void 0;
2917
- return /* @__PURE__ */ jsx20(
2918
- "button",
2919
- {
2920
- className: classes,
2921
- disabled: disabled || loading,
2922
- "aria-busy": loading || void 0,
2923
- ...props,
2924
- children: showInlineLoadingText ? /* @__PURE__ */ jsxs17("span", { className: "rs-button__loading-row", children: [
2925
- /* @__PURE__ */ jsx20(Spinner, { className: "rs-spinner--sm" }),
2926
- /* @__PURE__ */ jsx20("span", { children: loadingText })
2927
- ] }) : /* @__PURE__ */ jsxs17(Fragment4, { children: [
2928
- /* @__PURE__ */ jsx20("span", { className: loading ? "rs-button__content--hidden" : "", children }),
2929
- loading && /* @__PURE__ */ jsx20("span", { className: "rs-button__spinner", children: /* @__PURE__ */ jsx20(Spinner, { className: "rs-spinner--sm" }) })
2930
- ] })
2931
- }
2932
- );
2933
- }
2934
- Button.displayName = "Button";
2935
-
2936
- // src/components/ui/Tooltip.tsx
2937
- import {
2938
- useState as useState4,
2939
- useRef as useRef3,
2940
- useEffect as useEffect5,
2941
- useCallback as useCallback2
2942
- } from "react";
2943
- import { createPortal as createPortal2 } from "react-dom";
2944
- import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
2945
- function Tooltip({ content, children, className }) {
2946
- const [open, setOpen] = useState4(false);
2947
- const [position, setPosition] = useState4(null);
2948
- const triggerRef = useRef3(null);
2949
- const bubbleRef = useRef3(null);
2950
- const updatePosition = useCallback2(() => {
2951
- const trigger = triggerRef.current;
2952
- if (!trigger) return;
2953
- const rect = trigger.getBoundingClientRect();
2954
- setPosition({
2955
- top: rect.top,
2956
- left: rect.left + rect.width / 2
2957
- });
2958
- }, []);
2959
- useEffect5(() => {
2960
- if (!open) return;
2961
- updatePosition();
2962
- function handleOutside(event) {
2963
- const target = event.target;
2964
- if (!target) return;
2965
- if (triggerRef.current?.contains(target)) return;
2966
- if (bubbleRef.current?.contains(target)) return;
2967
- setOpen(false);
2968
- }
2969
- function handleKey(event) {
2970
- if (event.key === "Escape") setOpen(false);
2971
- }
2972
- document.addEventListener("mousedown", handleOutside);
2973
- document.addEventListener("touchstart", handleOutside, { passive: true });
2974
- document.addEventListener("keydown", handleKey);
2975
- window.addEventListener("scroll", updatePosition, true);
2976
- window.addEventListener("resize", updatePosition);
2977
- return () => {
2978
- document.removeEventListener("mousedown", handleOutside);
2979
- document.removeEventListener("touchstart", handleOutside);
2980
- document.removeEventListener("keydown", handleKey);
2981
- window.removeEventListener("scroll", updatePosition, true);
2982
- window.removeEventListener("resize", updatePosition);
2983
- };
2984
- }, [open, updatePosition]);
2985
- return /* @__PURE__ */ jsxs18(
2986
- "span",
2987
- {
2988
- ref: triggerRef,
2989
- className: `rs-tooltip ${className ?? ""}`,
2990
- onMouseEnter: () => setOpen(true),
2991
- onMouseLeave: () => setOpen(false),
2992
- children: [
2993
- /* @__PURE__ */ jsx21(
2994
- "span",
2995
- {
2996
- className: "rs-tooltip-trigger",
2997
- role: "button",
2998
- tabIndex: 0,
2999
- "aria-label": content,
3000
- onClick: (event) => {
3001
- event.stopPropagation();
3002
- event.preventDefault();
3003
- setOpen((value) => !value);
3004
- },
3005
- onKeyDown: (event) => {
3006
- if (event.key === "Enter" || event.key === " ") {
3007
- event.preventDefault();
3008
- setOpen((value) => !value);
3009
- }
3010
- },
3011
- children
3012
- }
3013
- ),
3014
- open && position && typeof document !== "undefined" && createPortal2(
3015
- /* @__PURE__ */ jsx21(
3016
- "span",
3017
- {
3018
- ref: bubbleRef,
3019
- className: "rs-tooltip-bubble",
3020
- role: "tooltip",
3021
- style: { top: position.top, left: position.left },
3022
- children: content
3023
- }
3024
- ),
3025
- document.body
3026
- )
3027
- ]
3028
- }
3029
- );
3030
- }
3031
- Tooltip.displayName = "Tooltip";
3032
-
3033
- // src/components/ui/FeesAccordion.tsx
3034
- import { useState as useState5 } from "react";
3035
- import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
3036
- function FeesAccordion({ total, rows, tooltip }) {
3037
- const [open, setOpen] = useState5(false);
3038
- const expandable = rows.length > 0;
3039
- return /* @__PURE__ */ jsxs19("div", { className: "rs-fees-accordion", children: [
3040
- /* @__PURE__ */ jsxs19("div", { className: "rs-fees-accordion-summary", children: [
3041
- /* @__PURE__ */ jsxs19("span", { className: "rs-fees-accordion-label", children: [
3042
- /* @__PURE__ */ jsx22("span", { children: "Fees" }),
3043
- tooltip && /* @__PURE__ */ jsx22(Tooltip, { content: tooltip, children: /* @__PURE__ */ jsx22("span", { className: "rs-review-detail-info", "aria-label": "Fees info", children: /* @__PURE__ */ jsx22(InfoIcon, {}) }) })
3044
- ] }),
3045
- /* @__PURE__ */ jsxs19(
3046
- "button",
3047
- {
3048
- type: "button",
3049
- className: "rs-fees-accordion-toggle",
3050
- "aria-label": "Fees",
3051
- "aria-expanded": expandable ? open : void 0,
3052
- disabled: !expandable,
3053
- onClick: () => expandable && setOpen((o) => !o),
3054
- children: [
3055
- /* @__PURE__ */ jsx22("span", { children: total }),
3056
- expandable && /* @__PURE__ */ jsx22(
3057
- "span",
3058
- {
3059
- className: `rs-fees-accordion-chevron${open ? " rs-fees-accordion-chevron--open" : ""}`,
3060
- "aria-hidden": "true",
3061
- children: /* @__PURE__ */ jsx22(ChevronDownIcon, {})
3062
- }
3063
- )
3064
- ]
3065
- }
3066
- )
3067
- ] }),
3068
- expandable && open && /* @__PURE__ */ jsx22("div", { className: "rs-fees-accordion-rows", children: rows.map((row, i) => /* @__PURE__ */ jsxs19("div", { className: "rs-fees-accordion-row", children: [
3069
- /* @__PURE__ */ jsx22("span", { children: row.label }),
3070
- /* @__PURE__ */ jsxs19("span", { className: "rs-review-detail-value", children: [
3071
- /* @__PURE__ */ jsx22(
3072
- "span",
3073
- {
3074
- className: row.strike ? "rs-review-detail-value--strike" : void 0,
3075
- children: row.value
3076
- }
3077
- ),
3078
- row.tooltip && /* @__PURE__ */ jsx22(Tooltip, { content: row.tooltip, children: /* @__PURE__ */ jsx22(
3079
- "span",
3080
- {
3081
- className: "rs-review-detail-info",
3082
- "aria-label": `${row.label} info`,
3083
- children: /* @__PURE__ */ jsx22(InfoIcon, {})
3084
- }
3085
- ) })
3086
- ] })
3087
- ] }, `${row.label}-${i}`)) })
3088
- ] });
3089
- }
3090
- FeesAccordion.displayName = "FeesAccordion";
3091
-
3092
- // src/components/steps/SwappedReceipt.tsx
3093
- import { jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
3094
- function SwappedReceipt({
3095
- onrampMethod,
3096
- onrampMethodIcon,
3097
- amountPaid,
3098
- depositedAmount,
3099
- depositedSymbol,
3100
- feesTotal,
3101
- feeRows,
3102
- feesTooltip,
3103
- newLabel,
3104
- onNewDeposit,
3105
- onClose
3106
- }) {
3107
- return /* @__PURE__ */ jsxs20("div", { className: "rs-screen", children: [
3108
- /* @__PURE__ */ jsxs20("div", { className: "rs-screen-body rs-screen-body--gap-32", children: [
3109
- /* @__PURE__ */ jsx23(BodyHeader, { icon: /* @__PURE__ */ jsx23(CheckIcon, {}), title: "Deposit successful" }),
3110
- /* @__PURE__ */ jsxs20("div", { className: "rs-review-details", children: [
3111
- onrampMethod && /* @__PURE__ */ jsxs20("div", { className: "rs-review-detail-row", children: [
3112
- /* @__PURE__ */ jsx23("span", { children: "Onramp method" }),
3113
- /* @__PURE__ */ jsxs20("span", { className: "rs-review-detail-value", children: [
3114
- /* @__PURE__ */ jsx23("span", { children: onrampMethod }),
3115
- onrampMethodIcon && /* @__PURE__ */ jsx23("span", { className: "rs-review-detail-icon rs-review-detail-icon--square", children: /* @__PURE__ */ jsx23("img", { src: onrampMethodIcon, alt: "" }) })
3116
- ] })
3117
- ] }),
3118
- amountPaid && /* @__PURE__ */ jsxs20("div", { className: "rs-review-detail-row", children: [
3119
- /* @__PURE__ */ jsx23("span", { children: "Amount paid" }),
3120
- /* @__PURE__ */ jsx23("span", { className: "rs-review-detail-value", children: amountPaid })
3121
- ] }),
3122
- /* @__PURE__ */ jsxs20("div", { className: "rs-review-detail-row", children: [
3123
- /* @__PURE__ */ jsx23("span", { children: "Deposited amount" }),
3124
- /* @__PURE__ */ jsxs20("span", { className: "rs-review-detail-value", children: [
3125
- /* @__PURE__ */ jsx23("span", { children: depositedAmount }),
3126
- depositedSymbol && /* @__PURE__ */ jsx23("span", { className: "rs-review-detail-icon", children: /* @__PURE__ */ jsx23(TokenIcon, { symbol: depositedSymbol }) })
3127
- ] })
3128
- ] }),
3129
- feesTotal != null && /* @__PURE__ */ jsx23(
3130
- FeesAccordion,
3131
- {
3132
- total: feesTotal,
3133
- rows: feeRows ?? [],
3134
- tooltip: feesTooltip ?? void 0
3135
- }
3136
- )
3137
- ] }),
3138
- /* @__PURE__ */ jsxs20("div", { className: "rs-screen-button-row", children: [
3139
- onNewDeposit && /* @__PURE__ */ jsx23(Button, { variant: "outline", onClick: onNewDeposit, fullWidth: true, children: newLabel }),
3140
- onClose && /* @__PURE__ */ jsx23(Button, { onClick: onClose, fullWidth: true, children: "Done" })
3141
- ] })
3142
- ] }),
3143
- /* @__PURE__ */ jsx23(PoweredBy, {})
3144
- ] });
3145
- }
3146
- SwappedReceipt.displayName = "SwappedReceipt";
3147
-
3148
- // src/core/webhook.ts
3149
- function isRecord(value) {
3150
- return typeof value === "object" && value !== null;
3151
- }
3152
- function asString(value) {
3153
- return typeof value === "string" ? value : void 0;
3154
- }
3155
- function asNumber(value) {
3156
- if (typeof value === "number" && Number.isFinite(value)) return value;
3157
- if (typeof value !== "string") return void 0;
3158
- const trimmed = value.trim();
3159
- if (!trimmed) return void 0;
3160
- const caipMatch = trimmed.match(/^eip155:(\d+)$/);
3161
- if (caipMatch?.[1]) {
3162
- const parsed2 = Number(caipMatch[1]);
3163
- return Number.isFinite(parsed2) ? parsed2 : void 0;
3164
- }
3165
- const parsed = Number(trimmed);
3166
- return Number.isFinite(parsed) ? parsed : void 0;
3167
- }
3168
- function asAmount(value) {
3169
- if (typeof value === "string") return value;
3170
- if (typeof value === "number" && Number.isFinite(value)) {
3171
- return value.toString();
3172
- }
3173
- return void 0;
3174
- }
3175
- function asAddress(value) {
3176
- if (typeof value !== "string") return void 0;
3177
- return /^0x[a-fA-F0-9]{40}$/.test(value) ? value : void 0;
3178
- }
3179
- function getEventTxHash(event) {
3180
- if (!event?.type) return void 0;
3181
- if (event.type === "deposit-received") {
3182
- return asString(event.data?.transactionHash);
3183
- }
3184
- if (event.type === "bridge-started" || event.type === "bridge-complete") {
3185
- const deposit = isRecord(event.data?.deposit) ? event.data.deposit : void 0;
3186
- const source = isRecord(event.data?.source) ? event.data.source : void 0;
3187
- return asString(deposit?.transactionHash) ?? asString(source?.transactionHash);
3188
- }
3189
- if (event.type === "bridge-failed" || event.type === "error") {
3190
- const deposit = isRecord(event.data?.deposit) ? event.data.deposit : void 0;
3191
- const source = isRecord(event.data?.source) ? event.data.source : void 0;
3192
- return asString(deposit?.transactionHash) ?? asString(source?.transactionHash);
3193
- }
3194
- return void 0;
3195
- }
3196
- function getEventSourceDetails(event) {
3197
- if (!event?.type || !isRecord(event.data)) return {};
3198
- if (event.type === "deposit-received") {
3199
- return {
3200
- chainId: asNumber(event.data.chain),
3201
- amount: asAmount(event.data.amount),
3202
- token: asAddress(event.data.token)
3203
- };
3204
- }
3205
- const source = isRecord(event.data.source) ? event.data.source : void 0;
3206
- const deposit = isRecord(event.data.deposit) ? event.data.deposit : void 0;
3207
- if (event.type === "bridge-started" || event.type === "bridge-complete" || event.type === "bridge-failed" || event.type === "error") {
3208
- return {
3209
- chainId: asNumber(source?.chain) ?? asNumber(deposit?.chain),
3210
- amount: asAmount(source?.amount) ?? asAmount(deposit?.amount),
3211
- token: asAddress(source?.asset) ?? asAddress(deposit?.asset) ?? asAddress(deposit?.token)
3212
- };
3213
- }
3214
- return {};
3215
- }
3216
- function asChain(value) {
3217
- if (typeof value === "string") {
3218
- const trimmed = value.trim();
3219
- if (trimmed.startsWith("solana")) return "solana";
3220
- if (trimmed.startsWith("hypercore")) return "hypercore";
3221
- }
3222
- return asNumber(value);
3223
- }
3224
- function getEventDestinationDetails(event) {
3225
- if (!event?.type || !isRecord(event.data)) return {};
3226
- if (event.type !== "bridge-started" && event.type !== "bridge-complete") {
3227
- return {};
3228
- }
3229
- const destination = isRecord(event.data.destination) ? event.data.destination : void 0;
3230
- if (!destination) return {};
3231
- const token = asString(destination.asset);
3232
- return {
3233
- chainId: asChain(destination.chain),
3234
- amount: asAmount(destination.amount),
3235
- token: token?.trim() || void 0
3236
- };
3237
- }
3238
- function isDepositEvent(event) {
3239
- return event?.type === "deposit-received" || event?.type === "bridge-started" || event?.type === "bridge-complete" || event?.type === "bridge-failed" || event?.type === "error";
3240
- }
3241
- function isFailedEvent(event) {
3242
- return event?.type === "bridge-failed" || event?.type === "error";
3243
- }
3244
- function isHexString(value) {
3245
- return value.startsWith("0x") || value.startsWith("0X");
3246
- }
3247
- function txRefsMatch(a, b) {
3248
- if (isHexString(a) && isHexString(b)) {
3249
- return a.toLowerCase() === b.toLowerCase();
3250
- }
3251
- return a === b;
3252
- }
3253
- function formatBridgeFailedMessage(event) {
3254
- const eventData = event?.data ?? {};
3255
- const code = typeof eventData.errorCode === "string" ? eventData.errorCode : void 0;
3256
- const backendMessage = typeof eventData.message === "string" ? eventData.message.trim() : "";
3257
- function toUserFacingFailure(raw) {
3258
- const lower = raw.toLowerCase();
3259
- if (lower.includes("insufficient funds")) {
3260
- return "Deposit was received, but processing could not continue due to insufficient funds. Please retry.";
3261
- }
3262
- if (lower.includes("no valid quote available")) {
3263
- return "No bridge route is currently available for this transfer. Please try again shortly.";
3264
- }
3265
- if (lower.includes("simulation failed")) {
3266
- return "Transfer processing failed during simulation. Please retry.";
3267
- }
3268
- if (raw.length > 220) {
3269
- return "Transfer processing failed. Please retry.";
3270
- }
3271
- return raw;
3272
- }
3273
- if (backendMessage.length > 0) {
3274
- return { message: toUserFacingFailure(backendMessage), code };
3275
- }
3276
- if (code) {
3277
- return { message: `Bridge failed (${code})`, code };
3278
- }
3279
- return { message: "Bridge failed" };
3280
- }
3281
- function failureMessageForEvent(event) {
3282
- if (event?.type === "error") {
3283
- const message = isRecord(event.data) ? asString(event.data.message) : void 0;
3284
- return message ?? "Unknown error";
3285
- }
3286
- return formatBridgeFailedMessage(event).message;
3287
- }
3288
-
3289
- // src/core/token-amount.ts
3290
- import { formatUnits } from "viem";
3291
- var STABLECOIN_SYMBOLS = /* @__PURE__ */ new Set([
3292
- "USDC",
3293
- "USDT",
3294
- "USDT0",
3295
- "DAI",
3296
- "FRAX",
3297
- "PYUSD",
3298
- "USDP",
3299
- "TUSD",
3300
- "GUSD",
3301
- "USDS",
3302
- "LUSD",
3303
- "BUSD",
3304
- "USDE"
3305
- ]);
3306
- var EVM_ADDRESS_RE = /^0x[a-fA-F0-9]{40}$/;
3307
- function resolveTokenDisplay(token, chain, fallback) {
3308
- if (token !== void 0) {
3309
- if (chain === "solana") {
3310
- const solanaToken = getSolanaTokenByMint(token);
3311
- if (solanaToken) {
3312
- return { symbol: solanaToken.symbol, decimals: solanaToken.decimals };
3313
- }
3314
- } else if (chain === "hypercore") {
3315
- const t = HYPERCORE_SOURCE_TOKENS.find(
3316
- (x) => x.address.toLowerCase() === token.toLowerCase()
3317
- );
3318
- if (t) return { symbol: t.symbol, decimals: t.decimals };
3319
- } else if (EVM_ADDRESS_RE.test(token)) {
3320
- const symbol = getTokenSymbol(token, chain);
3321
- const decimals = findTokenDecimals(token, chain);
3322
- if (symbol !== "Token" || decimals !== void 0) {
3323
- return {
3324
- symbol: symbol !== "Token" ? symbol : fallback?.symbol ?? symbol,
3325
- decimals: decimals ?? fallback?.decimals
3326
- };
3327
- }
3328
- }
3329
- }
3330
- return {
3331
- symbol: fallback?.symbol ?? "Token",
3332
- decimals: fallback?.decimals
3333
- };
3334
- }
3335
- function maxFractionDigitsFor(symbol) {
3336
- if (!symbol) return 6;
3337
- return STABLECOIN_SYMBOLS.has(symbol.toUpperCase()) ? 3 : 6;
3338
- }
3339
- function formatTokenAmount(amount, symbol) {
3340
- if (!Number.isFinite(amount)) return void 0;
3341
- return amount.toLocaleString("en-US", {
3342
- minimumFractionDigits: 2,
3343
- maximumFractionDigits: maxFractionDigitsFor(symbol)
3344
- });
3345
- }
3346
- function tokenAmountToNumber(rawAmount, decimals) {
3347
- if (decimals === void 0) return void 0;
3348
- try {
3349
- const value = Number(formatUnits(BigInt(rawAmount), decimals));
3350
- return Number.isFinite(value) ? value : void 0;
3351
- } catch {
3352
- return void 0;
3353
- }
3354
- }
3355
- function formatRawTokenAmount(rawAmount, token) {
3356
- const value = tokenAmountToNumber(rawAmount, token.decimals);
3357
- if (value === void 0) return void 0;
3358
- return formatTokenAmount(value, token.symbol);
3359
- }
3360
- function isDisplayStablecoinSymbol(symbol) {
3361
- return symbol !== void 0 && STABLECOIN_SYMBOLS.has(symbol.toUpperCase());
3362
- }
3363
- function priceUsdFor(symbol, prices) {
3364
- if (!symbol) return void 0;
3365
- const quoted = prices[symbol.toUpperCase()];
3366
- return typeof quoted === "number" && quoted > 0 ? quoted : void 0;
3367
- }
3368
- function isRecognizedToken(address, chain) {
3369
- if (address === void 0 || chain === void 0) return false;
3370
- if (chain === "solana") return getSolanaTokenByMint(address) !== void 0;
3371
- if (chain === "hypercore") {
3372
- return HYPERCORE_SOURCE_TOKENS.some(
3373
- (t) => t.address.toLowerCase() === address.toLowerCase()
3374
- );
3375
- }
3376
- return EVM_ADDRESS_RE.test(address) && isRegistryTokenOnChain(address, chain);
3377
- }
3378
- function estimateReceiveAmount(params) {
3379
- const {
3380
- sourceAmount,
3381
- sourceSymbol,
3382
- targetSymbol,
3383
- sourceAmountUsd,
3384
- prices,
3385
- sourceTrusted
3386
- } = params;
3387
- const trusted = sourceTrusted !== false;
3388
- if (trusted && sourceSymbol !== void 0 && sourceSymbol.toUpperCase() === targetSymbol.toUpperCase()) {
3389
- return sourceAmount;
3390
- }
3391
- if (!trusted) return void 0;
3392
- const usdValue = sourceAmountUsd !== void 0 && Number.isFinite(sourceAmountUsd) ? sourceAmountUsd : sourceAmount !== void 0 ? (() => {
3393
- const sourcePrice = priceUsdFor(sourceSymbol, prices);
3394
- return sourcePrice !== void 0 ? sourceAmount * sourcePrice : void 0;
3395
- })() : void 0;
3396
- if (usdValue === void 0) return void 0;
3397
- const targetPrice = priceUsdFor(targetSymbol, prices);
3398
- if (targetPrice === void 0) return void 0;
3399
- return usdValue / targetPrice;
3400
- }
3401
- function formatQuotedReceive(output, fallbackSymbol) {
3402
- if (output.decimals === null) return void 0;
3403
- let raw;
3404
- try {
3405
- raw = BigInt(output.amount);
3406
- } catch {
3407
- return void 0;
3408
- }
3409
- if (raw <= 0n) return void 0;
3410
- const symbol = output.symbol ?? fallbackSymbol;
3411
- const formatted = formatRawTokenAmount(raw, {
3412
- symbol,
3413
- decimals: output.decimals
3414
- });
3415
- if (formatted === void 0) return void 0;
3416
- return `~${formatted} ${symbol}`;
3417
- }
3418
- function formatReceiveEstimate(params) {
3419
- const estimate = estimateReceiveAmount(params);
3420
- if (estimate === void 0) return void 0;
3421
- const formatted = formatTokenAmount(estimate, params.targetSymbol);
3422
- if (formatted === void 0) return void 0;
3423
- const sameSymbol = params.sourceSymbol.toUpperCase() === params.targetSymbol.toUpperCase();
3424
- return sameSymbol ? `${formatted} ${params.targetSymbol}` : `~${formatted} ${params.targetSymbol}`;
3425
- }
3426
-
3427
- // src/components/steps/ProcessingStep.tsx
3428
- import { Fragment as Fragment5, jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
3429
- function SuccessBadge() {
3430
- return /* @__PURE__ */ jsxs21(
3431
- "svg",
3432
- {
3433
- width: "40",
3434
- height: "40",
3435
- viewBox: "0 0 40 40",
3436
- fill: "none",
3437
- xmlns: "http://www.w3.org/2000/svg",
3438
- "aria-hidden": "true",
3439
- children: [
3440
- /* @__PURE__ */ jsx24(
3441
- "rect",
3442
- {
3443
- width: "40",
3444
- height: "40",
3445
- rx: "8",
3446
- fill: "var(--rs-icon-wrapper-bg)"
3447
- }
3448
- ),
3449
- /* @__PURE__ */ jsx24(
3450
- "path",
3451
- {
3452
- d: "M28 14L17 25L12 20",
3453
- stroke: "var(--rs-icon-wrapper-icon)",
3454
- strokeWidth: "2",
3455
- strokeLinecap: "round",
3456
- strokeLinejoin: "round"
3457
- }
3458
- )
3459
- ]
3460
- }
3461
- );
3462
- }
3463
- function FailedBadge() {
3464
- return /* @__PURE__ */ jsxs21(
3465
- "svg",
3466
- {
3467
- width: "40",
3468
- height: "40",
3469
- viewBox: "0 0 40 40",
3470
- fill: "none",
3471
- xmlns: "http://www.w3.org/2000/svg",
3472
- "aria-hidden": "true",
3473
- children: [
3474
- /* @__PURE__ */ jsx24("rect", { width: "40", height: "40", rx: "8", fill: "#FB2C36" }),
3475
- /* @__PURE__ */ jsx24(
3476
- "path",
3477
- {
3478
- d: "M26 14L14 26M14 14L26 26",
3479
- stroke: "white",
3480
- strokeWidth: "2",
3481
- strokeLinecap: "round",
3482
- strokeLinejoin: "round"
3483
- }
3484
- )
3485
- ]
3486
- }
3487
- );
3488
- }
3489
- var INITIAL_POLL_INTERVAL = 3e3;
3490
- var MAX_POLL_INTERVAL = 3e4;
3491
- var BACKOFF_MULTIPLIER = 1.5;
3492
- var SWAPPED_RECEIPT_STATUS_RETRY_INTERVAL_MS = 1e3;
3493
- var SWAPPED_FIAT_STATUS_MAX_ATTEMPTS = 12;
3494
- var ESCALATED_DELAY_MS = 10 * 60 * 1e3;
3495
- var SOFT_DELAY_MS = {
3496
- confirming: 90 * 1e3,
3497
- received: 90 * 1e3,
3498
- bridging: 4 * 60 * 1e3
3499
- };
3500
- var PHASE_TIMINGS_PREFIX = "rhinestone:phase-timings";
3501
- var PAYMENT_METHOD_LABELS = {
3502
- creditcard: "Card",
3503
- debitcard: "Card",
3504
- card: "Card",
3505
- "apple-pay": "Apple Pay",
3506
- applepay: "Apple Pay",
3507
- "google-pay": "Google Pay",
3508
- googlepay: "Google Pay",
3509
- "bank-transfer": "Bank Transfer",
3510
- banktransfer: "Bank Transfer",
3511
- sepa: "SEPA",
3512
- "open-banking": "Open Banking",
3513
- "krak-pay": "Kraken Pay",
3514
- krakpay: "Kraken Pay",
3515
- kraken: "Kraken",
3516
- coinbase: "Coinbase",
3517
- binance: "Binance"
3518
- };
3519
- function formatPaymentMethod(method) {
3520
- const key = method.trim().toLowerCase();
3521
- if (PAYMENT_METHOD_LABELS[key]) return PAYMENT_METHOD_LABELS[key];
3522
- return key.replace(/[-_]+/g, " ").split(" ").filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
3523
- }
3524
- function normalizeFeeUsd(value) {
3525
- return Number.isFinite(value) ? Math.max(0, value) : null;
3526
- }
3527
- function formatUsdFee(value) {
3528
- return `$${normalizeFeeUsd(value)?.toFixed(2) ?? "0.00"}`;
3529
- }
3530
- function getMarketNetworkFees(breakdown) {
3531
- if (!breakdown) return null;
3532
- const gasUsd = normalizeFeeUsd(breakdown.gasUsd);
3533
- const bridgeUsd = normalizeFeeUsd(breakdown.bridgeUsd);
3534
- const swapUsd = normalizeFeeUsd(breakdown.swapUsd);
3535
- if (gasUsd === null || bridgeUsd === null || swapUsd === null) return null;
3536
- return {
3537
- marketUsd: bridgeUsd + swapUsd,
3538
- networkUsd: gasUsd
3539
- };
3540
- }
3541
- function toSwappedFiatContext(status) {
3542
- return {
3543
- orderCrypto: status.orderCrypto,
3544
- orderCryptoAmount: status.orderCryptoAmount,
3545
- paidAmountUsd: status.paidAmountUsd,
3546
- paidAmountEur: status.paidAmountEur,
3547
- onrampFeeUsd: status.onrampFeeUsd,
3548
- paymentMethod: status.paymentMethod
3549
- };
3550
- }
3551
- function hasFiatReceiptPricing(status) {
3552
- return status.paidAmountUsd != null && status.onrampFeeUsd != null;
3553
- }
3554
- function loadPhaseTimings(txHash) {
3555
- if (typeof window === "undefined") return null;
3556
- try {
3557
- const raw = window.localStorage.getItem(`${PHASE_TIMINGS_PREFIX}:${txHash}`);
3558
- if (!raw) return null;
3559
- const parsed = JSON.parse(raw);
3560
- if (typeof parsed.startedAt !== "number") return null;
3561
- return parsed;
3562
- } catch {
3563
- return null;
3564
- }
3565
- }
3566
- function savePhaseTimings(txHash, timings) {
3567
- if (typeof window === "undefined") return;
3568
- try {
3569
- window.localStorage.setItem(
3570
- `${PHASE_TIMINGS_PREFIX}:${txHash}`,
3571
- JSON.stringify(timings)
3572
- );
3573
- } catch {
3574
- }
3575
- }
3576
- function isEventForTx(event, txHash) {
3577
- const eventTxHash = getEventTxHash(event);
3578
- if (!eventTxHash) return false;
3579
- return txRefsMatch(eventTxHash, txHash);
3580
- }
3581
- function parseWebhookTimestamp(event) {
3582
- if (typeof event?.time !== "string") return void 0;
3583
- const timestamp = Date.parse(event.time);
3584
- return Number.isFinite(timestamp) ? timestamp : void 0;
3585
- }
3586
- function syncPhaseTimings(previous, event) {
3587
- if (!event?.type) return previous;
3588
- const timestamp = parseWebhookTimestamp(event) ?? Date.now();
3589
- const setReceived = (event.type === "deposit-received" || event.type === "bridge-started" || event.type === "bridge-complete" || event.type === "bridge-failed" || event.type === "error") && previous.receivedAt === void 0;
3590
- const setBridging = (event.type === "bridge-started" || event.type === "bridge-complete") && previous.bridgingAt === void 0;
3591
- const setCompleted = event.type === "bridge-complete" && previous.completedAt === void 0;
3592
- if (!setReceived && !setBridging && !setCompleted) return previous;
3593
- return {
3594
- ...previous,
3595
- ...setReceived && { receivedAt: timestamp },
3596
- ...setBridging && { bridgingAt: timestamp },
3597
- ...setCompleted && { completedAt: timestamp }
3598
- };
3599
- }
3600
- function formatTimer(seconds) {
3601
- const safe = Math.max(0, seconds);
3602
- const mins = Math.floor(safe / 60);
3603
- const secs = safe % 60;
3604
- return `${mins}:${String(secs).padStart(2, "0")}`;
3605
- }
3606
- function TickerChar({ value }) {
3607
- const [current, setCurrent] = useState6(value);
3608
- const [previous, setPrevious] = useState6(null);
3609
- const [animKey, setAnimKey] = useState6(0);
3610
- useEffect6(() => {
3611
- if (value === current) return;
3612
- setPrevious(current);
3613
- setCurrent(value);
3614
- setAnimKey((k) => k + 1);
3615
- const timeout = setTimeout(() => setPrevious(null), 360);
3616
- return () => clearTimeout(timeout);
3617
- }, [value, current]);
3618
- return /* @__PURE__ */ jsxs21("span", { className: "rs-ticker-slot", children: [
3619
- previous !== null && /* @__PURE__ */ jsx24("span", { className: "rs-ticker-out", children: previous }, `out-${animKey}`),
3620
- /* @__PURE__ */ jsx24("span", { className: "rs-ticker-in", children: current }, `in-${animKey}`)
3621
- ] });
3622
- }
3623
- function Ticker({ value }) {
3624
- return /* @__PURE__ */ jsx24("span", { className: "rs-ticker", "aria-label": value, children: value.split("").map((char, index) => (
3625
- // Position-stable key so each slot keeps its own animation state.
3626
- // eslint-disable-next-line react/no-array-index-key
3627
- /* @__PURE__ */ jsx24(TickerChar, { value: char }, index)
3628
- )) });
3629
- }
3630
- function getPhaseStartTime(phaseId, phaseTimings) {
3631
- if (phaseId === "confirming") return phaseTimings.startedAt;
3632
- if (phaseId === "received") {
3633
- return phaseTimings.receivedAt ?? phaseTimings.startedAt;
3634
- }
3635
- return phaseTimings.bridgingAt ?? phaseTimings.receivedAt ?? phaseTimings.startedAt;
3636
- }
3637
- function getFailedPhaseId(phaseTimings) {
3638
- if (phaseTimings.bridgingAt !== void 0) return "bridging";
3639
- if (phaseTimings.receivedAt !== void 0) return "received";
3640
- return "confirming";
3641
- }
3642
- function getCurrentPhaseId(state, phaseTimings) {
3643
- if (state.type === "failed") {
3644
- return getFailedPhaseId(phaseTimings);
3645
- }
3646
- if (state.type === "complete") {
3647
- return void 0;
3648
- }
3649
- if (state.lastEvent?.type === "bridge-started" || state.lastEvent?.type === "bridge-complete")
3650
- return "bridging";
3651
- if (state.lastEvent?.type === "deposit-received") return "received";
3652
- return "confirming";
3653
- }
3654
- function getCompletionDestinationTxHash(event) {
3655
- const eventData = event?.data;
3656
- const swapTxHash = eventData?.swap?.transactionHash;
3657
- const destinationTxHash = eventData?.destination?.transactionHash;
3658
- return swapTxHash ?? destinationTxHash;
3659
- }
3660
- function getTerminalProcessingOutcome(event) {
3661
- if (event?.type === "post-bridge-swap-complete") {
3662
- return {
3663
- type: "complete",
3664
- destinationTxHash: getCompletionDestinationTxHash(event)
3665
- };
3666
- }
3667
- if (event?.type === "post-bridge-swap-failed") {
3668
- return {
3669
- type: "failed",
3670
- message: formatBridgeFailedMessage(event).message
3671
- };
3672
- }
3673
- if (event?.type === "bridge-complete") {
3674
- return {
3675
- type: "complete",
3676
- destinationTxHash: getCompletionDestinationTxHash(event)
3677
- };
3678
- }
3679
- if (event?.type === "bridge-failed") {
3680
- return {
3681
- type: "failed",
3682
- message: formatBridgeFailedMessage(event).message
3683
- };
3684
- }
3685
- if (event?.type === "error") {
3686
- return {
3687
- type: "failed",
3688
- message: event.data?.message ?? "Unknown error"
3689
- };
3690
- }
3691
- return null;
3692
- }
3693
- function getInitialProcessingState(event, txHash) {
3694
- if (!event || !isEventForTx(event, txHash)) return null;
3695
- const terminal = getTerminalProcessingOutcome(event);
3696
- if (terminal?.type === "complete") {
3697
- return { type: "complete", lastEvent: event };
3698
- }
3699
- if (terminal?.type === "failed") {
3700
- return { type: "failed", message: terminal.message, lastEvent: event };
3701
- }
3702
- if (isDepositEvent(event)) {
3703
- return { type: "processing", lastEvent: event };
3704
- }
3705
- return null;
3706
- }
3707
- function ProcessingStep({
3708
- smartAccount,
3709
- solanaDepositAddress,
3710
- txHash,
3711
- sourceChain,
3712
- sourceToken,
3713
- targetChain,
3714
- amount,
3715
- sourceSymbol: providedSourceSymbol,
3716
- sourceDecimals: providedSourceDecimals,
3717
- amountUsd,
3718
- service,
3719
- directTransfer,
3720
- initialEvent,
3721
- flowLabel = "deposit",
3722
- debug,
3723
- targetToken,
3724
- uiConfig,
3725
- quotedFeeAmount,
3726
- quotedFeeSymbol,
3727
- quoteFeeBreakdown,
3728
- balanceAfterUsd,
3729
- isSwappedOrder,
3730
- swappedContext,
3731
- onClose,
3732
- onNewDeposit,
3733
- onRetry,
3734
- onDepositComplete,
3735
- onDepositFailed,
3736
- onError
3737
- }) {
3738
- const startTimeRef = useRef4(Date.now());
3739
- const pollIntervalRef = useRef4(INITIAL_POLL_INTERVAL);
3740
- const pollTimeoutRef = useRef4(null);
3741
- const escalatedDelayRef = useRef4(false);
3742
- const processingContextRef = useLatestRef({
3743
- amount,
3744
- sourceChain,
3745
- sourceToken,
3746
- sourceDecimals: providedSourceDecimals,
3747
- amountUsd,
3748
- targetChain,
3749
- targetToken
3750
- });
3751
- const onDepositCompleteRef = useLatestRef(onDepositComplete);
3752
- const onDepositFailedRef = useLatestRef(onDepositFailed);
3753
- const onErrorRef = useLatestRef(onError);
3754
- const initialTerminalEventRef = useRef4(null);
3755
- const [state, setState] = useState6(() => {
3756
- if (directTransfer) return { type: "complete" };
3757
- const initial = getInitialProcessingState(
3758
- initialEvent,
3759
- txHash
3760
- );
3761
- if (initial) {
3762
- if (initial.type !== "processing") {
3763
- initialTerminalEventRef.current = initial.lastEvent ?? null;
3764
- }
3765
- return initial;
3766
- }
3767
- return { type: "processing" };
3768
- });
3769
- const [elapsedSeconds, setElapsedSeconds] = useState6(0);
3770
- const [phaseTimings, setPhaseTimings] = useState6(() => {
3771
- const saved = loadPhaseTimings(txHash);
3772
- if (saved) {
3773
- startTimeRef.current = saved.startedAt;
3774
- return saved;
3775
- }
3776
- return { startedAt: startTimeRef.current };
3777
- });
3778
- const [hasEscalatedDelay, setHasEscalatedDelay] = useState6(false);
3779
- const updatePhaseTimings = useCallback3(
3780
- (updater) => {
3781
- setPhaseTimings((previous) => {
3782
- const next = updater(previous);
3783
- savePhaseTimings(txHash, next);
3784
- return next;
3785
- });
3786
- },
3787
- [txHash]
3788
- );
3789
- useEffect6(() => {
3790
- if (!directTransfer) return;
3791
- const completedAt = Date.now();
3792
- updatePhaseTimings(() => ({
3793
- startedAt: startTimeRef.current,
3794
- completedAt,
3795
- endedAt: completedAt
3796
- }));
3797
- debugLog(debug, "processing", "direct-transfer:complete", {
3798
- txHash,
3799
- flowLabel
3800
- });
3801
- const context = processingContextRef.current;
3802
- onDepositCompleteRef.current?.(txHash, void 0, {
3803
- amount: context.amount,
3804
- sourceChain: context.sourceChain,
3805
- sourceToken: context.sourceToken,
3806
- sourceDecimals: context.sourceDecimals,
3807
- amountUsd: context.amountUsd,
3808
- targetChain: context.targetChain,
3809
- targetToken: context.targetToken
3810
- });
3811
- }, [
3812
- debug,
3813
- directTransfer,
3814
- flowLabel,
3815
- onDepositCompleteRef,
3816
- processingContextRef,
3817
- txHash,
3818
- updatePhaseTimings
3819
- ]);
3820
- useEffect6(() => {
3821
- const event = initialTerminalEventRef.current;
3822
- if (!event) return;
3823
- initialTerminalEventRef.current = null;
3824
- const outcome = getTerminalProcessingOutcome(event);
3825
- if (!outcome) return;
3826
- if (outcome.type === "complete") {
3827
- const context = processingContextRef.current;
3828
- debugLog(debug, "processing", "initial-event:complete", {
3829
- txHash,
3830
- destinationTxHash: outcome.destinationTxHash,
3831
- event: event.type
3832
- });
3833
- onDepositCompleteRef.current?.(txHash, outcome.destinationTxHash, {
3834
- amount: context.amount,
3835
- sourceChain: context.sourceChain,
3836
- sourceToken: context.sourceToken,
3837
- sourceDecimals: context.sourceDecimals,
3838
- amountUsd: context.amountUsd,
3839
- targetChain: context.targetChain,
3840
- targetToken: context.targetToken
3841
- });
3842
- return;
3843
- }
3844
- debugLog(debug, "processing", "initial-event:failed", {
3845
- txHash,
3846
- message: outcome.message,
3847
- event: event.type
3848
- });
3849
- onDepositFailedRef.current?.(txHash, outcome.message);
3850
- }, [
3851
- debug,
3852
- onDepositCompleteRef,
3853
- onDepositFailedRef,
3854
- processingContextRef,
3855
- txHash
3856
- ]);
3857
- useEffect6(() => {
3858
- if (directTransfer || state.type !== "processing") return;
3859
- const updateElapsed = () => {
3860
- setElapsedSeconds(
3861
- Math.floor((Date.now() - startTimeRef.current) / 1e3)
3862
- );
3863
- };
3864
- updateElapsed();
3865
- const intervalId = setInterval(updateElapsed, 1e3);
3866
- return () => clearInterval(intervalId);
3867
- }, [directTransfer, state.type]);
3868
- useEffect6(() => {
3869
- if (state.type === "processing") return;
3870
- const endedAt = state.type === "complete" ? phaseTimings.completedAt ?? Date.now() : Date.now();
3871
- setElapsedSeconds(Math.floor((endedAt - startTimeRef.current) / 1e3));
3872
- updatePhaseTimings(
3873
- (previous) => previous.endedAt !== void 0 ? previous : { ...previous, endedAt }
3874
- );
3875
- }, [phaseTimings.completedAt, state.type, updatePhaseTimings]);
3876
- useEffect6(() => {
3877
- if (!state.lastEvent) return;
3878
- updatePhaseTimings(
3879
- (previous) => syncPhaseTimings(previous, state.lastEvent)
3880
- );
3881
- }, [state.lastEvent?.time, state.lastEvent?.type, updatePhaseTimings]);
3882
- const [swappedFiatContext, setSwappedFiatContext] = useState6(null);
3883
- useEffect6(() => {
3884
- let cancelled = false;
3885
- let timeoutId;
3886
- const isFiatSwappedOrder = isSwappedOrder && swappedContext?.variant === "fiat";
3887
- const expectedOrderUuid = swappedContext?.expectedOrderUuid ?? null;
3888
- setSwappedFiatContext(null);
3889
- if (isFiatSwappedOrder && !expectedOrderUuid) {
3890
- return () => {
3891
- cancelled = true;
3892
- };
3893
- }
3894
- let attempts = 0;
3895
- const matchesCurrentDeposit = (res) => {
3896
- if (isFiatSwappedOrder) {
3897
- return res.orderId === expectedOrderUuid;
3898
- }
3899
- return res.transactionId != null && res.transactionId.toLowerCase() === txHash.toLowerCase();
3900
- };
3901
- const scheduleRetry = () => {
3902
- if (cancelled || !isFiatSwappedOrder || attempts >= SWAPPED_FIAT_STATUS_MAX_ATTEMPTS) {
3903
- return;
3904
- }
3905
- timeoutId = setTimeout(
3906
- fetchContext,
3907
- SWAPPED_RECEIPT_STATUS_RETRY_INTERVAL_MS
3908
- );
3909
- };
3910
- async function fetchContext() {
3911
- attempts += 1;
3912
- try {
3913
- const res = await service.fetchSwappedOrderStatus(smartAccount);
3914
- if (cancelled) return;
3915
- if (!res || !matchesCurrentDeposit(res)) {
3916
- scheduleRetry();
3917
- return;
3918
- }
3919
- setSwappedFiatContext(toSwappedFiatContext(res));
3920
- if (isFiatSwappedOrder && !hasFiatReceiptPricing(res)) {
3921
- scheduleRetry();
3922
- }
3923
- } catch {
3924
- scheduleRetry();
3925
- }
3926
- }
3927
- fetchContext();
3928
- return () => {
3929
- cancelled = true;
3930
- if (timeoutId !== void 0) clearTimeout(timeoutId);
3931
- };
3932
- }, [
3933
- service,
3934
- smartAccount,
3935
- txHash,
3936
- isSwappedOrder,
3937
- swappedContext?.variant,
3938
- swappedContext?.expectedOrderUuid
3939
- ]);
3940
- useEffect6(() => {
3941
- if (directTransfer) return;
3942
- if (state.type !== "processing") {
3943
- pollIntervalRef.current = INITIAL_POLL_INTERVAL;
3944
- return;
3945
- }
3946
- let isMounted = true;
3947
- async function pollStatus() {
3948
- try {
3949
- const account = sourceChain === "solana" && solanaDepositAddress ? solanaDepositAddress : smartAccount;
3950
- debugLog(debug, "processing", "poll:request", {
3951
- account,
3952
- txHash,
3953
- intervalMs: pollIntervalRef.current
3954
- });
3955
- const data = await service.fetchStatus(account, txHash);
3956
- const lastEvent2 = data.lastEvent;
3957
- const eventMatchesTx = isEventForTx(lastEvent2, txHash);
3958
- const eventForCurrentTx = eventMatchesTx ? lastEvent2 : void 0;
3959
- if (lastEvent2) {
3960
- const eventData = lastEvent2.data;
3961
- debugLog(debug, "processing", "poll:event", {
3962
- type: lastEvent2.type,
3963
- matchesTx: eventMatchesTx,
3964
- intentId: eventData?.intentId
3965
- });
3966
- }
3967
- if (!isMounted) return;
3968
- if (eventForCurrentTx?.type === "bridge-complete") {
3969
- setState({ type: "complete", lastEvent: eventForCurrentTx });
3970
- const destinationTxHash2 = eventForCurrentTx.data?.destination?.transactionHash;
3971
- debugLog(debug, "processing", "state:complete", {
3972
- txHash,
3973
- destinationTxHash: destinationTxHash2,
3974
- event: eventForCurrentTx.type
3975
- });
3976
- const context = processingContextRef.current;
3977
- onDepositCompleteRef.current?.(txHash, destinationTxHash2, {
3978
- amount: context.amount,
3979
- sourceChain: context.sourceChain,
3980
- sourceToken: context.sourceToken,
3981
- sourceDecimals: context.sourceDecimals,
3982
- amountUsd: context.amountUsd,
3983
- targetChain: context.targetChain,
3984
- targetToken: context.targetToken
3985
- });
3986
- return;
3987
- }
3988
- if (eventForCurrentTx?.type === "bridge-failed") {
3989
- const formatted = formatBridgeFailedMessage(eventForCurrentTx);
3990
- setState({
3991
- type: "failed",
3992
- message: formatted.message,
3993
- lastEvent: eventForCurrentTx
3994
- });
3995
- debugLog(debug, "processing", "state:failed", {
3996
- txHash,
3997
- message: formatted.message,
3998
- code: formatted.code
3999
- });
4000
- onDepositFailedRef.current?.(txHash, formatted.message);
4001
- return;
4002
- }
4003
- if (eventForCurrentTx?.type === "error") {
4004
- const errorMessage = eventForCurrentTx.data?.message ?? "Unknown error";
4005
- setState({
4006
- type: "failed",
4007
- message: errorMessage,
4008
- lastEvent: eventForCurrentTx
4009
- });
4010
- debugLog(debug, "processing", "state:error-event", {
4011
- txHash,
4012
- message: errorMessage
4013
- });
4014
- onDepositFailedRef.current?.(txHash, errorMessage);
4015
- return;
4016
- }
4017
- setState((previous) => ({
4018
- type: "processing",
4019
- lastEvent: eventForCurrentTx ?? previous.lastEvent
4020
- }));
4021
- scheduleNextPoll();
4022
- } catch (error) {
4023
- debugError(debug, "processing", "poll:failure", error, {
4024
- smartAccount,
4025
- txHash,
4026
- intervalMs: pollIntervalRef.current
4027
- });
4028
- scheduleNextPoll();
4029
- }
4030
- }
4031
- function scheduleNextPoll() {
4032
- if (!isMounted) return;
4033
- pollTimeoutRef.current = setTimeout(() => {
4034
- pollIntervalRef.current = Math.min(
4035
- pollIntervalRef.current * BACKOFF_MULTIPLIER,
4036
- MAX_POLL_INTERVAL
4037
- );
4038
- debugLog(debug, "processing", "poll:scheduled", {
4039
- nextIntervalMs: pollIntervalRef.current
4040
- });
4041
- pollStatus();
4042
- }, pollIntervalRef.current);
4043
- }
4044
- pollStatus();
4045
- return () => {
4046
- isMounted = false;
4047
- if (pollTimeoutRef.current) {
4048
- clearTimeout(pollTimeoutRef.current);
4049
- }
4050
- };
4051
- }, [
4052
- debug,
4053
- directTransfer,
4054
- onDepositCompleteRef,
4055
- onDepositFailedRef,
4056
- processingContextRef,
4057
- service,
4058
- smartAccount,
4059
- solanaDepositAddress,
4060
- sourceChain,
4061
- state.type,
4062
- txHash
4063
- ]);
4064
- useEffect6(() => {
4065
- if (directTransfer || state.type !== "processing") return;
4066
- const timeoutId = setTimeout(() => {
4067
- if (escalatedDelayRef.current) return;
4068
- escalatedDelayRef.current = true;
4069
- setHasEscalatedDelay(true);
4070
- const message = "Transfer is taking longer than expected. Your funds are safe and processing will continue automatically.";
4071
- debugLog(debug, "processing", "state:delay-escalated", {
4072
- txHash,
4073
- timeoutMs: ESCALATED_DELAY_MS
4074
- });
4075
- onErrorRef.current?.(message, "PROCESS_TIMEOUT");
4076
- }, ESCALATED_DELAY_MS);
4077
- return () => clearTimeout(timeoutId);
4078
- }, [debug, directTransfer, onErrorRef, state.type, txHash]);
4079
- const isComplete = state.type === "complete";
4080
- const isFailed = state.type === "failed";
4081
- const isProcessing = state.type === "processing";
4082
- const lastEvent = state.lastEvent;
4083
- const failureMessage = state.type === "failed" ? state.message : void 0;
4084
- const timelineNowMs = phaseTimings.endedAt ?? Date.now();
4085
- const flowNoun = flowLabel === "withdraw" ? "withdrawal" : "deposit";
4086
- const flowCapitalized = flowLabel === "withdraw" ? "Withdrawal" : "Deposit";
4087
- const destinationTxHash = lastEvent?.data?.destination?.transactionHash || null;
4088
- const sourceDetails = getEventSourceDetails(lastEvent);
4089
- const displaySourceChain = sourceDetails.chainId ?? sourceChain;
4090
- const displaySourceToken = sourceDetails.token ?? sourceToken;
4091
- const displayAmount = sourceDetails.amount ?? amount;
4092
- const sourceExplorerUrl = getExplorerTxUrl(displaySourceChain, txHash);
4093
- const destExplorerUrl = destinationTxHash ? getExplorerTxUrl(targetChain, destinationTxHash) : null;
4094
- const sourceDisplay = (() => {
4095
- const resolved = resolveTokenDisplay(displaySourceToken, displaySourceChain, {
4096
- symbol: providedSourceSymbol ?? (displaySourceChain === "solana" ? "SOL" : "Token"),
4097
- decimals: providedSourceDecimals
4098
- });
4099
- return {
4100
- symbol: resolved.symbol,
4101
- decimals: resolved.decimals ?? (displaySourceChain === "solana" ? 9 : 18)
4102
- };
4103
- })();
4104
- const sourceSymbol = sourceDisplay.symbol;
4105
- const formattedSentAmount = formatRawTokenAmount(displayAmount, sourceDisplay) ?? // Not raw base units (e.g. a decimal string) — render the number as-is.
4106
- formatTokenAmount(Number(displayAmount), sourceDisplay.symbol) ?? displayAmount;
4107
- const eventDestination = getEventDestinationDetails(lastEvent);
4108
- const targetDisplay = resolveTokenDisplay(
4109
- eventDestination.token ?? targetToken,
4110
- eventDestination.chainId ?? targetChain,
4111
- // Dapp deposits default to USDC targets; mirror the source symbol last so
4112
- // unresolvable same-token routes still label sensibly.
4113
- { symbol: providedSourceSymbol ?? "USDC" }
4114
- );
4115
- const targetSymbol = targetDisplay.symbol;
4116
- const formattedDestinationAmount = eventDestination.amount !== void 0 ? formatRawTokenAmount(eventDestination.amount, targetDisplay) : void 0;
4117
- const amountUsdNumber = amountUsd !== void 0 && Number(amountUsd) > 0 ? Number(amountUsd) : void 0;
4118
- const prices = useTokenPrices(service, [
4119
- {
4120
- chainId: displaySourceChain,
4121
- address: displaySourceToken,
4122
- symbol: sourceDisplay.symbol
4123
- },
4124
- {
4125
- chainId: eventDestination.chainId ?? targetChain,
4126
- address: eventDestination.token ?? targetToken,
4127
- symbol: targetDisplay.symbol
4128
- }
4129
- ]);
4130
- const estimatedReceiveAmount = (() => {
4131
- const estimate = estimateReceiveAmount({
4132
- sourceAmount: tokenAmountToNumber(displayAmount, sourceDisplay.decimals),
4133
- sourceSymbol: sourceDisplay.symbol,
4134
- targetSymbol: targetDisplay.symbol,
4135
- sourceAmountUsd: amountUsdNumber,
4136
- sourceTrusted: isRecognizedToken(displaySourceToken, displaySourceChain),
4137
- prices
4138
- });
4139
- return estimate !== void 0 ? formatTokenAmount(estimate, targetDisplay.symbol) : void 0;
4140
- })();
4141
- const receiveDisplay = formattedDestinationAmount ? `${formattedDestinationAmount} ${targetSymbol}` : estimatedReceiveAmount !== void 0 ? `~${estimatedReceiveAmount} ${targetSymbol}` : amountUsdNumber !== void 0 ? `~$${amountUsdNumber.toFixed(2)}` : (
4142
- // Cross-token with no price and no USD context (rare QR case):
4143
- // an honest dash beats a wrong number.
4144
- "\u2014"
4145
- );
4146
- const formattedBridgingCost = (() => {
4147
- if (sourceSymbol.toUpperCase() !== targetSymbol.toUpperCase()) {
4148
- return void 0;
4149
- }
4150
- const sentValue = tokenAmountToNumber(displayAmount, sourceDisplay.decimals);
4151
- const receivedValue = eventDestination.amount !== void 0 ? tokenAmountToNumber(eventDestination.amount, targetDisplay.decimals) : void 0;
4152
- if (sentValue === void 0 || receivedValue === void 0 || sentValue <= receivedValue) {
4153
- return void 0;
4154
- }
4155
- const formatted = formatTokenAmount(sentValue - receivedValue, sourceSymbol);
4156
- if (formatted === void 0 || Number(formatted.replace(/,/g, "")) === 0) {
4157
- return void 0;
4158
- }
4159
- return formatted;
4160
- })();
4161
- const currentPhaseId = getCurrentPhaseId(state, phaseTimings);
4162
- const activePhaseStartedAt = currentPhaseId ? getPhaseStartTime(currentPhaseId, phaseTimings) : void 0;
4163
- const activePhaseElapsedMs = isProcessing && activePhaseStartedAt !== void 0 ? timelineNowMs - activePhaseStartedAt : 0;
4164
- const delayPhaseId = isProcessing && currentPhaseId && activePhaseElapsedMs >= SOFT_DELAY_MS[currentPhaseId] ? currentPhaseId : void 0;
4165
- void delayPhaseId;
4166
- void hasEscalatedDelay;
4167
- const sourceChainIcon = getChainIcon(displaySourceChain);
4168
- const targetChainIcon = getChainIcon(targetChain);
4169
- const sourceChainName = getChainName(displaySourceChain);
4170
- const targetChainName = getChainName(targetChain);
4171
- const timerText = formatTimer(elapsedSeconds);
4172
- const feeSponsored = uiConfig?.feeSponsored ?? false;
4173
- const feeTooltip = uiConfig?.feeTooltip ?? (feeSponsored ? "Network fees are sponsored for this deposit." : "Network fees apply.");
4174
- const stateTitle = isComplete ? `${flowCapitalized} successful` : isFailed ? `${flowCapitalized} failed` : "Processing...";
4175
- const handleRetry = onRetry ?? onNewDeposit;
4176
- const headerContent = isComplete ? /* @__PURE__ */ jsxs21("div", { className: "rs-body-header", children: [
4177
- /* @__PURE__ */ jsx24(SuccessBadge, {}),
4178
- /* @__PURE__ */ jsx24("div", { className: "rs-body-header-text", children: /* @__PURE__ */ jsx24("h2", { className: "rs-body-header-title", children: stateTitle }) })
4179
- ] }) : isFailed ? /* @__PURE__ */ jsxs21("div", { className: "rs-body-header", children: [
4180
- /* @__PURE__ */ jsx24(FailedBadge, {}),
4181
- /* @__PURE__ */ jsx24("div", { className: "rs-body-header-text", children: /* @__PURE__ */ jsx24("h2", { className: "rs-body-header-title", children: stateTitle }) })
4182
- ] }) : /* @__PURE__ */ jsx24(BodyHeader, { icon: /* @__PURE__ */ jsx24(WalletIcon, {}), title: stateTitle });
4183
- if (isComplete && isSwappedOrder) {
4184
- const effectivePaymentMethod = swappedContext?.method ?? swappedFiatContext?.paymentMethod ?? null;
4185
- const onrampMethod = effectivePaymentMethod ? formatPaymentMethod(effectivePaymentMethod) : null;
4186
- const onrampMethodIcon = swappedContext?.variant === "connect" && effectivePaymentMethod ? getExchangeLogoSrc(
4187
- onrampMethod ?? effectivePaymentMethod,
4188
- effectivePaymentMethod
4189
- ) : null;
4190
- const connectPaidAmount = swappedContext?.variant === "connect" ? `${formattedSentAmount} ${sourceSymbol}` : null;
4191
- const amountPaid = connectPaidAmount ?? (swappedFiatContext?.paidAmountUsd != null ? `$${swappedFiatContext.paidAmountUsd.toFixed(2)}` : null);
4192
- const depositedAmount = receiveDisplay;
4193
- const onrampFeeUsd = swappedFiatContext?.onrampFeeUsd ?? null;
4194
- const quoteFees = getMarketNetworkFees(quoteFeeBreakdown);
4195
- const fallbackNetworkFeeUsd = quoteFees === null && quotedFeeAmount !== void 0 && Number.isFinite(Number(quotedFeeAmount)) ? Number(quotedFeeAmount) : null;
4196
- const marketFeeUsd = quoteFees?.marketUsd ?? null;
4197
- const networkFeeUsd = quoteFees?.networkUsd ?? fallbackNetworkFeeUsd;
4198
- const sponsoredFeeTooltip = "This fee is sponsored for this deposit.";
4199
- const feesTooltip = feeSponsored ? "On-ramp fees are charged by the payment provider. Market and network fees are sponsored for this deposit." : "Fees include on-ramp, market, and network costs for this deposit.";
4200
- const feeRows = [];
4201
- if (onrampFeeUsd != null) {
4202
- feeRows.push({
4203
- label: "On-ramp fee",
4204
- value: formatUsdFee(onrampFeeUsd)
4205
- });
4206
- }
4207
- if (marketFeeUsd != null) {
4208
- feeRows.push({
4209
- label: "Market fee",
4210
- value: formatUsdFee(marketFeeUsd),
4211
- strike: feeSponsored,
4212
- tooltip: feeSponsored ? sponsoredFeeTooltip : void 0
4213
- });
4214
- }
4215
- if (networkFeeUsd != null) {
4216
- feeRows.push({
4217
- label: "Network fee",
4218
- value: formatUsdFee(networkFeeUsd),
4219
- strike: feeSponsored,
4220
- tooltip: feeSponsored ? sponsoredFeeTooltip : void 0
4221
- });
4222
- }
4223
- const chargeableQuoteFeeUsd = feeSponsored ? 0 : (marketFeeUsd ?? 0) + (networkFeeUsd ?? 0);
4224
- const feesTotal = feeRows.length > 0 ? formatUsdFee((onrampFeeUsd ?? 0) + chargeableQuoteFeeUsd) : null;
4225
- return /* @__PURE__ */ jsx24(
4226
- SwappedReceipt,
4227
- {
4228
- onrampMethod,
4229
- onrampMethodIcon,
4230
- amountPaid,
4231
- depositedAmount,
4232
- depositedSymbol: targetSymbol,
4233
- feesTotal,
4234
- feeRows,
4235
- feesTooltip,
4236
- newLabel: `New ${flowNoun}`,
4237
- onNewDeposit,
4238
- onClose
4239
- }
4240
- );
4241
- }
4242
- return /* @__PURE__ */ jsxs21("div", { className: "rs-screen", children: [
4243
- /* @__PURE__ */ jsxs21("div", { className: "rs-screen-body rs-screen-body--gap-32", children: [
4244
- headerContent,
4245
- /* @__PURE__ */ jsxs21("div", { className: "rs-review-details", children: [
4246
- /* @__PURE__ */ jsxs21("div", { className: "rs-review-detail-row", children: [
4247
- /* @__PURE__ */ jsx24("span", { children: "Source chain" }),
4248
- /* @__PURE__ */ jsxs21("span", { className: "rs-review-detail-value", children: [
4249
- /* @__PURE__ */ jsx24("span", { children: sourceChainName }),
4250
- sourceChainIcon && /* @__PURE__ */ jsx24("span", { className: "rs-review-detail-icon", children: /* @__PURE__ */ jsx24("img", { src: sourceChainIcon, alt: "" }) }),
4251
- sourceExplorerUrl && /* @__PURE__ */ jsx24(
4252
- "a",
4253
- {
4254
- href: sourceExplorerUrl,
4255
- target: "_blank",
4256
- rel: "noopener noreferrer",
4257
- className: "rs-review-detail-link",
4258
- "aria-label": "View source transaction",
4259
- children: /* @__PURE__ */ jsx24(ExternalLinkIcon, {})
4260
- }
4261
- )
4262
- ] })
4263
- ] }),
4264
- /* @__PURE__ */ jsxs21("div", { className: "rs-review-detail-row", children: [
4265
- /* @__PURE__ */ jsx24("span", { children: "Destination chain" }),
4266
- /* @__PURE__ */ jsxs21("span", { className: "rs-review-detail-value", children: [
4267
- /* @__PURE__ */ jsx24("span", { children: targetChainName }),
4268
- targetChainIcon && /* @__PURE__ */ jsx24("span", { className: "rs-review-detail-icon", children: /* @__PURE__ */ jsx24("img", { src: targetChainIcon, alt: "" }) }),
4269
- destExplorerUrl && /* @__PURE__ */ jsx24(
4270
- "a",
4271
- {
4272
- href: destExplorerUrl,
4273
- target: "_blank",
4274
- rel: "noopener noreferrer",
4275
- className: "rs-review-detail-link",
4276
- "aria-label": "View destination transaction",
4277
- children: /* @__PURE__ */ jsx24(ExternalLinkIcon, {})
4278
- }
4279
- )
4280
- ] })
4281
- ] }),
4282
- /* @__PURE__ */ jsxs21("div", { className: "rs-review-detail-row", children: [
4283
- /* @__PURE__ */ jsx24("span", { children: isProcessing ? "Time elapsed" : "Total time" }),
4284
- /* @__PURE__ */ jsx24("span", { className: "rs-review-detail-value", children: /* @__PURE__ */ jsx24(Ticker, { value: timerText }) })
4285
- ] }),
4286
- isSwappedOrder ? /* @__PURE__ */ jsxs21(Fragment5, { children: [
4287
- swappedFiatContext?.paidAmountUsd != null && /* @__PURE__ */ jsxs21("div", { className: "rs-review-detail-row", children: [
4288
- /* @__PURE__ */ jsx24("span", { children: "You pay" }),
4289
- /* @__PURE__ */ jsxs21("span", { className: "rs-review-detail-value", children: [
4290
- "$",
4291
- swappedFiatContext.paidAmountUsd.toFixed(2),
4292
- swappedFiatContext.paymentMethod && /* @__PURE__ */ jsxs21("span", { style: { color: "#71717b", marginLeft: 6 }, children: [
4293
- "via",
4294
- " ",
4295
- formatPaymentMethod(swappedFiatContext.paymentMethod)
4296
- ] })
4297
- ] })
4298
- ] }),
4299
- swappedFiatContext?.onrampFeeUsd != null && /* @__PURE__ */ jsxs21("div", { className: "rs-review-detail-row", children: [
4300
- /* @__PURE__ */ jsx24("span", { children: "On-ramp fee" }),
4301
- /* @__PURE__ */ jsxs21("span", { className: "rs-review-detail-value", children: [
4302
- "$",
4303
- swappedFiatContext.onrampFeeUsd.toFixed(2)
4304
- ] })
4305
- ] }),
4306
- formattedBridgingCost && /* @__PURE__ */ jsxs21("div", { className: "rs-review-detail-row", children: [
4307
- /* @__PURE__ */ jsx24("span", { children: "Bridging cost" }),
4308
- /* @__PURE__ */ jsxs21("span", { className: "rs-review-detail-value", children: [
4309
- /* @__PURE__ */ jsxs21("span", { children: [
4310
- formattedBridgingCost,
4311
- " ",
4312
- sourceSymbol
4313
- ] }),
4314
- /* @__PURE__ */ jsx24("span", { className: "rs-review-detail-icon", children: /* @__PURE__ */ jsx24(TokenIcon, { symbol: sourceSymbol }) })
4315
- ] })
4316
- ] })
4317
- ] }) : /* @__PURE__ */ jsxs21("div", { className: "rs-review-detail-row", children: [
4318
- /* @__PURE__ */ jsx24("span", { children: isProcessing ? "You send" : "You sent" }),
4319
- /* @__PURE__ */ jsxs21("span", { className: "rs-review-detail-value", children: [
4320
- /* @__PURE__ */ jsxs21("span", { children: [
4321
- formattedSentAmount,
4322
- " ",
4323
- sourceSymbol
4324
- ] }),
4325
- /* @__PURE__ */ jsx24("span", { className: "rs-review-detail-icon", children: /* @__PURE__ */ jsx24(TokenIcon, { symbol: sourceSymbol }) })
4326
- ] })
4327
- ] }),
4328
- /* @__PURE__ */ jsxs21("div", { className: "rs-review-detail-row", children: [
4329
- /* @__PURE__ */ jsx24("span", { children: isProcessing ? "Receive" : "Received" }),
4330
- /* @__PURE__ */ jsxs21("span", { className: "rs-review-detail-value", children: [
4331
- /* @__PURE__ */ jsx24("span", { children: receiveDisplay }),
4332
- /* @__PURE__ */ jsx24("span", { className: "rs-review-detail-icon", children: /* @__PURE__ */ jsx24(TokenIcon, { symbol: targetSymbol }) })
4333
- ] })
4334
- ] }),
4335
- isFailed && balanceAfterUsd !== void 0 && /* @__PURE__ */ jsxs21("div", { className: "rs-review-detail-row", children: [
4336
- /* @__PURE__ */ jsx24("span", { children: "Balance" }),
4337
- /* @__PURE__ */ jsxs21("span", { className: "rs-review-detail-value", children: [
4338
- "$",
4339
- balanceAfterUsd.toFixed(2)
4340
- ] })
4341
- ] }),
4342
- isSwappedOrder ? quotedFeeAmount !== void 0 && /* @__PURE__ */ jsxs21("div", { className: "rs-review-detail-row", children: [
4343
- /* @__PURE__ */ jsx24("span", { children: "Fees" }),
4344
- /* @__PURE__ */ jsxs21("span", { className: "rs-review-detail-value", children: [
4345
- /* @__PURE__ */ jsxs21(
4346
- "span",
4347
- {
4348
- style: feeSponsored ? { textDecoration: "line-through" } : void 0,
4349
- children: [
4350
- quotedFeeAmount,
4351
- " ",
4352
- quotedFeeSymbol ?? sourceSymbol
4353
- ]
4354
- }
4355
- ),
4356
- /* @__PURE__ */ jsx24(Tooltip, { content: feeTooltip, children: /* @__PURE__ */ jsx24(
4357
- "span",
4358
- {
4359
- className: "rs-review-detail-info",
4360
- "aria-label": "Fee info",
4361
- children: /* @__PURE__ */ jsx24(InfoIcon, {})
4362
- }
4363
- ) })
4364
- ] })
4365
- ] }) : (() => {
4366
- const feeValue = quotedFeeAmount ?? formattedBridgingCost;
4367
- if (feeValue === void 0) return null;
4368
- return /* @__PURE__ */ jsxs21("div", { className: "rs-review-detail-row", children: [
4369
- /* @__PURE__ */ jsx24("span", { children: "Fees" }),
4370
- /* @__PURE__ */ jsxs21("span", { className: "rs-review-detail-value", children: [
4371
- /* @__PURE__ */ jsxs21(
4372
- "span",
4373
- {
4374
- style: feeSponsored ? { textDecoration: "line-through" } : void 0,
4375
- children: [
4376
- feeValue,
4377
- " ",
4378
- quotedFeeSymbol ?? sourceSymbol
4379
- ]
4380
- }
4381
- ),
4382
- /* @__PURE__ */ jsx24(Tooltip, { content: feeTooltip, children: /* @__PURE__ */ jsx24(
4383
- "span",
4384
- {
4385
- className: "rs-review-detail-info",
4386
- "aria-label": "Fee info",
4387
- children: /* @__PURE__ */ jsx24(InfoIcon, {})
4388
- }
4389
- ) })
4390
- ] })
4391
- ] });
4392
- })()
4393
- ] }),
4394
- isFailed && failureMessage && /* @__PURE__ */ jsx24(Callout, { variant: "error", children: failureMessage }),
4395
- isProcessing && /* @__PURE__ */ jsx24(
4396
- Button,
4397
- {
4398
- fullWidth: true,
4399
- disabled: true,
4400
- loading: true,
4401
- loadingText: "Submitting transaction\u2026",
4402
- children: "Submitting transaction\u2026"
4403
- }
4404
- ),
4405
- isComplete && /* @__PURE__ */ jsxs21("div", { className: "rs-screen-button-row", children: [
4406
- onNewDeposit && /* @__PURE__ */ jsxs21(Button, { variant: "outline", onClick: onNewDeposit, fullWidth: true, children: [
4407
- "New ",
4408
- flowNoun
4409
- ] }),
4410
- onClose && /* @__PURE__ */ jsx24(Button, { onClick: onClose, fullWidth: true, children: "Done" })
4411
- ] }),
4412
- isFailed && /* @__PURE__ */ jsxs21("div", { className: "rs-screen-button-row", children: [
4413
- onClose && /* @__PURE__ */ jsx24(Button, { variant: "outline", onClick: onClose, fullWidth: true, children: "Cancel" }),
4414
- handleRetry && /* @__PURE__ */ jsx24(Button, { onClick: handleRetry, fullWidth: true, children: "Try again" })
4415
- ] })
4416
- ] }),
4417
- /* @__PURE__ */ jsx24(PoweredBy, {})
4418
- ] });
4419
- }
4420
-
4421
- // src/core/session-owner.ts
4422
- import { isAddress } from "viem";
4423
- import {
4424
- generatePrivateKey,
4425
- privateKeyToAccount
4426
- } from "viem/accounts";
4427
- var STORAGE_PREFIX = "rhinestone:session-owner";
4428
- function storageKey(eoaAddress) {
4429
- return `${STORAGE_PREFIX}:${eoaAddress.toLowerCase()}`;
4430
- }
4431
- function loadSessionOwnerFromStorage(eoaAddress) {
4432
- if (typeof window === "undefined") return null;
4433
- const raw = window.localStorage.getItem(storageKey(eoaAddress));
4434
- if (!raw) return null;
4435
- try {
4436
- const parsed = JSON.parse(raw);
4437
- if (!parsed.privateKey) return null;
4438
- const account = privateKeyToAccount(parsed.privateKey);
4439
- return {
4440
- privateKey: parsed.privateKey,
4441
- address: account.address
4442
- };
4443
- } catch {
4444
- return null;
4445
- }
4446
- }
4447
- function saveSessionOwnerToStorage(eoaAddress, privateKey, address) {
4448
- if (typeof window === "undefined") return;
4449
- if (!isAddress(address)) return;
4450
- const payload = {
4451
- privateKey,
4452
- address,
4453
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
4454
- };
4455
- window.localStorage.setItem(storageKey(eoaAddress), JSON.stringify(payload));
4456
- }
4457
- function createSessionOwnerKey() {
4458
- const privateKey = generatePrivateKey();
4459
- const account = privateKeyToAccount(privateKey);
4460
- return {
4461
- privateKey,
4462
- account,
4463
- address: account.address
4464
- };
4465
- }
4466
- function accountFromPrivateKey(privateKey) {
4467
- return privateKeyToAccount(privateKey);
4468
- }
4469
-
4470
- export {
4471
- Modal,
4472
- WalletIcon,
4473
- ExternalLinkIcon,
4474
- CheckIcon,
4475
- TransferCryptoIcon,
4476
- ChevronLeftIcon,
4477
- ChevronDownIcon,
4478
- CloseIcon,
4479
- HandCoinsIcon,
4480
- HistoryIcon,
4481
- InfoIcon,
4482
- CopyIcon,
4483
- ArrowUpRightIcon,
4484
- AlertTriangleIcon,
4485
- PercentIcon,
4486
- ClockIcon,
4487
- PlusCircleIcon,
4488
- CircleArrowOutUpLeftIcon,
4489
- BankIcon,
4490
- UnplugIcon,
4491
- Callout,
4492
- BodyHeader,
4493
- PoweredBy,
4494
- Spinner,
4495
- getExchangeLogo,
4496
- ConnectStep,
4497
- useLatestRef,
4498
- Button,
4499
- TokenIcon,
4500
- debugLog,
4501
- debugError,
4502
- getAssetId,
4503
- portfolioToAssets,
4504
- isNativeAsset,
4505
- buildSessionDetails,
4506
- createDepositService,
4507
- currencyFormatter,
4508
- tokenFormatter,
4509
- isUnsupportedChainSwitchError,
4510
- formatUserError,
4511
- Tooltip,
4512
- formatTokenAmount,
4513
- isDisplayStablecoinSymbol,
4514
- isRecognizedToken,
4515
- formatQuotedReceive,
4516
- formatReceiveEstimate,
4517
- getEventTxHash,
4518
- getEventSourceDetails,
4519
- isDepositEvent,
4520
- isFailedEvent,
4521
- txRefsMatch,
4522
- failureMessageForEvent,
4523
- fetchTokenPriceUsd,
4524
- useTokenPrices,
4525
- ProcessingStep,
4526
- rpcUrlFor,
4527
- RpcUrlsProvider,
4528
- useRpcUrls,
4529
- useStableRpcUrls,
4530
- getPublicClient,
4531
- getHyperEvmReadClient,
4532
- loadSessionOwnerFromStorage,
4533
- saveSessionOwnerToStorage,
4534
- createSessionOwnerKey,
4535
- accountFromPrivateKey,
4536
- applyTheme
4537
- };