@pollar/react 0.11.1-rc.3 → 0.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1035,7 +1035,7 @@ var PollarModalFooter = () => {
1035
1035
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
1036
1036
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-footer-version", children: [
1037
1037
  "v",
1038
- "0.11.1-rc.3"
1038
+ "0.11.2"
1039
1039
  ] })
1040
1040
  ] })
1041
1041
  ] });
@@ -1101,6 +1101,36 @@ function ModalStatusBanner({ message, status, onCancel, onRetry }) {
1101
1101
  status === "ERROR" && onRetry && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-status-cancel", onClick: onRetry, children: "Retry" })
1102
1102
  ] });
1103
1103
  }
1104
+ function cropAddress(address) {
1105
+ if (address.length <= 16) return address;
1106
+ return `${address.slice(0, 8)}...${address.slice(-8)}`;
1107
+ }
1108
+ function useStickyData(data) {
1109
+ const lastRef = react.useRef(null);
1110
+ if (data !== null) lastRef.current = data;
1111
+ return data ?? lastRef.current;
1112
+ }
1113
+ function BusyOverlay({ label = "Loading\u2026" }) {
1114
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-busy-overlay", "aria-busy": "true", "aria-live": "polite", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-busy-overlay-inner", children: [
1115
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner" }),
1116
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: label })
1117
+ ] }) });
1118
+ }
1119
+ function Toggle({ checked, onChange, disabled = false, busy = false, label }) {
1120
+ return /* @__PURE__ */ jsxRuntime.jsx(
1121
+ "button",
1122
+ {
1123
+ type: "button",
1124
+ role: "switch",
1125
+ "aria-checked": checked,
1126
+ "aria-label": label,
1127
+ className: `pollar-switch${checked ? " pollar-switch-on" : ""}${busy ? " pollar-switch-busy" : ""}`,
1128
+ onClick: onChange,
1129
+ disabled: disabled || busy,
1130
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-switch-knob", children: busy && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm pollar-spinner-current" }) })
1131
+ }
1132
+ );
1133
+ }
1104
1134
  var PERIOD_LABEL = {
1105
1135
  DAY: "every 24h",
1106
1136
  DAY_CALENDAR: "daily",
@@ -1328,9 +1358,66 @@ function DistributionRulesModal({ onClose }) {
1328
1358
  }
1329
1359
  ) });
1330
1360
  }
1331
- function cropAddress(address) {
1332
- if (address.length <= 16) return address;
1333
- return `${address.slice(0, 8)}...${address.slice(-8)}`;
1361
+ var CHAIN_LABEL = {
1362
+ STELLAR: "Stellar",
1363
+ POLYGON: "Polygon",
1364
+ SOLANA: "Solana"
1365
+ };
1366
+ function resolveChain(chain) {
1367
+ return chain ?? "STELLAR";
1368
+ }
1369
+ function chainsOf(wallets, order) {
1370
+ const held = [];
1371
+ for (const w of wallets) {
1372
+ const chain = resolveChain(w.chain);
1373
+ if (!held.includes(chain)) held.push(chain);
1374
+ }
1375
+ if (!order || order.length === 0) return held;
1376
+ return order.filter((c) => held.includes(c));
1377
+ }
1378
+ function addressForChain(wallets, chain) {
1379
+ if (!chain) return "";
1380
+ return wallets.find((w) => resolveChain(w.chain) === chain)?.address ?? "";
1381
+ }
1382
+ function ChainSelect({ label = "Network", value, options, onChange, disabled = false }) {
1383
+ if (options.length < 2) return null;
1384
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field pollar-chain-field", children: [
1385
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: label }),
1386
+ /* @__PURE__ */ jsxRuntime.jsxs(
1387
+ "select",
1388
+ {
1389
+ className: "pollar-input pollar-send-select",
1390
+ value: value ?? "",
1391
+ disabled,
1392
+ onChange: (e) => onChange(e.target.value),
1393
+ children: [
1394
+ value === null && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, hidden: true }),
1395
+ options.map((chain) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: chain, children: CHAIN_LABEL[chain] ?? chain }, chain))
1396
+ ]
1397
+ }
1398
+ )
1399
+ ] });
1400
+ }
1401
+
1402
+ // src/useChains.ts
1403
+ function useChains() {
1404
+ const { wallets, appConfig, configStatus } = usePollar();
1405
+ const configured = appConfig?.application?.chains;
1406
+ const ready = configStatus === "ready";
1407
+ return react.useMemo(() => {
1408
+ if (!ready) {
1409
+ const fallback = chainsOf(wallets);
1410
+ return {
1411
+ chains: [],
1412
+ primaryChain: null,
1413
+ primaryAddress: addressForChain(wallets, fallback[0] ?? null),
1414
+ ready: false
1415
+ };
1416
+ }
1417
+ const chains = chainsOf(wallets, configured);
1418
+ const primaryChain = chains[0] ?? null;
1419
+ return { chains, primaryChain, primaryAddress: addressForChain(wallets, primaryChain), ready: true };
1420
+ }, [wallets, configured, ready]);
1334
1421
  }
1335
1422
  function cssVarsFor(theme, accentColor) {
1336
1423
  const isDark = theme === "dark";
@@ -1355,14 +1442,18 @@ function cssVarsFor(theme, accentColor) {
1355
1442
  function assetKey(record) {
1356
1443
  return record.code + (record.issuer ?? "");
1357
1444
  }
1445
+ function rowKey(record) {
1446
+ return (record.chain ?? "") + assetKey(record);
1447
+ }
1358
1448
  function AssetItem({
1359
1449
  record,
1360
1450
  busy,
1361
1451
  disabled,
1362
1452
  onToggle
1363
1453
  }) {
1364
- const established = record.trustlineEstablished;
1454
+ const established = record.trustlineEstablished ?? false;
1365
1455
  const isNative = record.type === "native";
1456
+ const isStellar = resolveChain(record.chain) === "STELLAR";
1366
1457
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-asset-item", children: [
1367
1458
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-asset-info", children: [
1368
1459
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-asset-code-row", children: [
@@ -1370,17 +1461,22 @@ function AssetItem({
1370
1461
  record.enabledInApp && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-asset-tag", children: "App" })
1371
1462
  ] }),
1372
1463
  record.name && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-asset-name", children: record.name }),
1373
- !isNative && record.enabledInApp && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-asset-sponsor", children: record.sponsored ? "Reserve sponsored by the app" : "You pay the reserve (~0.5 XLM)" })
1464
+ record.issuer && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-issuer", children: [
1465
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-issuer-addr", children: cropAddress(record.issuer) }),
1466
+ /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: record.issuer, label: "Copy issuer address", className: "pollar-copy-btn-sm" })
1467
+ ] }),
1468
+ isStellar && !isNative && record.enabledInApp && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-asset-sponsor", children: record.sponsored ? "Reserve sponsored by the app" : "You pay the reserve (~0.5 XLM)" })
1374
1469
  ] }),
