@rhinestone/deposit-modal 0.10.0 → 0.11.1

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 (49) hide show
  1. package/dist/{DepositModalReown-MTWT6Y66.mjs → DepositModalReown-MO5QDLIT.mjs} +96 -26
  2. package/dist/{DepositModalReown-S3DSFXTX.cjs → DepositModalReown-YGB73NMW.cjs} +97 -27
  3. package/dist/caip-D8aRWdEY.d.cts +40 -0
  4. package/dist/caip-D8aRWdEY.d.ts +40 -0
  5. package/dist/{chunk-NF4NBRUP.cjs → chunk-4FTI3GTB.cjs} +1 -1
  6. package/dist/{chunk-A223BLVC.mjs → chunk-53IFZGSF.mjs} +177 -21
  7. package/dist/{chunk-VDGT6NZQ.mjs → chunk-5746YXKC.mjs} +14 -31
  8. package/dist/{chunk-7TV7GLJB.mjs → chunk-CWGUBFJL.mjs} +763 -169
  9. package/dist/{chunk-LR7MKHYV.mjs → chunk-EIWOVX53.mjs} +27 -25
  10. package/dist/{chunk-VTVOHNXM.cjs → chunk-FVUXJ3RP.cjs} +3 -3
  11. package/dist/{chunk-A42XAHIB.cjs → chunk-HUHBNYD3.cjs} +84 -101
  12. package/dist/{chunk-YEBXUUH3.cjs → chunk-JPRV36DT.cjs} +2 -2
  13. package/dist/{chunk-UMCDZJMG.cjs → chunk-LQGYPM5B.cjs} +96 -94
  14. package/dist/{chunk-ILT2PITN.mjs → chunk-MZ53PDIX.mjs} +1 -1
  15. package/dist/{chunk-5NJYW5FT.mjs → chunk-OWYPKCYD.mjs} +12 -9
  16. package/dist/{chunk-W4YAOJPG.cjs → chunk-SSQ27YFB.cjs} +625 -568
  17. package/dist/{chunk-H577RJN5.cjs → chunk-TENL4H64.cjs} +186 -30
  18. package/dist/{chunk-5OEWGJR4.mjs → chunk-URFSTNRS.mjs} +1 -1
  19. package/dist/{chunk-KW32UBUQ.mjs → chunk-V6T7LORJ.mjs} +1 -1
  20. package/dist/{chunk-MHIOMTMM.mjs → chunk-YELNYILK.mjs} +391 -334
  21. package/dist/{chunk-PUJHXHRA.cjs → chunk-ZQR36NCV.cjs} +845 -251
  22. package/dist/{chunk-DEF767BA.cjs → chunk-ZRIRCIQM.cjs} +66 -63
  23. package/dist/claim.cjs +6 -6
  24. package/dist/claim.d.cts +3 -2
  25. package/dist/claim.d.ts +3 -2
  26. package/dist/claim.mjs +5 -5
  27. package/dist/{caip-523Zrc3r.d.cts → constants-FuzG3h4m.d.cts} +1 -18
  28. package/dist/{caip-523Zrc3r.d.ts → constants-FuzG3h4m.d.ts} +1 -18
  29. package/dist/constants.cjs +5 -3
  30. package/dist/constants.d.cts +3 -2
  31. package/dist/constants.d.ts +3 -2
  32. package/dist/constants.mjs +4 -2
  33. package/dist/deposit.cjs +8 -8
  34. package/dist/deposit.d.cts +3 -2
  35. package/dist/deposit.d.ts +3 -2
  36. package/dist/deposit.mjs +7 -7
  37. package/dist/index.cjs +12 -10
  38. package/dist/index.d.cts +3 -2
  39. package/dist/index.d.ts +3 -2
  40. package/dist/index.mjs +11 -9
  41. package/dist/polymarket.cjs +5 -5
  42. package/dist/polymarket.mjs +2 -2
  43. package/dist/{types-C0SGf-21.d.cts → types-CsGa-HxD.d.cts} +10 -3
  44. package/dist/{types-C0SGf-21.d.ts → types-DdS8OySJ.d.ts} +10 -3
  45. package/dist/withdraw.cjs +6 -6
  46. package/dist/withdraw.d.cts +3 -2
  47. package/dist/withdraw.d.ts +3 -2
  48. package/dist/withdraw.mjs +5 -5
  49. package/package.json +1 -1
@@ -1,14 +1,23 @@
1
1
  import {
2
2
  SERVICE_HEADERS
3
- } from "./chunk-5OEWGJR4.mjs";
3
+ } from "./chunk-URFSTNRS.mjs";
4
4
  import {
5
+ CHAIN_BY_ID,
6
+ CHAIN_DISPLAY_ORDER,
5
7
  HYPERCORE_CHAIN_ID,
6
8
  HYPERCORE_MAINNET_CAIP2,
7
9
  HYPERCORE_SOURCE_TOKENS,
8
10
  ICON_CDN,
9
11
  NATIVE_TOKEN_ADDRESS,
12
+ SOLANA_MAINNET_CAIP2,
13
+ SOURCE_CHAINS,
10
14
  findTokenDecimals,
15
+ getBundledTargetTokens,
16
+ getChainName,
17
+ getExplorerTxUrl,
11
18
  getSolanaTokenByMint,
19
+ getSupportedChainIds,
20
+ getSupportedTargetTokens,
12
21
  getTokenAddress,
13
22
  getTokenDecimalsByAddress,
14
23
  getTokenSymbol,
@@ -16,8 +25,12 @@ import {
16
25
  isRegistryTokenOnChain,
17
26
  isSolanaCaip2,
18
27
  parseEvmChainId,
28
+ publishShortlistTokens,
29
+ setRuntimeChainMeta,
30
+ setRuntimeTokens,
31
+ toEvmCaip2,
19
32
  tokenIconUrl
20
- } from "./chunk-A223BLVC.mjs";
33
+ } from "./chunk-53IFZGSF.mjs";
21
34
 
22
35
  // src/components/ui/Modal.tsx