1375
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-asset-actions", children: [
1376
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `pollar-asset-trustline${established ? " pollar-established" : ""}`, children: established ? "Trustline active" : "Needs trustline" }),
1377
- !isNative && /* @__PURE__ */ jsxRuntime.jsx(
1378
- "button",
1470
+ isStellar && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-asset-actions", children: [
1471
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-asset-trustline-label", children: "Trustline" }),
1472
+ /* @__PURE__ */ jsxRuntime.jsx(
1473
+ Toggle,
1379
1474
  {
1380
- className: `pollar-asset-btn${established ? " pollar-danger" : ""}`,
1381
- onClick: () => onToggle(record),
1382
- disabled: busy || disabled,
1383
- children: busy ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm pollar-spinner-current" }) : established ? "Disable" : "Enable"
1475
+ checked: established,
1476
+ busy,
1477
+ disabled: isNative || disabled,
1478
+ onChange: () => onToggle(record),
1479
+ label: `${established ? "Disable" : "Enable"} ${record.code} trustline`
1384
1480
  }
1385
1481
  )
1386
1482
  ] })
@@ -1391,6 +1487,9 @@ function EnabledAssetsModalTemplate({
1391
1487
  accentColor,
1392
1488
  enabledAssets,
1393
1489
  walletAddress,
1490
+ chains,
1491
+ selectedChain,
1492
+ onSelectChain,
1394
1493
  busyKey,
1395
1494
  actionError,
1396
1495
  onRefresh,
@@ -1400,8 +1499,10 @@ function EnabledAssetsModalTemplate({
1400
1499
  }) {
1401
1500
  const cssVars = cssVarsFor(theme, accentColor);
1402
1501
  const isLoading = enabledAssets.step === "loading";
1403
- const data = enabledAssets.step === "loaded" ? enabledAssets.data : null;
1502
+ const data = useStickyData(enabledAssets.step === "loaded" ? enabledAssets.data : null);
1404
1503
  const busy = busyKey !== null;
1504
+ const assets = (data?.assets ?? []).filter((a) => resolveChain(a.chain) === selectedChain);
1505
+ const isStellarSelected = selectedChain === "STELLAR";
1405
1506
  return /* @__PURE__ */ jsxRuntime.jsxs(
1406
1507
  "div",
1407
1508
  {
@@ -1410,8 +1511,9 @@ function EnabledAssetsModalTemplate({
1410
1511
  style: cssVars,
1411
1512
  onClick: (e) => e.stopPropagation(),
1412
1513
  children: [
1514
+ isLoading && data && /* @__PURE__ */ jsxRuntime.jsx(BusyOverlay, { label: "Refreshing assets\u2026" }),
1413
1515
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
1414
- /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Trustlines" }),
1516
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Assets" }),
1415
1517
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header-actions", children: [
1416
1518
  /* @__PURE__ */ jsxRuntime.jsx(
1417
1519
  "button",
@@ -1448,8 +1550,12 @@ function EnabledAssetsModalTemplate({
1448
1550
  /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
1449
1551
  ] })
1450
1552
  ] }),
1451
- walletAddress && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-asset-address", children: cropAddress(walletAddress) }),
1452
- isLoading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-loading-block", children: [
1553
+ /* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain, disabled: isLoading || busy }),
1554
+ walletAddress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-address-row", children: [
1555
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-address", children: cropAddress(walletAddress) }),
1556
+ /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: walletAddress, label: "Copy wallet address" })
1557
+ ] }),
1558
+ isLoading && !data && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-loading-block", children: [
1453
1559
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner" }),
1454
1560
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading\u2026" })
1455
1561
  ] }),
@@ -1460,8 +1566,8 @@ function EnabledAssetsModalTemplate({
1460
1566
  data.network,
1461
1567
  "."
1462
1568
  ] }),
1463
- data && data.assets.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No trustlines found." }),
1464
- data && data.assets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-asset-list", children: data.assets.map((a) => /* @__PURE__ */ jsxRuntime.jsx(
1569
+ data && assets.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No assets found on this network." }),
1570
+ data && assets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-asset-list", children: assets.map((a) => /* @__PURE__ */ jsxRuntime.jsx(
1465
1571
  AssetItem,
1466
1572
  {
1467
1573
  record: a,
@@ -1469,9 +1575,9 @@ function EnabledAssetsModalTemplate({
1469
1575
  disabled: busy && busyKey !== assetKey(a),
1470
1576
  onToggle: onToggleTrustline
1471
1577
  },
1472
- assetKey(a)
1578
+ rowKey(a)
1473
1579
  )) }),
1474
- /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-asset-add-custom", onClick: onAddCustom, disabled: busy, children: "+ Add custom trustline" }),
1580
+ isStellarSelected && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-asset-add-custom", onClick: onAddCustom, disabled: busy, children: "+ Add custom trustline" }),
1475
1581
  /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
1476
1582
  ]
1477
1583
  }
@@ -1585,9 +1691,14 @@ function assetKey2(record) {
1585
1691
  return record.code + (record.issuer ?? "");
1586
1692
  }
1587
1693
  function EnabledAssetsModal({ onClose }) {
1588
- const { enabledAssets, refreshAssets, setTrustline, wallet, styles } = usePollar();
1589
- const walletAddress = wallet?.address ?? "";
1694
+ const { enabledAssets, refreshAssets, setTrustline, wallets, styles } = usePollar();
1590
1695
  const { theme = "light", accentColor = "#005DB4" } = styles;
1696
+ const { chains } = useChains();
1697
+ const [selectedChain, setSelectedChain] = react.useState(null);
1698
+ react.useEffect(() => {
1699
+ if (selectedChain === null && chains.length > 0) setSelectedChain(chains[0]);
1700
+ }, [chains, selectedChain]);
1701
+ const walletAddress = addressForChain(wallets, selectedChain);
1591
1702
  const [view, setView] = react.useState("list");
1592
1703
  const [busyKey, setBusyKey] = react.useState(null);
1593
1704
  const [actionError, setActionError] = react.useState(null);
@@ -1616,7 +1727,7 @@ function EnabledAssetsModal({ onClose }) {
1616
1727
  void runAction(
1617
1728
  assetKey2(record),
1618
1729
  { code: record.code, issuer: record.issuer ?? "" },
1619
- { ...removing ? { limit: "0" } : {}, sponsored: record.sponsored ?? false }
1730
+ { ...removing ? { limit: "0" } : {} }
1620
1731
  );
1621
1732
  },
1622
1733
  [runAction]
@@ -1626,7 +1737,7 @@ function EnabledAssetsModal({ onClose }) {
1626
1737
  const ok = await runAction(
1627
1738
  "custom",
1628
1739
  { code: input.code, issuer: input.issuer },
1629
- { ...input.limit ? { limit: input.limit } : {}, sponsored: false }
1740
+ { ...input.limit ? { limit: input.limit } : {}, skipSponsorship: true }
1630
1741
  );
1631
1742
  if (ok) setView("list");
1632
1743
  },
@@ -1639,6 +1750,9 @@ function EnabledAssetsModal({ onClose }) {
1639
1750
  accentColor,
1640
1751
  enabledAssets,
1641
1752
  walletAddress,
1753
+ chains,
1754
+ selectedChain,
1755
+ onSelectChain: setSelectedChain,
1642
1756
  busyKey,
1643
1757
  actionError,
1644
1758
  onRefresh: () => refreshAssets(),
@@ -3357,10 +3471,18 @@ var QRCode = react.forwardRef(function QRCode2({ bgColor = "#FFFFFF", fgColor =
3357
3471
  }
3358
3472
  );
3359
3473
  });
3474
+ var CHAIN_NAME = {
3475
+ STELLAR: "Stellar",
3476
+ POLYGON: "Polygon",
3477
+ SOLANA: "Solana"
3478
+ };
3360
3479
  function ReceiveModalTemplate({
3361
3480
  theme,
3362
3481
  accentColor,
3363
3482
  walletAddress,
3483
+ chains,
3484
+ selectedChain,
3485
+ onSelectChain,
3364
3486
  copied,
3365
3487
  onCopy,
3366
3488
  onClose
@@ -3383,6 +3505,7 @@ function ReceiveModalTemplate({
3383
3505
  "--pollar-input-border-radius": "0.5rem",
3384
3506
  "--pollar-card-border-radius": "10px"
3385
3507
  };
3508
+ const chainName = selectedChain ? CHAIN_NAME[selectedChain] ?? selectedChain : "wallet";
3386
3509
  return /* @__PURE__ */ jsxRuntime.jsxs(
3387
3510
  "div",
3388
3511
  {
@@ -3395,9 +3518,16 @@ function ReceiveModalTemplate({
3395
3518
  /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Receive" }),
3396
3519
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) }) })
3397
3520
  ] }),
3521
+ /* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain }),
3398
3522
  walletAddress ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3399
3523
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-receive-qr", children: /* @__PURE__ */ jsxRuntime.jsx(QRCode, { value: walletAddress, size: 180, fgColor: isDark ? "#ffffff" : "#111827", bgColor: "transparent" }) }),
3400
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-receive-instructions", children: "Share your Stellar address to receive any asset. Only send Stellar assets to this address." }),
3524
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-receive-instructions", children: [
3525
+ "Share your ",
3526
+ chainName,
3527
+ " address to receive any asset. Only send ",
3528
+ chainName,
3529
+ " assets to this address. Funds sent from another network are lost."
3530
+ ] }),
3401
3531
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-receive-address-row", children: [
3402
3532
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-receive-address", children: walletAddress }),
3403
3533
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-receive-copy-btn", onClick: onCopy, "aria-label": "Copy address", children: copied ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -3438,11 +3568,16 @@ function ReceiveModalTemplate({
3438
3568
  );