23
36
  import {
@@ -433,140 +446,6 @@ function PoweredBy() {
433
446
  }
434
447
  PoweredBy.displayName = "PoweredBy";
435
448
 
436
- // src/core/useLatestRef.ts
437
- import { useEffect as useEffect2, useRef as useRef2 } from "react";
438
- function useLatestRef(value) {
439
- const ref = useRef2(value);
440
- useEffect2(() => {
441
- ref.current = value;
442
- }, [value]);
443
- return ref;
444
- }
445
-
446
- // src/components/ui/Spinner.tsx
447
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
448
- function Spinner({ className }) {
449
- return /* @__PURE__ */ jsxs4(
450
- "svg",
451
- {
452
- className: `rs-spinner ${className || ""}`,
453
- fill: "none",
454
- viewBox: "0 0 20 21",
455
- children: [
456
- /* @__PURE__ */ jsx6(
457
- "path",
458
- {
459
- 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",
460
- fill: "currentColor",
461
- opacity: 0.3
462
- }
463
- ),
464
- /* @__PURE__ */ jsx6(
465
- "path",
466
- {
467
- 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",
468
- fill: "currentColor"
469
- }
470
- )
471
- ]
472
- }
473
- );
474
- }
475
-
476
- // src/components/ui/Button.tsx
477
- import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
478
- function Button({
479
- children,
480
- variant = "accent",
481
- size = "default",
482
- loading = false,
483
- loadingText,
484
- fullWidth = false,
485
- disabled,
486
- className = "",
487
- ...props
488
- }) {
489
- const classes = [
490
- "rs-button",
491
- `rs-button--${variant}`,
492
- `rs-button--size-${size}`,
493
- fullWidth ? "rs-button--full-width" : "",
494
- className
495
- ].filter(Boolean).join(" ");
496
- const showInlineLoadingText = loading && loadingText !== void 0;
497
- return /* @__PURE__ */ jsx7(
498
- "button",
499
- {
500
- className: classes,
501
- disabled: disabled || loading,
502
- "aria-busy": loading || void 0,
503
- ...props,
504
- children: showInlineLoadingText ? /* @__PURE__ */ jsxs5("span", { className: "rs-button__loading-row", children: [
505
- /* @__PURE__ */ jsx7(Spinner, { className: "rs-spinner--sm" }),
506
- /* @__PURE__ */ jsx7("span", { children: loadingText })
507
- ] }) : /* @__PURE__ */ jsxs5(Fragment2, { children: [
508
- /* @__PURE__ */ jsx7("span", { className: loading ? "rs-button__content--hidden" : "", children }),
509
- loading && /* @__PURE__ */ jsx7("span", { className: "rs-button__spinner", children: /* @__PURE__ */ jsx7(Spinner, { className: "rs-spinner--sm" }) })
510
- ] })
511
- }
512
- );
513
- }
514
- Button.displayName = "Button";
515
-
516
- // src/components/ui/Callout.tsx
517
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
518
- function CircleAlertIcon() {
519
- return /* @__PURE__ */ jsx8(
520
- "svg",
521
- {
522
- width: "16",
523
- height: "16",
524
- viewBox: "0 0 16 16",
525
- fill: "none",
526
- xmlns: "http://www.w3.org/2000/svg",
527
- "aria-hidden": "true",
528
- children: /* @__PURE__ */ jsx8(
529
- "path",
530
- {
531
- 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",
532
- stroke: "currentColor",
533
- strokeWidth: "1.33",
534
- strokeLinecap: "round",
535
- strokeLinejoin: "round"
536
- }
537
- )
538
- }
539
- );
540
- }
541
- function Callout({ variant = "error", children, role }) {
542
- return /* @__PURE__ */ jsxs6(
543
- "div",
544
- {
545
- className: `rs-callout rs-callout--${variant}`,
546
- role: role ?? (variant === "error" ? "alert" : "status"),
547
- children: [
548
- /* @__PURE__ */ jsx8("span", { className: "rs-callout-icon", children: variant === "error" ? /* @__PURE__ */ jsx8(CircleAlertIcon, {}) : /* @__PURE__ */ jsx8(AlertTriangleIcon, {}) }),
549
- /* @__PURE__ */ jsx8("span", { className: "rs-callout-text", children })
550
- ]
551
- }
552
- );
553
- }
554
- Callout.displayName = "Callout";
555
-
556
- // src/components/ui/TokenIcon.tsx
557
- import { jsx as jsx9 } from "react/jsx-runtime";
558
- function TokenIcon({ symbol, className, fallback }) {
559
- return /* @__PURE__ */ jsx9(
560
- CdnIcon,
561
- {
562
- src: tokenIconUrl(symbol),
563
- className: `rs-token-icon ${className ?? ""}`.trimEnd(),
564
- fallback
565
- }
566
- );
567
- }
568
- TokenIcon.displayName = "TokenIcon";
569
-
570
449
  // src/core/deposit-service.ts
571
450
  import { getAddress } from "viem";
572
451
 
@@ -623,6 +502,101 @@ function debugError(enabled, scope, message, error, data) {
623
502
  console.error(`[deposit-modal:${scope}] ${message}`, payload);
624
503
  }
625
504
 
505
+ // src/core/chain-catalog.ts
506
+ function parseToken(value) {
507
+ if (typeof value !== "object" || value === null) return null;
508
+ const { symbol, address, decimals } = value;
509
+ if (typeof symbol !== "string" || typeof address !== "string" || typeof decimals !== "number") {
510
+ return null;
511
+ }
512
+ return { symbol, address, decimals };
513
+ }
514
+ function parseExplorer(value) {
515
+ if (typeof value !== "object" || value === null) return null;
516
+ const { url, addressPath, txPath } = value;
517
+ if (typeof url !== "string" || typeof addressPath !== "string" || typeof txPath !== "string") {
518
+ return null;
519
+ }
520
+ return { url, addressPath, txPath };
521
+ }
522
+ function parseVmType(value) {
523
+ return value === "evm" || value === "svm" || value === "tvm" ? value : null;
524
+ }
525
+ function parseOptionalString(value) {
526
+ return typeof value === "string" && value.trim() !== "" ? value.trim() : null;
527
+ }
528
+ function parseChain(caip2, value) {
529
+ if (typeof value !== "object" || value === null) return null;
530
+ const raw = value;
531
+ const { name, testnet, deposit, destination, refund } = raw;
532
+ if (typeof name !== "string" || typeof testnet !== "boolean" || typeof deposit !== "boolean" || typeof destination !== "boolean" || typeof refund !== "boolean") {
533
+ return null;
534
+ }
535
+ const vmType = parseVmType(raw.vmType);
536
+ const nativeToken = parseToken(raw.nativeToken);
537
+ if (!vmType || !nativeToken) return null;
538
+ let supportedTokens;
539
+ if (raw.supportedTokens === "all") {
540
+ supportedTokens = "all";
541
+ } else if (Array.isArray(raw.supportedTokens)) {
542
+ const tokens = [];
543
+ for (const entry of raw.supportedTokens) {
544
+ const token = parseToken(entry);
545
+ if (!token) return null;
546
+ tokens.push(token);
547
+ }
548
+ supportedTokens = tokens;
549
+ } else {
550
+ return null;
551
+ }
552
+ return {
553
+ caip2,
554
+ // `parseEvmChainId` returns null for `solana:`/`tron:`/`hypercore:` keys,
555
+ // which is the intended answer — those chains have no numeric id, and the
556
+ // modal addresses them by their CAIP-2 string or a sentinel.
557
+ chainId: parseEvmChainId(caip2),
558
+ name,
559
+ testnet,
560
+ deposit,
561
+ destination,
562
+ refund,
563
+ vmType,
564
+ nativeToken,
565
+ explorer: parseExplorer(raw.explorer),
566
+ supportedTokens,
567
+ publicRpcUrl: parseOptionalString(raw.publicRpcUrl),
568
+ iconUrl: parseOptionalString(raw.iconUrl)
569
+ };
570
+ }
571
+ function parseChainCatalog(body) {
572
+ if (typeof body !== "object" || body === null || Array.isArray(body)) {
573
+ return null;
574
+ }
575
+ const all = [];
576
+ const byCaip2 = /* @__PURE__ */ new Map();
577
+ const byChainId = /* @__PURE__ */ new Map();
578
+ for (const [caip2, value] of Object.entries(body)) {
579
+ const chain = parseChain(caip2, value);
580
+ if (!chain) continue;
581
+ all.push(chain);
582
+ byCaip2.set(chain.caip2, chain);
583
+ if (chain.chainId !== null) byChainId.set(chain.chainId, chain);
584
+ }
585
+ if (all.length === 0) return null;
586
+ return { all, byCaip2, byChainId };
587
+ }
588
+ function catalogKeyForChain(chainId) {
589
+ if (chainId === "solana") return SOLANA_MAINNET_CAIP2;
590
+ if (chainId === "hypercore" || chainId === HYPERCORE_CHAIN_ID) {
591
+ return HYPERCORE_MAINNET_CAIP2;
592
+ }
593
+ return chainId;
594
+ }
595
+ function catalogExplorerTxUrl(chain, txHash) {
596
+ if (!chain?.explorer) return void 0;
597
+ return `${chain.explorer.url}${chain.explorer.txPath}${txHash}`;
598
+ }
599
+
626
600
  // src/core/deposit-asset-helpers.ts
627
601
  function getAssetId(asset) {
628
602
  return `${asset.chainId}:${asset.token.toLowerCase()}`;
@@ -869,6 +843,11 @@ var SwappedConnectFeeChangedError = class extends Error {
869
843
  function parseExchangeFeeBps(value) {
870
844
  return typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 1e4 ? value : void 0;
871
845
  }
846
+ var UNSUPPORTED_CONNECT_EXCHANGES = /* @__PURE__ */ new Set(["kraken", "htx"]);
847
+ var SUPPORTED_CONNECT_EXCHANGE_COUNT = 7;
848
+ function isSupportedConnectExchange(exchange) {
849
+ return !UNSUPPORTED_CONNECT_EXCHANGES.has(exchange.connection.toLowerCase());
850
+ }
872
851
  function resolveAppFeeBps(appFees, sourceChainCaip2, sourceToken) {
873
852
  const override = appFees?.tokens?.[sourceChainCaip2]?.[sourceToken.toLowerCase()];
874
853
  const bps = override ?? appFees?.feeBps ?? 0;
@@ -889,6 +868,7 @@ function createDepositService(baseUrl, options) {
889
868
  const PORTFOLIO_CACHE_TTL_MS = 3e4;
890
869
  const portfolioCache = /* @__PURE__ */ new Map();
891
870
  let topTokensPromise = null;
871
+ let chainsPromise = null;
892
872
  function parseTopTokens(value) {
893
873
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
894
874
  return null;
@@ -936,6 +916,32 @@ function createDepositService(baseUrl, options) {
936
916
  return null;
937
917
  }
938
918
  }
919
+ async function requestChains() {
920
+ try {
921
+ const response = await fetch(apiUrl("/chains"), {
922
+ method: "GET",
923
+ headers: SERVICE_HEADERS
924
+ });
925
+ if (!response.ok) {
926
+ debugLog(debug, scope, "getChains:unavailable", {
927
+ status: response.status
928
+ });
929
+ return null;
930
+ }
931
+ const catalog = parseChainCatalog(await response.json());
932
+ if (!catalog) {
933
+ debugLog(debug, scope, "getChains:malformed");
934
+ return null;
935
+ }
936
+ debugLog(debug, scope, "getChains:success", {
937
+ chains: catalog.all.length
938
+ });
939
+ return catalog;
940
+ } catch (error) {
941
+ debugError(debug, scope, "getChains:error", error);
942
+ return null;
943
+ }
944
+ }
939
945
  function cachedPortfolio(key, fetcher, forceRefresh = false) {
940
946
  const now = Date.now();
941
947
  const entry = portfolioCache.get(key);
@@ -1326,7 +1332,7 @@ function createDepositService(baseUrl, options) {
1326
1332
  return { deposits, nextCursor };
1327
1333
  },
1328
1334
  async checkLiquidity(params) {
1329
- if (params.destinationChainId === "solana") {
1335
+ if (isSolanaCaip2(params.destinationChainId) || params.destinationChainId === "solana") {
1330
1336
  const token = getSolanaTokenByMint(params.destinationToken);
1331
1337
  return {
1332
1338
  hasLiquidity: true,
@@ -1337,9 +1343,9 @@ function createDepositService(baseUrl, options) {
1337
1343
  };
1338
1344
  }
1339
1345
  const searchParams = new URLSearchParams({
1340
- sourceChainId: String(params.sourceChainId),
1346
+ sourceChainId: toEvmCaip2(params.sourceChainId),
1341
1347
  sourceToken: params.sourceToken,
1342
- destinationChainId: String(params.destinationChainId),
1348
+ destinationChainId: params.destinationChainId,
1343
1349
  destinationToken: params.destinationToken,
1344
1350
  amount: params.amount
1345
1351
  });
@@ -1593,7 +1599,7 @@ function createDepositService(baseUrl, options) {
1593
1599
  throw new Error("Swapped Connect exchanges: malformed response");
1594
1600
  }
1595
1601
  return {
1596
- exchanges,
1602
+ exchanges: exchanges.filter(isSupportedConnectExchange),
1597
1603
  fetchedAt: body.fetchedAt,
1598
1604
  expiresAt: body.expiresAt,
1599
1605
  stale: body.stale === true ? true : void 0,
@@ -1682,6 +1688,16 @@ function createDepositService(baseUrl, options) {
1682
1688
  }
1683
1689
  return topTokensPromise;
1684
1690
  },
1691
+ getChains() {
1692
+ if (!chainsPromise) {
1693
+ const attempt = requestChains().then((catalog) => {
1694
+ if (!catalog && chainsPromise === attempt) chainsPromise = null;
1695
+ return catalog;
1696
+ });
1697
+ chainsPromise = attempt;
1698
+ }
1699
+ return chainsPromise;
1700
+ },
1685
1701
  async getSetup() {
1686
1702
  const url = apiUrl("/setup");
1687
1703
  try {
@@ -1866,6 +1882,558 @@ function extractNumericString(data, key) {
1866
1882
  return Number.isFinite(parsed) ? parsed : null;
1867
1883
  }
1868
1884
 
1885
+ // src/core/rpc.ts
1886
+ import { createContext, useContext, useMemo } from "react";
1887
+ function rpcUrlFor(rpcUrls, chain) {
1888
+ const url = rpcUrls?.[chain]?.trim();
1889
+ return url ? url : void 0;
1890
+ }
1891
+ var RpcUrlsContext = createContext(void 0);
1892
+ var RpcUrlsProvider = RpcUrlsContext.Provider;
1893
+ function useRpcUrls() {
1894
+ return useContext(RpcUrlsContext);
1895
+ }
1896
+ function rpcUrlsKey(rpcUrls) {
1897
+ if (!rpcUrls) return "";
1898
+ return Object.entries(rpcUrls).map(([chain, url]) => [chain, url?.trim() ?? ""]).filter(([, url]) => url !== "").map(([chain, url]) => `${chain}=${url}`).sort().join("|");
1899
+ }
1900
+ function useStableRpcUrls(rpcUrls) {
1901
+ const key = rpcUrlsKey(rpcUrls);
1902
+ return useMemo(() => rpcUrls, [key]);
1903
+ }
1904
+
1905
+ // src/core/chain-catalog-context.tsx
1906
+ import {
1907
+ createContext as createContext2,
1908
+ useContext as useContext2,
1909
+ useEffect as useEffect2,
1910
+ useMemo as useMemo2,
1911
+ useState as useState2
1912
+ } from "react";
1913
+
1914
+ // src/core/public-client.ts
1915
+ import { createPublicClient, http } from "viem";
1916
+ var clientCache = /* @__PURE__ */ new Map();
1917
+ var runtimeChainById = /* @__PURE__ */ new Map();
1918
+ function setRuntimeChains(chains) {
1919
+ for (const chain of chains) {
1920
+ const known = runtimeChainById.get(chain.id);
1921
+ if (known === chain) continue;
1922
+ runtimeChainById.set(chain.id, chain);
1923
+ for (const key of clientCache.keys()) {
1924
+ if (key.startsWith(`${chain.id}|`)) clientCache.delete(key);
1925
+ }
1926
+ }
1927
+ }
1928
+ function getPublicClient(chainId, rpcUrls) {
1929
+ const url = rpcUrlFor(rpcUrls, chainId);
1930
+ const cacheKey = `${chainId}|${url ?? ""}`;
1931
+ let client = clientCache.get(cacheKey);
1932
+ if (!client) {
1933
+ const chain = CHAIN_BY_ID[chainId] ?? runtimeChainById.get(chainId);
1934
+ client = createPublicClient({
1935
+ chain,
1936
+ transport: http(url)
1937
+ });
1938
+ clientCache.set(cacheKey, client);
1939
+ }
1940
+ return client;
1941
+ }
1942
+
1943
+ // src/core/chain-objects.ts
1944
+ import { defineChain } from "viem";
1945
+ var viemChainsById = null;
1946
+ var viemChainsPromise = null;
1947
+ async function loadViemChains() {
1948
+ if (viemChainsById) return viemChainsById;
1949
+ if (!viemChainsPromise) {
1950
+ viemChainsPromise = import("viem/chains").then((module) => {
1951
+ const map = /* @__PURE__ */ new Map();
1952
+ for (const value of Object.values(module)) {
1953
+ if (value && typeof value === "object" && typeof value.id === "number" && value.rpcUrls?.default?.http?.length) {
1954
+ const chain = value;
1955
+ const existing = map.get(chain.id);
1956
+ if (existing) existing.push(chain);
1957
+ else map.set(chain.id, [chain]);
1958
+ }
1959
+ }
1960
+ viemChainsById = map;
1961
+ return map;
1962
+ });
1963
+ }
1964
+ return viemChainsPromise;
1965
+ }
1966
+ function pickViemChain(candidates, chain) {
1967
+ if (!candidates?.length) return void 0;
1968
+ if (candidates.length === 1) return candidates[0];
1969
+ const sameNetworkClass = candidates.filter(
1970
+ (candidate) => Boolean(candidate.testnet) === chain.testnet
1971
+ );
1972
+ if (sameNetworkClass.length === 1) return sameNetworkClass[0];
1973
+ const pool = sameNetworkClass.length > 0 ? sameNetworkClass : candidates;
1974
+ const normalized = chain.name.toLowerCase().replace(/\s+/g, "");
1975
+ const byName = pool.find(
1976
+ (candidate) => candidate.name.toLowerCase().replace(/\s+/g, "") === normalized
1977
+ );
1978
+ if (byName) return byName;
1979
+ return void 0;
1980
+ }
1981
+ function resolveRpcUrls(chain, override, viemChains) {
1982
+ const urls = [];
1983
+ if (override?.trim()) urls.push(override.trim());
1984
+ if (chain.publicRpcUrl) urls.push(chain.publicRpcUrl);
1985
+ if (chain.chainId !== null && chain.vmType === "evm") {
1986
+ const http2 = pickViemChain(viemChains?.get(chain.chainId), chain)?.rpcUrls?.default?.http;
1987
+ if (http2) urls.push(...http2);
1988
+ }
1989
+ return [...new Set(urls)];
1990
+ }
1991
+ function toViemChain(chain, override, viemChains) {
1992
+ if (chain.vmType !== "evm" || chain.chainId === null) return null;
1993
+ const rpcUrls = resolveRpcUrls(chain, override, viemChains);
1994
+ if (rpcUrls.length === 0) return null;
1995
+ const bundled = pickViemChain(viemChains?.get(chain.chainId), chain);
1996
+ if (bundled) {
1997
+ if (rpcUrls[0] === bundled.rpcUrls.default.http[0]) return bundled;
1998
+ return defineChain({
1999
+ ...bundled,
2000
+ rpcUrls: { ...bundled.rpcUrls, default: { http: rpcUrls } }
2001
+ });
2002
+ }
2003
+ return defineChain({
2004
+ id: chain.chainId,
2005
+ name: chain.name,
2006
+ nativeCurrency: {
2007
+ name: chain.nativeToken.symbol,
2008
+ symbol: chain.nativeToken.symbol,
2009
+ decimals: chain.nativeToken.decimals
2010
+ },
2011
+ rpcUrls: { default: { http: rpcUrls } },
2012
+ blockExplorers: chain.explorer ? {
2013
+ default: {
2014
+ name: "Explorer",
2015
+ url: chain.explorer.url
2016
+ }
2017
+ } : void 0,
2018
+ testnet: chain.testnet
2019
+ });
2020
+ }
2021
+ function toViemChains(catalog, overrides, viemChains) {
2022
+ const chains = [];
2023
+ for (const entry of catalog.all) {
2024
+ const chain = toViemChain(
2025
+ entry,
2026
+ entry.chainId === null ? void 0 : overrides?.[entry.chainId],
2027
+ viemChains
2028
+ );
2029
+ if (chain) chains.push(chain);
2030
+ }
2031
+ return chains;
2032
+ }
2033
+ function needsViemChains(catalog, overrides) {
2034
+ return catalog.all.some(
2035
+ (chain) => chain.vmType === "evm" && chain.chainId !== null && !chain.publicRpcUrl && !overrides?.[chain.chainId]?.trim()
2036
+ );
2037
+ }
2038
+
2039
+ // src/core/chain-catalog-context.tsx
2040
+ import { jsx as jsx6 } from "react/jsx-runtime";
2041
+ var EMPTY = {
2042
+ catalog: null,
2043
+ viemChains: null,
2044
+ isLoading: true,
2045
+ shortlist: null,
2046
+ clientCapableChainIds: null
2047
+ };
2048
+ var ChainCatalogContext = createContext2(EMPTY);
2049
+ var resolvedChainsByKey = /* @__PURE__ */ new Map();
2050
+ function overridesKey(overrides) {
2051
+ return Object.entries(overrides ?? {}).map(([id, override]) => `${id}=${override ?? ""}`).sort().join("|");
2052
+ }
2053
+ function runtimeChainsKey(backendUrl, overrides) {
2054
+ return [backendUrl.replace(/\/$/, ""), overridesKey(overrides)].join("#");
2055
+ }
2056
+ var catalogByBackend = /* @__PURE__ */ new Map();
2057
+ function primeChainCatalog(backendUrl, debug = false) {
2058
+ const key = backendUrl.replace(/\/$/, "");
2059
+ let promise = catalogByBackend.get(key);
2060
+ if (!promise) {
2061
+ promise = createDepositService(key, {
2062
+ debug,
2063
+ debugScope: "service:chains"
2064
+ }).getChains();
2065
+ catalogByBackend.set(key, promise);
2066
+ promise.then((catalog) => {
2067
+ if (!catalog) catalogByBackend.delete(key);
2068
+ });
2069
+ }
2070
+ return promise;
2071
+ }
2072
+ function peekRuntimeChains(backendUrl, overrides) {
2073
+ return resolvedChainsByKey.get(runtimeChainsKey(backendUrl, overrides)) ?? null;
2074
+ }
2075
+ function publishCatalogTokens(catalog) {
2076
+ setRuntimeTokens(
2077
+ catalog.all.flatMap(
2078
+ (chain) => chain.chainId === null || !Array.isArray(chain.supportedTokens) ? [] : chain.supportedTokens.map((token) => ({
2079
+ chainId: chain.chainId,
2080
+ symbol: token.symbol,
2081
+ address: token.address,
2082
+ decimals: token.decimals
2083
+ }))
2084
+ )
2085
+ );
2086
+ }
2087
+ function publishRuntimeChainMeta(catalog) {
2088
+ setRuntimeChainMeta(
2089
+ catalog.all.flatMap((chain) => {
2090
+ const ids = [];
2091
+ if (chain.chainId !== null) ids.push(chain.chainId);
2092
+ if (chain.caip2 === HYPERCORE_MAINNET_CAIP2) ids.push(HYPERCORE_CHAIN_ID);
2093
+ return ids.map((chainId) => ({
2094
+ chainId,
2095
+ name: chain.name,
2096
+ iconUrl: chain.iconUrl ?? void 0,
2097
+ nativeSymbol: chain.nativeToken.symbol
2098
+ }));
2099
+ })
2100
+ );
2101
+ }
2102
+ var runtimeChainsByBackend = /* @__PURE__ */ new Map();
2103
+ function primeRuntimeChains(backendUrl, overrides, debug = false) {
2104
+ const url = backendUrl.replace(/\/$/, "");
2105
+ const key = runtimeChainsKey(url, overrides);
2106
+ let promise = runtimeChainsByBackend.get(key);
2107
+ if (!promise) {
2108
+ promise = primeChainCatalog(url, debug).then(async (catalog) => {
2109
+ if (!catalog) return [];
2110
+ publishRuntimeChainMeta(catalog);
2111
+ publishCatalogTokens(catalog);
2112
+ const viemChains = needsViemChains(catalog, overrides) ? await loadViemChains() : null;
2113
+ const chains = toViemChains(catalog, overrides, viemChains);
2114
+ if (chains.length > 0) {
2115
+ setRuntimeChains(chains);
2116
+ resolvedChainsByKey.set(key, chains);
2117
+ }
2118
+ return chains;
2119
+ }).catch(() => []);
2120
+ runtimeChainsByBackend.set(key, promise);
2121
+ promise.then((chains) => {
2122
+ if (chains.length === 0) runtimeChainsByBackend.delete(key);
2123
+ });
2124
+ }
2125
+ return promise;
2126
+ }
2127
+ function useChainCatalog() {
2128
+ return useContext2(ChainCatalogContext);
2129
+ }
2130
+ function useCatalogChain(chainId) {
2131
+ const { catalog } = useChainCatalog();
2132
+ if (!catalog || chainId == null) return void 0;
2133
+ return typeof chainId === "number" ? catalog.byChainId.get(chainId) : catalog.byCaip2.get(chainId);
2134
+ }
2135
+ function useDepositChainIds() {
2136
+ const { catalog } = useChainCatalog();
2137
+ return useMemo2(() => {
2138
+ if (!catalog) return getSupportedChainIds();
2139
+ const ids = catalog.all.filter(
2140
+ (c) => c.deposit && c.vmType === "evm" && c.chainId !== null && // `/chains` enumerates testnets; the bundled list never did, and a
2141
+ // production picker offering Sepolia next to Ethereum is a way to
2142
+ // lose funds. Reading the set at runtime must not quietly widen it
2143
+ // to a different KIND of chain.
2144
+ !c.testnet
2145
+ ).map((c) => c.chainId);
2146
+ const rank = (id) => {
2147
+ const i = CHAIN_DISPLAY_ORDER.indexOf(id);
2148
+ return i === -1 ? CHAIN_DISPLAY_ORDER.length : i;
2149
+ };
2150
+ return ids.map((id, i) => ({ id, i })).sort((a, b) => rank(a.id) - rank(b.id) || a.i - b.i).map(({ id }) => id);
2151
+ }, [catalog]);
2152
+ }
2153
+ function useDestinationChains() {
2154
+ const { catalog } = useChainCatalog();
2155
+ return useMemo2(() => {
2156
+ if (!catalog) {
2157
+ return SOURCE_CHAINS.filter(
2158
+ (chain) => getSupportedTargetTokens(chain.id).length > 0
2159
+ ).map((chain) => ({ id: chain.id, name: chain.name }));
2160
+ }
2161
+ const rank = (id) => {
2162
+ const i = CHAIN_DISPLAY_ORDER.indexOf(id);
2163
+ return i === -1 ? CHAIN_DISPLAY_ORDER.length : i;
2164
+ };
2165
+ return catalog.all.filter(
2166
+ (c) => c.destination && c.vmType === "evm" && c.chainId !== null && !c.testnet
2167
+ ).map((c, i) => ({ id: c.chainId, name: c.name, i })).sort((a, b) => rank(a.id) - rank(b.id) || a.i - b.i).map(({ id, name }) => ({ id, name }));
2168
+ }, [catalog]);
2169
+ }
2170
+ function useTargetTokens() {
2171
+ const { catalog, shortlist } = useChainCatalog();
2172
+ return useMemo2(() => {
2173
+ return (chainId) => {
2174
+ const bundled = getBundledTargetTokens(chainId);
2175
+ if (bundled.length > 0) return bundled;
2176
+ const fromShortlist = shortlist?.[String(chainId)];
2177
+ if (fromShortlist?.length) {
2178
+ return fromShortlist.map((token) => ({
2179
+ symbol: token.symbol,
2180
+ address: token.address,
2181
+ decimals: token.decimals
2182
+ }));
2183
+ }
2184
+ const entry = catalog?.byChainId.get(chainId);
2185
+ return Array.isArray(entry?.supportedTokens) ? entry.supportedTokens.map((token) => ({
2186
+ symbol: token.symbol,
2187
+ address: token.address,
2188
+ decimals: token.decimals
2189
+ })) : [];
2190
+ };
2191
+ }, [catalog, shortlist]);
2192
+ }
2193
+ function useIsDepositChain() {
2194
+ const ids = useDepositChainIds();
2195
+ const { clientCapableChainIds } = useChainCatalog();
2196
+ return useMemo2(() => {
2197
+ const set = new Set(ids);
2198
+ return (chainId) => set.has(chainId) && (clientCapableChainIds === null || clientCapableChainIds.has(chainId));
2199
+ }, [ids, clientCapableChainIds]);
2200
+ }
2201
+ function useChainName() {
2202
+ const { catalog } = useChainCatalog();
2203
+ return useMemo2(() => {
2204
+ return (chainId) => {
2205
+ if (!catalog) return getChainName(chainId);
2206
+ const key = catalogKeyForChain(chainId);
2207
+ const entry = typeof key === "number" ? catalog.byChainId.get(key) : catalog.byCaip2.get(key);
2208
+ return entry?.name ?? getChainName(chainId);
2209
+ };
2210
+ }, [catalog]);
2211
+ }
2212
+ function useExplorerTxUrl() {
2213
+ const { catalog } = useChainCatalog();
2214
+ return useMemo2(() => {
2215
+ return (chainId, txHash) => {
2216
+ if (chainId === "hypercore") return getExplorerTxUrl(chainId, txHash);
2217
+ const key = catalog ? catalogKeyForChain(chainId) : void 0;
2218
+ const entry = key === void 0 ? void 0 : typeof key === "number" ? catalog?.byChainId.get(key) : catalog?.byCaip2.get(key);
2219
+ return catalogExplorerTxUrl(entry, txHash) ?? getExplorerTxUrl(chainId, txHash);
2220
+ };
2221
+ }, [catalog]);
2222
+ }
2223
+ function ChainCatalogProvider({
2224
+ service,
2225
+ rpcUrls,
2226
+ children
2227
+ }) {
2228
+ const [catalog, setCatalog] = useState2(null);
2229
+ const [viemChains, setViemChains] = useState2(null);
2230
+ const [isLoading, setIsLoading] = useState2(true);
2231
+ useEffect2(() => {
2232
+ let active = true;
2233
+ setIsLoading(true);
2234
+ service.getChains().then((next) => {
2235
+ if (!active) return;
2236
+ setCatalog(next);
2237
+ setIsLoading(false);
2238
+ });
2239
+ return () => {
2240
+ active = false;
2241
+ };
2242
+ }, [service]);
2243
+ const overrides = useMemo2(() => {
2244
+ if (!rpcUrls) return void 0;
2245
+ const out = {};
2246
+ for (const [key, url] of Object.entries(rpcUrls)) {
2247
+ const id = Number(key);
2248
+ if (Number.isFinite(id) && typeof url === "string") out[id] = url;
2249
+ }
2250
+ return out;
2251
+ }, [rpcUrls]);
2252
+ const overrideKey = overridesKey(overrides);
2253
+ useEffect2(() => {
2254
+ if (!catalog || viemChains) return;
2255
+ if (!needsViemChains(catalog, overrides)) return;
2256
+ let active = true;
2257
+ loadViemChains().then((chains) => {
2258
+ if (active) setViemChains(chains);
2259
+ });
2260
+ return () => {
2261
+ active = false;
2262
+ };
2263
+ }, [catalog, viemChains, overrideKey]);
2264
+ useEffect2(() => {
2265
+ if (!catalog) return;
2266
+ publishRuntimeChainMeta(catalog);
2267
+ publishCatalogTokens(catalog);
2268
+ const chains = toViemChains(catalog, overrides, viemChains);
2269
+ if (chains.length > 0) setRuntimeChains(chains);
2270
+ }, [catalog, viemChains, overrides]);
2271
+ const [shortlist, setShortlist] = useState2(null);
2272
+ useEffect2(() => {
2273
+ let active = true;
2274
+ setShortlist(null);
2275
+ service.getTopTokens().then((tokens) => {
2276
+ if (!active || !tokens) return;
2277
+ publishShortlistTokens(tokens);
2278
+ setShortlist(tokens);
2279
+ });
2280
+ return () => {
2281
+ active = false;
2282
+ };
2283
+ }, [service]);
2284
+ const clientCapableChainIds = useMemo2(() => {
2285
+ if (!catalog) return null;
2286
+ return new Set(
2287
+ toViemChains(catalog, overrides, viemChains).map((c) => c.id)
2288
+ );
2289
+ }, [catalog, viemChains, overrideKey]);
2290
+ const value = useMemo2(
2291
+ () => ({
2292
+ catalog,
2293
+ viemChains,
2294
+ isLoading,
2295
+ shortlist,
2296
+ clientCapableChainIds
2297
+ }),
2298
+ [catalog, viemChains, isLoading, shortlist, clientCapableChainIds]
2299
+ );
2300
+ return /* @__PURE__ */ jsx6(ChainCatalogContext.Provider, { value, children });
2301
+ }
2302
+
2303
+ // src/core/useLatestRef.ts
2304
+ import { useEffect as useEffect3, useRef as useRef2 } from "react";
2305
+ function useLatestRef(value) {
2306
+ const ref = useRef2(value);
2307
+ useEffect3(() => {
2308
+ ref.current = value;
2309
+ }, [value]);
2310
+ return ref;
2311
+ }
2312
+
2313
+ // src/components/ui/Spinner.tsx
2314
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
2315
+ function Spinner({ className }) {
2316
+ return /* @__PURE__ */ jsxs4(
2317
+ "svg",
2318
+ {
2319
+ className: `rs-spinner ${className || ""}`,
2320
+ fill: "none",
2321
+ viewBox: "0 0 20 21",
2322
+ children: [
2323
+ /* @__PURE__ */ jsx7(
2324
+ "path",
2325
+ {
2326
+ 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",
2327
+ fill: "currentColor",
2328
+ opacity: 0.3
2329
+ }
2330
+ ),
2331
+ /* @__PURE__ */ jsx7(
2332
+ "path",
2333
+ {
2334
+ 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",
2335
+ fill: "currentColor"
2336
+ }
2337
+ )
2338
+ ]
2339
+ }
2340
+ );
2341
+ }
2342
+
2343
+ // src/components/ui/Button.tsx
2344
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
2345
+ function Button({
2346
+ children,
2347
+ variant = "accent",
2348
+ size = "default",
2349
+ loading = false,
2350
+ loadingText,
2351
+ fullWidth = false,
2352
+ disabled,
2353
+ className = "",
2354
+ ...props
2355
+ }) {
2356
+ const classes = [
2357
+ "rs-button",
2358
+ `rs-button--${variant}`,
2359
+ `rs-button--size-${size}`,
2360
+ fullWidth ? "rs-button--full-width" : "",
2361
+ className
2362
+ ].filter(Boolean).join(" ");
2363
+ const showInlineLoadingText = loading && loadingText !== void 0;
2364
+ return /* @__PURE__ */ jsx8(
2365
+ "button",
2366
+ {
2367
+ className: classes,
2368
+ disabled: disabled || loading,
2369
+ "aria-busy": loading || void 0,
2370
+ ...props,
2371
+ children: showInlineLoadingText ? /* @__PURE__ */ jsxs5("span", { className: "rs-button__loading-row", children: [
2372
+ /* @__PURE__ */ jsx8(Spinner, { className: "rs-spinner--sm" }),
2373
+ /* @__PURE__ */ jsx8("span", { children: loadingText })
2374
+ ] }) : /* @__PURE__ */ jsxs5(Fragment2, { children: [
2375
+ /* @__PURE__ */ jsx8("span", { className: loading ? "rs-button__content--hidden" : "", children }),
2376
+ loading && /* @__PURE__ */ jsx8("span", { className: "rs-button__spinner", children: /* @__PURE__ */ jsx8(Spinner, { className: "rs-spinner--sm" }) })
2377
+ ] })
2378
+ }
2379
+ );
2380
+ }
2381
+ Button.displayName = "Button";
2382
+
2383
+ // src/components/ui/Callout.tsx
2384
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
2385
+ function CircleAlertIcon() {
2386
+ return /* @__PURE__ */ jsx9(
2387
+ "svg",
2388
+ {
2389
+ width: "16",
2390
+ height: "16",
2391
+ viewBox: "0 0 16 16",
2392
+ fill: "none",
2393
+ xmlns: "http://www.w3.org/2000/svg",
2394
+ "aria-hidden": "true",
2395
+ children: /* @__PURE__ */ jsx9(
2396
+ "path",
2397
+ {
2398
+ 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",
2399
+ stroke: "currentColor",
2400
+ strokeWidth: "1.33",
2401
+ strokeLinecap: "round",
2402
+ strokeLinejoin: "round"
2403
+ }
2404
+ )
2405
+ }
2406
+ );
2407
+ }
2408
+ function Callout({ variant = "error", children, role }) {
2409
+ return /* @__PURE__ */ jsxs6(
2410
+ "div",
2411
+ {
2412
+ className: `rs-callout rs-callout--${variant}`,
2413
+ role: role ?? (variant === "error" ? "alert" : "status"),
2414
+ children: [
2415
+ /* @__PURE__ */ jsx9("span", { className: "rs-callout-icon", children: variant === "error" ? /* @__PURE__ */ jsx9(CircleAlertIcon, {}) : /* @__PURE__ */ jsx9(AlertTriangleIcon, {}) }),
2416
+ /* @__PURE__ */ jsx9("span", { className: "rs-callout-text", children })
2417
+ ]
2418
+ }
2419
+ );
2420
+ }
2421
+ Callout.displayName = "Callout";
2422
+
2423
+ // src/components/ui/TokenIcon.tsx
2424
+ import { jsx as jsx10 } from "react/jsx-runtime";
2425
+ function TokenIcon({ symbol, className, fallback }) {
2426
+ return /* @__PURE__ */ jsx10(
2427
+ CdnIcon,
2428
+ {
2429
+ src: tokenIconUrl(symbol),
2430
+ className: `rs-token-icon ${className ?? ""}`.trimEnd(),
2431
+ fallback
2432
+ }
2433
+ );
2434
+ }
2435
+ TokenIcon.displayName = "TokenIcon";
2436
+
1869
2437
  // src/core/formatters.ts
1870
2438
  var currencyFormatter = new Intl.NumberFormat("en-US", {
1871
2439
  style: "currency",
@@ -1882,6 +2450,22 @@ function isUnsupportedChainSwitchError(error) {
1882
2450
  const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
1883
2451
  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");
1884
2452
  }
2453
+ var OPAQUE_REVERT_REASONS = [
2454
+ "unexpected error",
2455
+ "internal error",
2456
+ "unknown error",
2457
+ "internal json-rpc error"
2458
+ ];
2459
+ var DETAIL_SECTION_HEADINGS = [
2460
+ "Request Arguments:",
2461
+ "Raw Call Arguments:",
2462
+ "Request body:",
2463
+ "Contract Call:",
2464
+ "Docs:",
2465
+ "Details:",
2466
+ "Version:",
2467
+ "URL:"
2468
+ ];
1885
2469
  function formatUserError(raw) {
1886
2470
  const lower = raw.toLowerCase();
1887
2471
  if (lower.includes("user rejected") || lower.includes("user denied")) {
@@ -1893,6 +2477,22 @@ function formatUserError(raw) {
1893
2477
  if (lower.includes("nonce too low") || lower.includes("nonce too high")) {
1894
2478
  return "Transaction conflict \u2014 please try again";
1895
2479
  }
2480
+ const revertMarker = "reverted with the following reason:";
2481
+ const revertIdx = lower.indexOf(revertMarker);
2482
+ const revertReason = revertIdx === -1 ? null : raw.slice(revertIdx + revertMarker.length).split(/\n[^\S\n]*\n/)[0].split("\n").map((line) => line.trim()).find(
2483
+ (line) => line.length > 0 && !DETAIL_SECTION_HEADINGS.some(
2484
+ (heading) => line.startsWith(heading)
2485
+ )
2486
+ ) ?? "";
2487
+ if (revertReason !== null) {
2488
+ const reasonLower = revertReason.toLowerCase();
2489
+ if (reasonLower.includes("execution reverted")) {
2490
+ return "Transaction would fail on-chain";
2491
+ }
2492
+ if (revertReason === "" || revertReason === "0x" || OPAQUE_REVERT_REASONS.some((opaque) => reasonLower.includes(opaque))) {
2493
+ return "Your wallet couldn't send the transaction \u2014 please try again";
2494
+ }
2495
+ }
1896
2496
  if (lower.includes("execution reverted")) {
1897
2497
  return "Transaction would fail on-chain";
1898
2498
  }
@@ -1911,7 +2511,7 @@ function formatUserError(raw) {
1911
2511
  if (lower.includes("rate limit") || lower.includes("429")) {
1912
2512
  return "Rate limited \u2014 please try again shortly";
1913
2513
  }
1914
- let cleaned = raw;
2514
+ let cleaned = revertReason || raw;
1915
2515
  const stripMarkers = [
1916
2516
  "\n\nRequest Arguments:",
1917
2517
  "\nRaw Call Arguments:",
@@ -2076,26 +2676,6 @@ function formatReceiveEstimate(params) {
2076
2676
  return sameSymbol ? `${formatted} ${params.targetSymbol}` : `~${formatted} ${params.targetSymbol}`;
2077
2677
  }
2078
2678
 
2079
- // src/core/rpc.ts
2080
- import { createContext, useContext, useMemo } from "react";
2081
- function rpcUrlFor(rpcUrls, chain) {
2082
- const url = rpcUrls?.[chain]?.trim();
2083
- return url ? url : void 0;
2084
- }
2085
- var RpcUrlsContext = createContext(void 0);
2086
- var RpcUrlsProvider = RpcUrlsContext.Provider;
2087
- function useRpcUrls() {
2088
- return useContext(RpcUrlsContext);
2089
- }
2090
- function rpcUrlsKey(rpcUrls) {
2091
- if (!rpcUrls) return "";
2092
- return Object.entries(rpcUrls).map(([chain, url]) => [chain, url?.trim() ?? ""]).filter(([, url]) => url !== "").map(([chain, url]) => `${chain}=${url}`).sort().join("|");
2093
- }
2094
- function useStableRpcUrls(rpcUrls) {
2095
- const key = rpcUrlsKey(rpcUrls);
2096
- return useMemo(() => rpcUrls, [key]);
2097
- }
2098
-
2099
2679
  // src/core/theme.ts
2100
2680
  var RADIUS_SCALE = {
2101
2681
  none: { sm: "0", md: "0", lg: "0" },
@@ -2296,10 +2876,7 @@ export {
2296
2876
  CdnIcon,
2297
2877
  PoweredBy,
2298
2878
  Spinner,
2299
- useLatestRef,
2300
- Button,
2301
- Callout,
2302
- TokenIcon,
2879
+ catalogKeyForChain,
2303
2880
  debugLog,
2304
2881
  debugError,
2305
2882
  getAssetId,
@@ -2310,8 +2887,29 @@ export {
2310
2887
  quoteFeeRow,
2311
2888
  quoteFeeGroups,
2312
2889
  SwappedConnectFeeChangedError,
2890
+ SUPPORTED_CONNECT_EXCHANGE_COUNT,
2313
2891
  resolveAppFeeBps,
2314
2892
  createDepositService,
2893
+ rpcUrlFor,
2894
+ RpcUrlsProvider,
2895
+ useRpcUrls,
2896
+ useStableRpcUrls,
2897
+ getPublicClient,
2898
+ peekRuntimeChains,
2899
+ primeRuntimeChains,
2900
+ useChainCatalog,
2901
+ useCatalogChain,
2902
+ useDepositChainIds,
2903
+ useDestinationChains,
2904
+ useTargetTokens,
2905
+ useIsDepositChain,
2906
+ useChainName,
2907
+ useExplorerTxUrl,
2908
+ ChainCatalogProvider,
2909
+ useLatestRef,
2910
+ Button,
2911
+ Callout,
2912
+ TokenIcon,
2315
2913
  currencyFormatter,
2316
2914
  tokenFormatter,
2317
2915
  isUnsupportedChainSwitchError,
@@ -2325,10 +2923,6 @@ export {
2325
2923
  estimateReceiveAmount,
2326
2924
  formatQuotedReceive,
2327
2925
  formatReceiveEstimate,
2328
- rpcUrlFor,
2329
- RpcUrlsProvider,
2330
- useRpcUrls,
2331
- useStableRpcUrls,
2332
2926
  applyTheme,
2333
2927
  checkBackendUrl
2334
2928
  };