3439
3569
  }
3440
3570
  function ReceiveModal({ onClose }) {
3441
- const { wallet, styles } = usePollar();
3442
- const walletAddress = wallet?.address ?? "";
3571
+ const { wallets, styles } = usePollar();
3443
3572
  const { theme = "light", accentColor = "#005DB4" } = styles;
3444
3573
  const [copied, setCopied] = react.useState(false);
3445
3574
  const copyTimerRef = react.useRef(null);
3575
+ const { chains } = useChains();
3576
+ const [selectedChain, setSelectedChain] = react.useState(null);
3577
+ react.useEffect(() => {
3578
+ if (selectedChain === null && chains.length > 0) setSelectedChain(chains[0]);
3579
+ }, [chains, selectedChain]);
3580
+ const walletAddress = addressForChain(wallets, selectedChain);
3446
3581
  react.useEffect(
3447
3582
  () => () => {
3448
3583
  if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
@@ -3466,6 +3601,12 @@ function ReceiveModal({ onClose }) {
3466
3601
  theme,
3467
3602
  accentColor,
3468
3603
  walletAddress,
3604
+ chains,
3605
+ selectedChain,
3606
+ onSelectChain: (chain) => {
3607
+ setCopied(false);
3608
+ setSelectedChain(chain);
3609
+ },
3469
3610
  copied,
3470
3611
  onCopy: handleCopy,
3471
3612
  onClose
@@ -3711,6 +3852,7 @@ function TxStatusView({
3711
3852
  ] });
3712
3853
  }
3713
3854
  function formatBalance(balance) {
3855
+ if (balance === null) return "\u2014";
3714
3856
  const n = parseFloat(balance);
3715
3857
  return isNaN(n) ? balance : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
3716
3858
  }
@@ -3724,6 +3866,11 @@ function SendModalTemplate({
3724
3866
  txTitle,
3725
3867
  assets,
3726
3868
  selectedAsset,
3869
+ chains,
3870
+ selectedChain,
3871
+ walletAddress,
3872
+ canSendOnChain,
3873
+ onSelectChain,
3727
3874
  amount,
3728
3875
  destination,
3729
3876
  formError,
@@ -3767,7 +3914,7 @@ function SendModalTemplate({
3767
3914
  "--pollar-card-border-radius": "10px"
3768
3915
  };
3769
3916
  const selectedKey = selectedAsset ? assetKey3(selectedAsset) : "";
3770
- const canSubmit = !!selectedAsset && !!amount && !!destination.trim() && !isLoadingBalance;
3917
+ const canSubmit = canSendOnChain && !!selectedAsset && !!amount && !!destination.trim() && !isLoadingBalance;
3771
3918
  const title = step === "form" ? "Send" : txTitle;
3772
3919
  return /* @__PURE__ */ jsxRuntime.jsxs(
3773
3920
  "div",
@@ -3819,6 +3966,12 @@ function SendModalTemplate({
3819
3966
  ] })
3820
3967
  ] }),
3821
3968
  step === "form" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3969
+ /* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain, disabled: isLoadingBalance }),
3970
+ walletAddress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-address-row", children: [
3971
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-address", children: cropAddress(walletAddress) }),
3972
+ /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: walletAddress, label: "Copy wallet address" })
3973
+ ] }),
3974
+ !canSendOnChain && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "Sending is not available on this network yet." }),
3822
3975
  /* @__PURE__ */ jsxRuntime.jsx(
3823
3976
  AssetSelect,
3824
3977
  {
@@ -3829,7 +3982,9 @@ function SendModalTemplate({
3829
3982
  options: assets.map((a) => ({
3830
3983
  key: assetKey3(a),
3831
3984
  code: a.code,
3832
- available: a.available,
3985
+ // Unreadable (null) drops the "— X available" suffix instead of
3986
+ // claiming a zero balance.
3987
+ available: a.available ?? void 0,
3833
3988
  enabledInApp: a.enabledInApp
3834
3989
  })),
3835
3990
  onChange: (key) => {
@@ -3908,9 +4063,11 @@ function SendModal({ onClose }) {
3908
4063
  walletBalance,
3909
4064
  refreshWalletBalance,
3910
4065
  buildTx,
4066
+ sendPayment,
3911
4067
  signAndSubmitTx,
3912
4068
  tx: transaction,
3913
4069
  wallet,
4070
+ wallets,
3914
4071
  network,
3915
4072
  styles
3916
4073
  } = usePollar();
@@ -3924,6 +4081,14 @@ function SendModal({ onClose }) {
3924
4081
  const [copied, setCopied] = react.useState(false);
3925
4082
  const [formError, setFormError] = react.useState("");
3926
4083
  const copyTimerRef = react.useRef(null);
4084
+ const { chains } = useChains();
4085
+ const [selectedChain, setSelectedChain] = react.useState(null);
4086
+ react.useEffect(() => {
4087
+ if (selectedChain === null && chains.length > 0) setSelectedChain(chains[0]);
4088
+ }, [chains, selectedChain]);
4089
+ const walletAddress = addressForChain(wallets, selectedChain);
4090
+ const canSendOnChain = selectedChain === "STELLAR" || selectedChain === "SOLANA";
4091
+ const isBaseUnitChain = selectedChain === "SOLANA";
3927
4092
  react.useEffect(() => {
3928
4093
  void refreshWalletBalance();
3929
4094
  }, [refreshWalletBalance]);
@@ -3934,18 +4099,24 @@ function SendModal({ onClose }) {
3934
4099
  []
3935
4100
  );
3936
4101
  const balanceData = walletBalance.step === "loaded" ? walletBalance.data : null;
3937
- const allAssets = (balanceData?.balances ?? []).filter((b) => b.chain === void 0 || b.chain === "STELLAR");
4102
+ const allAssets = (balanceData?.balances ?? []).filter((b) => resolveChain(b.chain) === selectedChain);
3938
4103
  const sortedAssets = [
3939
4104
  ...allAssets.filter((b) => b.enabledInApp),
3940
- ...allAssets.filter((b) => !b.enabledInApp && (b.type === "native" || parseFloat(b.balance) > 0))
4105
+ // An unreadable balance (null) is not a positive one, so it stays out.
4106
+ ...allAssets.filter((b) => !b.enabledInApp && (b.type === "native" || parseFloat(b.balance ?? "0") > 0))
3941
4107
  ];
3942
4108
  react.useEffect(() => {
4109
+ const stranded = selectedAsset !== null && resolveChain(selectedAsset.chain) !== selectedChain;
4110
+ if (stranded) {
4111
+ setSelectedAsset(sortedAssets[0] ?? null);
4112
+ return;
4113
+ }
3943
4114
  if (!selectedAsset && sortedAssets.length > 0) setSelectedAsset(sortedAssets[0]);
3944
- }, [sortedAssets, selectedAsset]);
4115
+ }, [sortedAssets, selectedAsset, selectedChain]);
3945
4116
  const hash = transaction.step === "success" ? transaction.hash : null;
3946
4117
  const buildData = "buildData" in transaction ? transaction.buildData : null;
3947
4118
  const explorerNetwork = buildData?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : buildData ? "public" : network === "testnet" ? "testnet" : "public";
3948
- const explorerUrl = hash ? `https://stellar.expert/explorer/${explorerNetwork}/tx/${hash}` : null;
4119
+ const explorerUrl = !hash ? null : selectedChain === "SOLANA" ? `https://explorer.solana.com/tx/${hash}${explorerNetwork === "testnet" ? "?cluster=devnet" : ""}` : `https://stellar.expert/explorer/${explorerNetwork}/tx/${hash}`;
3949
4120
  const IN_FLIGHT_STEPS3 = [
3950
4121
  "building",
3951
4122
  "signing",
@@ -3959,6 +4130,10 @@ function SendModal({ onClose }) {
3959
4130
  const txTitle = isInProgress ? "Sending\u2026" : transaction.step === "success" ? "Sent!" : transaction.step === "error" ? "Send failed" : "Confirm Send";
3960
4131
  async function handleSubmit() {
3961
4132
  setFormError("");
4133
+ if (!canSendOnChain) {
4134
+ setFormError("Sending is not available on this network yet.");
4135
+ return;
4136
+ }
3962
4137
  if (!selectedAsset) {
3963
4138
  setFormError("Select an asset");
3964
4139
  return;
@@ -3968,7 +4143,7 @@ function SendModal({ onClose }) {
3968
4143
  setFormError("Enter a valid amount");
3969
4144
  return;
3970
4145
  }
3971
- if (parsed > parseFloat(selectedAsset.available)) {
4146
+ if (parsed > parseFloat(selectedAsset.available ?? "0")) {
3972
4147
  setFormError("Insufficient balance");
3973
4148
  return;
3974
4149
  }
@@ -3976,7 +4151,32 @@ function SendModal({ onClose }) {
3976
4151
  setFormError("Enter a destination address");
3977
4152
  return;
3978
4153
  }
4154
+ const isNativeAsset = selectedAsset.type === "native";
4155
+ if (isBaseUnitChain && !isNativeAsset && (!selectedAsset.issuer || selectedAsset.decimals === void 0)) {
4156
+ setFormError("This token is missing its mint or decimals and cannot be sent.");
4157
+ return;
4158
+ }
4159
+ let sendAmount = amount;
4160
+ if (isBaseUnitChain) {
4161
+ try {
4162
+ sendAmount = core.toBaseUnits(amount, selectedAsset.decimals ?? 9);
4163
+ } catch (e) {
4164
+ setFormError(e instanceof Error ? e.message : "Invalid amount");
4165
+ return;
4166
+ }
4167
+ }
3979
4168
  setStep("tx");
4169
+ if (selectedChain === "SOLANA") {
4170
+ await sendPayment({
4171
+ chain: "SOLANA",
4172
+ destination: destination.trim(),
4173
+ amount: sendAmount,
4174
+ // Native SOL carries no mint; an SPL token's mint rides in `issuer`,
4175
+ // which the guard above proved is present.
4176
+ ...isNativeAsset ? {} : { mint: selectedAsset.issuer }
4177
+ });
4178
+ return;
4179
+ }
3980
4180
  await buildTx("payment", { destination: destination.trim(), amount, asset: assetParam(selectedAsset) });
3981
4181
  }
3982
4182
  function handleSignAndSend() {
@@ -4014,6 +4214,11 @@ function SendModal({ onClose }) {
4014
4214
  txTitle,
4015
4215
  assets: sortedAssets,
4016
4216
  selectedAsset,
4217
+ chains,
4218
+ selectedChain,
4219
+ walletAddress,
4220
+ canSendOnChain,
4221
+ onSelectChain: setSelectedChain,
4017
4222
  amount,
4018
4223
  destination,
4019
4224
  formError,
@@ -4440,11 +4645,19 @@ function SwapModal({ onClose }) {
4440
4645
  const assetRecords = enabledAssets.step === "loaded" ? enabledAssets.data.assets : [];
4441
4646
  const isLoadingData = walletBalance.step === "loading" || enabledAssets.step === "loading";
4442
4647
  const sellOptions = balances.filter(
4443
- (b) => b.type != null && (b.type === "native" || !b.trustlineRemoved)
4444
- ).map((b) => ({ ref: toRef(b), code: b.code, issuer: b.issuer, available: b.available, enabledInApp: b.enabledInApp }));
4648
+ (b) => (b.chain === void 0 || b.chain === "STELLAR") && (b.type === "native" || (b.type === "credit_alphanum4" || b.type === "credit_alphanum12") && !b.trustlineRemoved)
4649
+ ).map((b) => ({
4650
+ ref: toRef(b),
4651
+ code: b.code,
4652
+ issuer: b.issuer,
4653
+ available: b.available ?? void 0,
4654
+ enabledInApp: b.enabledInApp
4655
+ }));
4445
4656
  const buyKeyOfSell = selectedSell ? `${selectedSell.code}:${selectedSell.issuer ?? "native"}` : "";
4446
4657
  const optKey = (o) => `${o.code}:${o.issuer ?? "native"}`;
4447
- const enabledBuy = assetRecords.map((a) => ({
4658
+ const enabledBuy = assetRecords.filter(
4659
+ (a) => (a.chain === void 0 || a.chain === "STELLAR") && (a.type === "native" || a.type === "credit_alphanum4" || a.type === "credit_alphanum12")
4660
+ ).map((a) => ({
4448
4661
  ref: toRef(a),
4449
4662
  code: a.code,
4450
4663
  issuer: a.issuer,
@@ -4745,15 +4958,13 @@ function EarnModal({ onClose }) {
4745
4958
  if (!selectedOpportunity) return null;
4746
4959
  const balances = walletBalance.step === "loaded" ? walletBalance.data.balances : [];
4747
4960
  const issuer = selectedOpportunity.asset.issuer;
4748
- const rec = balances.find(
4749
- (b) => issuer === null ? b.type === "native" : b.code === assetCode && b.issuer === issuer
4750
- );
4961
+ const rec = balances.find((b) => issuer === null ? b.type === "native" : b.code === assetCode && b.issuer === issuer);
4751
4962
  return rec ? rec.available : null;
4752
4963
  })();
4753
4964
  const depositAssetRecord = (() => {
4754
4965
  if (!selectedOpportunity?.asset.issuer || enabledAssets.step !== "loaded") return void 0;
4755
4966
  return enabledAssets.data.assets.find(
4756
- (a) => a.code === assetCode && a.issuer === selectedOpportunity.asset.issuer
4967
+ (a) => (a.chain === void 0 || a.chain === "STELLAR") && a.code === assetCode && a.issuer === selectedOpportunity.asset.issuer
4757
4968
  );
4758
4969
  })();
4759
4970
  const depositNeedsTrustline = tab === "deposit" && !smartUnsupported && !!selectedOpportunity?.asset.issuer && !depositAssetRecord?.trustlineEstablished;
@@ -4809,10 +5020,7 @@ function EarnModal({ onClose }) {
4809
5020
  }
4810
5021
  setStep("tx");
4811
5022
  if (tab === "deposit" && depositNeedsTrustline && selectedOpportunity?.asset.issuer) {
4812
- const tl = await setTrustline(
4813
- { code: assetCode, issuer: selectedOpportunity.asset.issuer },
4814
- depositAssetRecord?.sponsored ? { sponsored: true } : void 0
4815
- );
5023
+ const tl = await setTrustline({ code: assetCode, issuer: selectedOpportunity.asset.issuer });
4816
5024
  if (tl.status === "error") {
4817
5025
  setFormError(`Trustline for ${assetCode} failed: ${tl.details ?? "unknown error"}`);
4818
5026
  setStep("form");
@@ -5427,6 +5635,12 @@ function TransactionModal({ onClose }) {
5427
5635
  ) });
5428
5636
  }
5429
5637
  var PAGE_SIZE = 10;
5638
+ function explorerUrlFor(chain, hash, network) {
5639
+ if (chain === "SOLANA") {
5640
+ return `https://explorer.solana.com/tx/${hash}${network === "testnet" ? "?cluster=devnet" : ""}`;
5641
+ }
5642
+ return `https://stellar.expert/explorer/${network === "testnet" ? "testnet" : "public"}/tx/${hash}`;
5643
+ }
5430
5644
  function StatusBadge({ status }) {
5431
5645
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-hist-item-badge", "data-status": status, children: status });
5432
5646
  }
@@ -5465,6 +5679,10 @@ function TxHistoryModalTemplate({
5465
5679
  accentColor,
5466
5680
  txHistory,
5467
5681
  offset,
5682
+ chains,
5683
+ selectedChain,
5684
+ walletAddress,
5685
+ onSelectChain,
5468
5686
  onRefresh,
5469
5687
  onPrev,
5470
5688
  onNext,
@@ -5540,6 +5758,11 @@ function TxHistoryModalTemplate({
5540
5758
  /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
5541
5759
  ] })
5542
5760
  ] }),
5761
+ /* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain, disabled: isLoading }),
5762
+ walletAddress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-address-row", children: [
5763
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-address", children: cropAddress(walletAddress) }),
5764
+ /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: walletAddress, label: "Copy wallet address" })
5765
+ ] }),
5543
5766
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-hist-list", children: [
5544
5767
  txHistory.step === "idle" && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "Click Refresh to load transactions." }),
5545
5768
  isLoading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-loading-block", children: [
@@ -5550,7 +5773,7 @@ function TxHistoryModalTemplate({
5550
5773
  txHistory.step === "loaded" && records.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No transactions yet." }),
5551
5774
  records.map((record) => {
5552
5775
  const hash = typeof record.hash === "string" && record.hash.length > 0 ? record.hash : void 0;
5553
- const explorerUrl = hash ? `https://stellar.expert/explorer/${record.network === "testnet" ? "testnet" : "public"}/tx/${hash}` : void 0;
5776
+ const explorerUrl = hash ? explorerUrlFor(record.chain, hash, record.network) : void 0;
5554
5777
  const asset = typeof record.details?.asset === "string" ? record.details.asset : void 0;
5555
5778
  const colon = asset ? asset.indexOf(":") : -1;
5556
5779
  const trustline = record.operation === "change_trust" && asset && colon > 0 ? {
@@ -5584,10 +5807,11 @@ function TxHistoryModalTemplate({
5584
5807
  "\xB7 ",
5585
5808
  record.details.sponsored ? "Sponsored" : "Self-paid"
5586
5809
  ] }),
5587
- record.feeXlm && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
5810
+ record.fee && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
5588
5811
  "\xB7 ",
5589
- record.feeXlm,
5590
- " XLM"
5812
+ record.fee.amount,
5813
+ " ",
5814
+ record.fee.unit
5591
5815
  ] })
5592
5816
  ] }),
5593
5817
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-hist-item-footer", children: [
@@ -5603,7 +5827,7 @@ function TxHistoryModalTemplate({
5603
5827
  href: explorerUrl,
5604
5828
  target: "_blank",
5605
5829
  rel: "noopener noreferrer",
5606
- "aria-label": "View on Stellar Explorer",
5830
+ "aria-label": "View on block explorer",
5607
5831
  children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 13 13", fill: "none", "aria-hidden": true, children: [
5608
5832
  /* @__PURE__ */ jsxRuntime.jsx(
5609
5833
  "path",
@@ -5652,19 +5876,29 @@ function TxHistoryModalTemplate({
5652
5876
  }
5653
5877
  var PAGE_SIZE2 = 10;
5654
5878
  function TxHistoryModal({ onClose }) {
5655
- const { getClient, styles, txHistory } = usePollar();
5879
+ const { getClient, styles, txHistory, wallets } = usePollar();
5656
5880
  const { theme = "light", accentColor = "#005DB4" } = styles;
5657
5881
  const [offset, setOffset] = react.useState(0);
5882
+ const { chains } = useChains();
5883
+ const [selectedChain, setSelectedChain] = react.useState(null);
5884
+ react.useEffect(() => {
5885
+ if (selectedChain === null && chains.length > 0) setSelectedChain(chains[0]);
5886
+ }, [chains, selectedChain]);
5887
+ const walletAddress = addressForChain(wallets, selectedChain);
5658
5888
  const load = react.useCallback(
5659
- (nextOffset) => {
5889
+ (nextOffset, chain) => {
5660
5890
  setOffset(nextOffset);
5661
- void getClient().fetchTxHistory({ limit: PAGE_SIZE2, offset: nextOffset });
5891
+ void getClient().fetchTxHistory({ limit: PAGE_SIZE2, offset: nextOffset, chain });
5662
5892
  },
5663
5893
  [getClient]
5664
5894
  );
5665
5895
  react.useEffect(() => {
5666
- load(0);
5667
- }, [load]);
5896
+ if (selectedChain) load(0, selectedChain);
5897
+ }, [selectedChain, load]);
5898
+ const onSelectChain = (chain) => setSelectedChain(chain);
5899
+ const paged = (nextOffset) => {
5900
+ if (selectedChain) load(nextOffset, selectedChain);
5901
+ };
5668
5902
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
5669
5903
  TxHistoryModalTemplate,
5670
5904
  {
@@ -5672,47 +5906,48 @@ function TxHistoryModal({ onClose }) {
5672
5906
  accentColor,
5673
5907
  txHistory,
5674
5908
  offset,
5675
- onRefresh: () => load(offset),
5676
- onPrev: () => load(Math.max(0, offset - PAGE_SIZE2)),
5677
- onNext: () => load(offset + PAGE_SIZE2),
5909
+ chains,
5910
+ selectedChain,
5911
+ walletAddress,
5912
+ onSelectChain,
5913
+ onRefresh: () => paged(offset),
5914
+ onPrev: () => paged(Math.max(0, offset - PAGE_SIZE2)),
5915
+ onNext: () => paged(offset + PAGE_SIZE2),
5678
5916
  onClose
5679
5917
  }
5680
5918
  ) });
5681
5919
  }
5682
- function formatBalance2(balance) {
5920
+ function formatBalance2(balance, decimals = 7) {
5921
+ if (balance === null) return "\u2014";
5922
+ const digits = Math.min(decimals, 7);
5683
5923
  const n = parseFloat(balance);
5684
- return isNaN(n) ? balance : n.toLocaleString(void 0, { minimumFractionDigits: 7, maximumFractionDigits: 7 });
5924
+ return isNaN(n) ? balance : n.toLocaleString(void 0, { minimumFractionDigits: digits, maximumFractionDigits: digits });
5685
5925
  }
5686
- function cropAddress2(address) {
5687
- if (address.length <= 16) return address;
5688
- return `${address.slice(0, 8)}...${address.slice(-8)}`;
5689
- }
5690
- var CHAIN_TAG = {
5691
- STELLAR: { label: "Stellar", color: "#7d00ff" },
5692
- POLYGON: { label: "Polygon", color: "#8247e5" },
5693
- SOLANA: { label: "Solana", color: "#14f195" }
5694
- };
5695
- function ChainTag({ chain }) {
5696
- const tag = CHAIN_TAG[chain] ?? { label: chain, color: "#6b7280" };
5697
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-bal-chain-tag", style: { "--pollar-chain-color": tag.color }, children: tag.label });
5926
+ function faucetFor(record) {
5927
+ if (record.type === "native") return { url: "https://faucet.solana.com/", label: "Get test SOL" };
5928
+ if (record.code === "USDC") return { url: "https://faucet.circle.com/", label: "Get test USDC" };
5929
+ return null;
5698
5930
  }
5699
- function BalanceItem({ record, showChain }) {
5931
+ function BalanceItem({ record, faucet }) {
5700
5932
  const balanceDiffers = record.balance !== record.available;
5701
5933
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-bal-item", children: [
5702
5934
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-bal-asset-info", children: [
5703
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-bal-asset-code-row", children: [
5704
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-bal-asset", children: record.code }),
5705
- showChain && record.chain && /* @__PURE__ */ jsxRuntime.jsx(ChainTag, { chain: record.chain })
5706
- ] }),
5707
- record.issuer && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-bal-issuer", children: [
5708
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-bal-issuer-addr", children: cropAddress2(record.issuer) }),
5935
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-bal-asset-code-row", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-bal-asset", children: record.code }) }),
5936
+ record.issuer && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-issuer", children: [
5937
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-issuer-addr", children: cropAddress(record.issuer) }),
5709
5938
  /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: record.issuer, label: "Copy issuer address", className: "pollar-copy-btn-sm" })
5939
+ ] }),
5940
+ faucet && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-bal-faucet-hint", children: [
5941
+ "Need more?",
5942
+ " ",
5943
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: faucet.url, target: "_blank", rel: "noopener noreferrer", children: faucet.label }),
5944
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-bal-faucet-net", children: " (devnet)" })
5710
5945
  ] })
5711
5946
  ] }),
5712
5947
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-bal-amounts", children: [
5713
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-bal-amount", children: formatBalance2(record.balance) }),
5948
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-bal-amount", children: formatBalance2(record.balance, record.decimals) }),
5714
5949
  balanceDiffers && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-bal-available", children: [
5715
- formatBalance2(record.available),
5950
+ formatBalance2(record.available, record.decimals),
5716
5951
  " available"
5717
5952
  ] })
5718
5953
  ] })
@@ -5723,6 +5958,10 @@ function WalletBalanceModalTemplate({
5723
5958
  accentColor,
5724
5959
  walletBalance,
5725
5960
  walletAddress,
5961
+ chains,
5962
+ selectedChain,
5963
+ network,
5964
+ onSelectChain,
5726
5965
  onRefresh,
5727
5966
  onClose
5728
5967
  }) {
@@ -5745,8 +5984,11 @@ function WalletBalanceModalTemplate({
5745
5984
  "--pollar-card-border-radius": "10px"
5746
5985
  };
5747
5986
  const isLoading = walletBalance.step === "loading";
5748
- const data = walletBalance.step === "loaded" ? walletBalance.data : null;
5987
+ const data = useStickyData(walletBalance.step === "loaded" ? walletBalance.data : null);
5988
+ const balances = (data?.balances ?? []).filter((b) => resolveChain(b.chain) === selectedChain);
5989
+ const showFaucets = selectedChain === "SOLANA" && network === "testnet";
5749
5990
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-card pollar-bal-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
5991
+ isLoading && data && /* @__PURE__ */ jsxRuntime.jsx(BusyOverlay, { label: "Refreshing balances\u2026" }),
5750
5992
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
5751
5993
  /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Wallet Balance" }),
5752
5994
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header-actions", children: [
@@ -5785,11 +6027,12 @@ function WalletBalanceModalTemplate({
5785
6027
  /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
5786
6028
  ] })
5787
6029
  ] }),
5788
- walletAddress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-bal-address-row", children: [
5789
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-bal-address", children: cropAddress2(walletAddress) }),
6030
+ /* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain, disabled: isLoading }),
6031
+ walletAddress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-address-row", children: [
6032
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-address", children: cropAddress(walletAddress) }),
5790
6033
  /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: walletAddress, label: "Copy wallet address" })
5791
6034
  ] }),
5792
- isLoading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-loading-block", children: [
6035
+ isLoading && !data && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-loading-block", children: [
5793
6036
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner" }),
5794
6037
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading\u2026" })
5795
6038
  ] }),
@@ -5799,15 +6042,27 @@ function WalletBalanceModalTemplate({
5799
6042
  data.network,
5800
6043
  "."
5801
6044
  ] }),
5802
- data?.exists && data.balances.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No balances found." }),
5803
- data?.exists && data.balances.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-bal-list", children: data.balances.map((b) => /* @__PURE__ */ jsxRuntime.jsx(BalanceItem, { record: b, showChain: data.multichain === true }, (b.chain ?? "") + b.code + (b.issuer ?? ""))) }),
6045
+ data?.exists && balances.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No balances found on this network." }),
6046
+ data?.exists && balances.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-bal-list", children: balances.map((b) => /* @__PURE__ */ jsxRuntime.jsx(
6047
+ BalanceItem,
6048
+ {
6049
+ record: b,
6050
+ faucet: showFaucets ? faucetFor(b) : null
6051
+ },
6052
+ (b.chain ?? "") + b.code + (b.issuer ?? "")
6053
+ )) }),
5804
6054
  /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
5805
6055
  ] });
5806
6056
  }
5807
6057
  function WalletBalanceModal({ onClose }) {
5808
- const { walletBalance, refreshWalletBalance, wallet, styles } = usePollar();
5809
- const walletAddress = wallet?.address ?? "";
6058
+ const { walletBalance, refreshWalletBalance, wallets, network, styles } = usePollar();
5810
6059
  const { theme = "light", accentColor = "#005DB4" } = styles;
6060
+ const { chains } = useChains();
6061
+ const [selectedChain, setSelectedChain] = react.useState(null);
6062
+ react.useEffect(() => {
6063
+ if (selectedChain === null && chains.length > 0) setSelectedChain(chains[0]);
6064
+ }, [chains, selectedChain]);
6065
+ const walletAddress = addressForChain(wallets, selectedChain);
5811
6066
  react.useEffect(() => {
5812
6067
  void refreshWalletBalance();
5813
6068
  }, [refreshWalletBalance]);
@@ -5818,6 +6073,10 @@ function WalletBalanceModal({ onClose }) {
5818
6073
  accentColor,
5819
6074
  walletBalance,
5820
6075
  walletAddress,
6076
+ chains,
6077
+ selectedChain,
6078
+ network,
6079
+ onSelectChain: setSelectedChain,
5821
6080
  onRefresh: () => refreshWalletBalance(),
5822
6081
  onClose
5823
6082
  }
@@ -5922,6 +6181,9 @@ function PollarProvider({
5922
6181
  );
5923
6182
  const [configRetry, setConfigRetry] = react.useState(0);
5924
6183
  const retryConfig = react.useCallback(() => setConfigRetry((n) => n + 1), []);
6184
+ const appConfigKey = appConfigProp === void 0 ? "" : JSON.stringify(appConfigProp);
6185
+ const appConfigPropRef = react.useRef(appConfigProp);
6186
+ appConfigPropRef.current = appConfigProp;
5925
6187
  react.useEffect(() => {
5926
6188
  return pollarClient.onTransactionStateChange(setTransaction);
5927
6189
  }, [pollarClient]);
@@ -5985,7 +6247,9 @@ function PollarProvider({
5985
6247
  setModalErrorLogger(pollarClient.getLogger());
5986
6248
  }, [pollarClient]);
5987
6249
  react.useEffect(() => {
5988
- if (appConfigProp !== void 0) {
6250
+ const localConfig = appConfigPropRef.current;
6251
+ if (localConfig !== void 0) {
6252
+ setResolvedConfig(localConfig ?? DEFAULT_APP_CONFIG);
5989
6253
  setConfigStatus("ready");
5990
6254
  return;
5991
6255
  }
@@ -6007,7 +6271,7 @@ function PollarProvider({
6007
6271
  return () => {
6008
6272
  cancelled = true;
6009
6273
  };
6010
- }, [pollarClient, appConfigProp, configRetry]);
6274
+ }, [pollarClient, appConfigKey, configRetry]);
6011
6275
  const [loginModalOpen, setLoginModalOpen] = react.useState(false);
6012
6276
  const [transactionModalOpen, setTransactionModalOpen] = react.useState(false);
6013
6277
  const [kycModalOpen, setKycModalOpen] = react.useState(false);
@@ -6034,6 +6298,7 @@ function PollarProvider({
6034
6298
  return {
6035
6299
  // session
6036
6300
  wallet: pollarClient.getWallet(),
6301
+ wallets: pollarClient.getWallets(),
6037
6302
  isAuthenticated: !!walletAddress,
6038
6303
  verified,
6039
6304
  // client
@@ -6050,6 +6315,7 @@ function PollarProvider({
6050
6315
  submitTx: (signedXdr) => pollarClient.submitTx(signedXdr),
6051
6316
  buildAndSignAndSubmitTx: (operation, params, options) => pollarClient.buildAndSignAndSubmitTx(operation, params, options),
6052
6317
  runTx: (operation, params, options) => pollarClient.runTx(operation, params, options),
6318
+ sendPayment: (params) => pollarClient.sendPayment(params),
6053
6319
  openTxModal: () => setTransactionModalOpen(true),
6054
6320
  // tx history
6055
6321
  txHistory,
@@ -6534,7 +6800,8 @@ function WalletButton() {
6534
6800
  openDistributionRulesModal,
6535
6801
  tx: transaction
6536
6802
  } = usePollar();
6537
- const walletAddress = wallet?.address ?? "";
6803
+ const { primaryAddress } = useChains();
6804
+ const walletAddress = primaryAddress || (wallet?.address ?? "");
6538
6805
  const walletType = wallet?.custody === "external" ? wallet.provider : null;
6539
6806
  const [open, setOpen] = react.useState(false);
6540
6807
  const [copied, setCopied] = react.useState(false);
@@ -6656,6 +6923,7 @@ function WalletButton() {
6656
6923
  );
6657
6924
  }
6658
6925
 
6926
+ exports.ChainSelect = ChainSelect;
6659
6927
  exports.DistributionRulesModal = DistributionRulesModal;
6660
6928
  exports.DistributionRulesModalTemplate = DistributionRulesModalTemplate;
6661
6929
  exports.EarnModal = EarnModal;
@@ -6684,7 +6952,11 @@ exports.WalletBalanceModal = WalletBalanceModal;
6684
6952
  exports.WalletBalanceModalTemplate = WalletBalanceModalTemplate;
6685
6953
  exports.WalletButton = WalletButton;
6686
6954
  exports.WalletButtonTemplate = WalletButtonTemplate;
6955
+ exports.addressForChain = addressForChain;
6956
+ exports.chainsOf = chainsOf;
6687
6957
  exports.createPollarAdapterHook = createPollarAdapterHook;
6958
+ exports.resolveChain = resolveChain;
6959
+ exports.useChains = useChains;
6688
6960
  exports.usePollar = usePollar;
6689
6961
  //# sourceMappingURL=index.js.map
6690
6962
  //# sourceMappingURL=index.js.map