@pollar/react 0.9.0 → 0.10.0-rc.10

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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { AUTH_ERROR_CODES, WalletType, PollarClient } from '@pollar/core';
2
+ import { AUTH_ERROR_CODES, WalletType, PollarClient, isInteractiveAuthAdapter } from '@pollar/core';
3
3
  import { forwardRef, createContext, useState, useCallback, useEffect, useRef, useMemo, useContext, Component } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
  import { startAuthentication, startRegistration } from '@simplewebauthn/browser';
@@ -1033,7 +1033,7 @@ var PollarModalFooter = () => {
1033
1033
  /* @__PURE__ */ jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
1034
1034
  /* @__PURE__ */ jsxs("span", { className: "pollar-footer-version", children: [
1035
1035
  "v",
1036
- "0.9.0"
1036
+ "0.10.0-rc.10"
1037
1037
  ] })
1038
1038
  ] })
1039
1039
  ] });
@@ -1338,54 +1338,63 @@ function EnabledAssetsModalTemplate({
1338
1338
  const isLoading = enabledAssets.step === "loading";
1339
1339
  const data = enabledAssets.step === "loaded" ? enabledAssets.data : null;
1340
1340
  const busy = busyKey !== null;
1341
- return /* @__PURE__ */ jsxs("div", { className: "pollar-modal-card pollar-asset-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
1342
- /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
1343
- /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Trustlines" }),
1344
- /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header-actions", children: [
1345
- /* @__PURE__ */ jsxs("button", { className: "pollar-modal-refresh-btn", onClick: onRefresh, disabled: isLoading || busy, children: [
1346
- /* @__PURE__ */ jsxs(
1347
- "svg",
1348
- {
1349
- className: `pollar-modal-refresh-icon${isLoading ? " spinning" : ""}`,
1350
- width: "13",
1351
- height: "13",
1352
- viewBox: "0 0 13 13",
1353
- fill: "none",
1354
- "aria-hidden": true,
1355
- children: [
1356
- /* @__PURE__ */ jsx("path", { d: "M11.5 6.5a5 5 0 11-1.5-3.536", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
1357
- /* @__PURE__ */ jsx("path", { d: "M10 1v3h-3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
1358
- ]
1359
- }
1360
- ),
1361
- "Refresh"
1341
+ return /* @__PURE__ */ jsxs(
1342
+ "div",
1343
+ {
1344
+ className: "pollar-modal-card pollar-asset-modal",
1345
+ "data-theme": theme,
1346
+ style: cssVars,
1347
+ onClick: (e) => e.stopPropagation(),
1348
+ children: [
1349
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
1350
+ /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Trustlines" }),
1351
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header-actions", children: [
1352
+ /* @__PURE__ */ jsxs("button", { className: "pollar-modal-refresh-btn", onClick: onRefresh, disabled: isLoading || busy, children: [
1353
+ /* @__PURE__ */ jsxs(
1354
+ "svg",
1355
+ {
1356
+ className: `pollar-modal-refresh-icon${isLoading ? " spinning" : ""}`,
1357
+ width: "13",
1358
+ height: "13",
1359
+ viewBox: "0 0 13 13",
1360
+ fill: "none",
1361
+ "aria-hidden": true,
1362
+ children: [
1363
+ /* @__PURE__ */ jsx("path", { d: "M11.5 6.5a5 5 0 11-1.5-3.536", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }),
1364
+ /* @__PURE__ */ jsx("path", { d: "M10 1v3h-3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" })
1365
+ ]
1366
+ }
1367
+ ),
1368
+ "Refresh"
1369
+ ] }),
1370
+ /* @__PURE__ */ jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
1371
+ ] })
1362
1372
  ] }),
1363
- /* @__PURE__ */ jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
1364
- ] })
1365
- ] }),
1366
- walletAddress && /* @__PURE__ */ jsx("div", { className: "pollar-asset-address", children: cropAddress(walletAddress) }),
1367
- isLoading && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Loading\u2026" }),
1368
- enabledAssets.step === "error" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: enabledAssets.message }),
1369
- actionError && /* @__PURE__ */ jsx("div", { className: "pollar-modal-action-error", children: actionError }),
1370
- data && !data.exists && /* @__PURE__ */ jsxs("div", { className: "pollar-modal-empty", children: [
1371
- "Account not found on ",
1372
- data.network,
1373
- "."
1374
- ] }),
1375
- data && data.assets.length === 0 && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "No trustlines found." }),
1376
- data && data.assets.length > 0 && /* @__PURE__ */ jsx("div", { className: "pollar-asset-list", children: data.assets.map((a) => /* @__PURE__ */ jsx(
1377
- AssetItem,
1378
- {
1379
- record: a,
1380
- busy: busyKey === assetKey(a),
1381
- disabled: busy && busyKey !== assetKey(a),
1382
- onToggle: onToggleTrustline
1383
- },
1384
- assetKey(a)
1385
- )) }),
1386
- /* @__PURE__ */ jsx("button", { className: "pollar-asset-add-custom", onClick: onAddCustom, disabled: busy, children: "+ Add custom trustline" }),
1387
- /* @__PURE__ */ jsx(PollarModalFooter, {})
1388
- ] });
1373
+ walletAddress && /* @__PURE__ */ jsx("div", { className: "pollar-asset-address", children: cropAddress(walletAddress) }),
1374
+ isLoading && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "Loading\u2026" }),
1375
+ enabledAssets.step === "error" && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: enabledAssets.message }),
1376
+ actionError && /* @__PURE__ */ jsx("div", { className: "pollar-modal-action-error", children: actionError }),
1377
+ data && !data.exists && /* @__PURE__ */ jsxs("div", { className: "pollar-modal-empty", children: [
1378
+ "Account not found on ",
1379
+ data.network,
1380
+ "."
1381
+ ] }),
1382
+ data && data.assets.length === 0 && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "No trustlines found." }),
1383
+ data && data.assets.length > 0 && /* @__PURE__ */ jsx("div", { className: "pollar-asset-list", children: data.assets.map((a) => /* @__PURE__ */ jsx(
1384
+ AssetItem,
1385
+ {
1386
+ record: a,
1387
+ busy: busyKey === assetKey(a),
1388
+ disabled: busy && busyKey !== assetKey(a),
1389
+ onToggle: onToggleTrustline
1390
+ },
1391
+ assetKey(a)
1392
+ )) }),
1393
+ /* @__PURE__ */ jsx("button", { className: "pollar-asset-add-custom", onClick: onAddCustom, disabled: busy, children: "+ Add custom trustline" }),
1394
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
1395
+ ]
1396
+ }
1397
+ );
1389
1398
  }
1390
1399
  function isValidIssuer(issuer) {
1391
1400
  return issuer.length === 56 && issuer.startsWith("G");
@@ -1411,79 +1420,89 @@ function CustomTrustlineModalTemplate({
1411
1420
  const trimmedLimit = limit.trim();
1412
1421
  onSubmit({ code: code.trim(), issuer: issuer.trim(), ...trimmedLimit ? { limit: trimmedLimit } : {} });
1413
1422
  };
1414
- return /* @__PURE__ */ jsxs("div", { className: "pollar-modal-card pollar-asset-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
1415
- /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
1416
- /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header-actions", children: [
1417
- /* @__PURE__ */ jsx("button", { className: "pollar-modal-back", onClick: onBack, disabled: busy, "aria-label": "Back", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M10 3L5 8l5 5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
1418
- /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Add custom trustline" })
1419
- ] }),
1420
- /* @__PURE__ */ jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
1421
- ] }),
1422
- /* @__PURE__ */ jsx("p", { className: "pollar-asset-custom-hint", children: "Custom trustlines aren't sponsored \u2014 your wallet pays the 0.5 XLM reserve and the transaction fee." }),
1423
- /* @__PURE__ */ jsxs("div", { className: "pollar-field", children: [
1424
- /* @__PURE__ */ jsx("label", { className: "pollar-label", htmlFor: "pollar-trustline-code", children: "Asset code" }),
1425
- /* @__PURE__ */ jsx(
1426
- "input",
1427
- {
1428
- id: "pollar-trustline-code",
1429
- className: "pollar-input",
1430
- value: code,
1431
- onChange: (e) => setCode(e.target.value),
1432
- placeholder: "USDC",
1433
- maxLength: 12,
1434
- autoComplete: "off",
1435
- spellCheck: false,
1436
- disabled: busy
1437
- }
1438
- )
1439
- ] }),
1440
- /* @__PURE__ */ jsxs("div", { className: "pollar-field", children: [
1441
- /* @__PURE__ */ jsx("label", { className: "pollar-label", htmlFor: "pollar-trustline-issuer", children: "Issuer" }),
1442
- /* @__PURE__ */ jsx(
1443
- "input",
1444
- {
1445
- id: "pollar-trustline-issuer",
1446
- className: "pollar-input",
1447
- value: issuer,
1448
- onChange: (e) => setIssuer(e.target.value),
1449
- placeholder: "G\u2026",
1450
- autoComplete: "off",
1451
- spellCheck: false,
1452
- disabled: busy
1453
- }
1454
- ),
1455
- issuer.trim().length > 0 && !issuerOk && /* @__PURE__ */ jsx("span", { className: "pollar-field-error", children: "Issuer must be a 56-character Stellar address starting with G." })
1456
- ] }),
1457
- /* @__PURE__ */ jsxs("div", { className: "pollar-field", children: [
1458
- /* @__PURE__ */ jsxs("label", { className: "pollar-label", htmlFor: "pollar-trustline-limit", children: [
1459
- "Limit ",
1460
- /* @__PURE__ */ jsx("span", { className: "pollar-label-optional", children: "(optional)" })
1461
- ] }),
1462
- /* @__PURE__ */ jsx(
1463
- "input",
1464
- {
1465
- id: "pollar-trustline-limit",
1466
- className: "pollar-input",
1467
- value: limit,
1468
- onChange: (e) => setLimit(e.target.value),
1469
- placeholder: "Maximum",
1470
- inputMode: "decimal",
1471
- autoComplete: "off",
1472
- spellCheck: false,
1473
- disabled: busy
1474
- }
1475
- )
1476
- ] }),
1477
- actionError && /* @__PURE__ */ jsx("div", { className: "pollar-modal-action-error", children: actionError }),
1478
- /* @__PURE__ */ jsx("button", { className: "pollar-asset-submit", onClick: submit, disabled: !canSubmit, children: busy ? "Enabling\u2026" : "Enable trustline" }),
1479
- /* @__PURE__ */ jsx(PollarModalFooter, {})
1480
- ] });
1423
+ return /* @__PURE__ */ jsxs(
1424
+ "div",
1425
+ {
1426
+ className: "pollar-modal-card pollar-asset-modal",
1427
+ "data-theme": theme,
1428
+ style: cssVars,
1429
+ onClick: (e) => e.stopPropagation(),
1430
+ children: [
1431
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
1432
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header-actions", children: [
1433
+ /* @__PURE__ */ jsx("button", { className: "pollar-modal-back", onClick: onBack, disabled: busy, "aria-label": "Back", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M10 3L5 8l5 5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
1434
+ /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Add custom trustline" })
1435
+ ] }),
1436
+ /* @__PURE__ */ jsx("button", { className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) })
1437
+ ] }),
1438
+ /* @__PURE__ */ jsx("p", { className: "pollar-asset-custom-hint", children: "Custom trustlines aren't sponsored \u2014 your wallet pays the 0.5 XLM reserve and the transaction fee." }),
1439
+ /* @__PURE__ */ jsxs("div", { className: "pollar-field", children: [
1440
+ /* @__PURE__ */ jsx("label", { className: "pollar-label", htmlFor: "pollar-trustline-code", children: "Asset code" }),
1441
+ /* @__PURE__ */ jsx(
1442
+ "input",
1443
+ {
1444
+ id: "pollar-trustline-code",
1445
+ className: "pollar-input",
1446
+ value: code,
1447
+ onChange: (e) => setCode(e.target.value),
1448
+ placeholder: "USDC",
1449
+ maxLength: 12,
1450
+ autoComplete: "off",
1451
+ spellCheck: false,
1452
+ disabled: busy
1453
+ }
1454
+ )
1455
+ ] }),
1456
+ /* @__PURE__ */ jsxs("div", { className: "pollar-field", children: [
1457
+ /* @__PURE__ */ jsx("label", { className: "pollar-label", htmlFor: "pollar-trustline-issuer", children: "Issuer" }),
1458
+ /* @__PURE__ */ jsx(
1459
+ "input",
1460
+ {
1461
+ id: "pollar-trustline-issuer",
1462
+ className: "pollar-input",
1463
+ value: issuer,
1464
+ onChange: (e) => setIssuer(e.target.value),
1465
+ placeholder: "G\u2026",
1466
+ autoComplete: "off",
1467
+ spellCheck: false,
1468
+ disabled: busy
1469
+ }
1470
+ ),
1471
+ issuer.trim().length > 0 && !issuerOk && /* @__PURE__ */ jsx("span", { className: "pollar-field-error", children: "Issuer must be a 56-character Stellar address starting with G." })
1472
+ ] }),
1473
+ /* @__PURE__ */ jsxs("div", { className: "pollar-field", children: [
1474
+ /* @__PURE__ */ jsxs("label", { className: "pollar-label", htmlFor: "pollar-trustline-limit", children: [
1475
+ "Limit ",
1476
+ /* @__PURE__ */ jsx("span", { className: "pollar-label-optional", children: "(optional)" })
1477
+ ] }),
1478
+ /* @__PURE__ */ jsx(
1479
+ "input",
1480
+ {
1481
+ id: "pollar-trustline-limit",
1482
+ className: "pollar-input",
1483
+ value: limit,
1484
+ onChange: (e) => setLimit(e.target.value),
1485
+ placeholder: "Maximum",
1486
+ inputMode: "decimal",
1487
+ autoComplete: "off",
1488
+ spellCheck: false,
1489
+ disabled: busy
1490
+ }
1491
+ )
1492
+ ] }),
1493
+ actionError && /* @__PURE__ */ jsx("div", { className: "pollar-modal-action-error", children: actionError }),
1494
+ /* @__PURE__ */ jsx("button", { className: "pollar-asset-submit", onClick: submit, disabled: !canSubmit, children: busy ? "Enabling\u2026" : "Enable trustline" }),
1495
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
1496
+ ]
1497
+ }
1498
+ );
1481
1499
  }
1482
1500
  function assetKey2(record) {
1483
1501
  return record.code + (record.issuer ?? "");
1484
1502
  }
1485
1503
  function EnabledAssetsModal({ onClose }) {
1486
- const { enabledAssets, refreshAssets, setTrustline, walletAddress, styles } = usePollar();
1504
+ const { enabledAssets, refreshAssets, setTrustline, wallet, styles } = usePollar();
1505
+ const walletAddress = wallet?.address ?? "";
1487
1506
  const { theme = "light", accentColor = "#005DB4" } = styles;
1488
1507
  const [view, setView] = useState("list");
1489
1508
  const [busyKey, setBusyKey] = useState(null);
@@ -1831,35 +1850,42 @@ var GoogleButton = ({ disabled, onClick }) => {
1831
1850
  ] })
1832
1851
  ] });
1833
1852
  };
1834
- function DefaultFreighterAlbedoButtons({ onConnect, isLoading }) {
1835
- return /* @__PURE__ */ jsxs("div", { className: "pollar-wallet-list", children: [
1836
- /* @__PURE__ */ jsxs(
1837
- "button",
1838
- {
1839
- type: "button",
1840
- disabled: isLoading,
1841
- className: "pollar-wallet-list-btn",
1842
- onClick: () => onConnect(WalletType.FREIGHTER),
1843
- children: [
1844
- /* @__PURE__ */ jsx("img", { src: LOGO_FREIGHTER, alt: "Freighter", className: "pollar-wallet-list-icon" }),
1845
- /* @__PURE__ */ jsx("span", { className: "pollar-wallet-list-name", children: "Freighter" })
1846
- ]
1847
- }
1848
- ),
1849
- /* @__PURE__ */ jsxs(
1853
+ function WalletAdapterButtons({
1854
+ walletAdapters,
1855
+ onConnect,
1856
+ isLoading,
1857
+ variant = "list"
1858
+ }) {
1859
+ if (variant === "entry") {
1860
+ return /* @__PURE__ */ jsx(Fragment, { children: walletAdapters.map((a) => /* @__PURE__ */ jsxs(
1850
1861
  "button",
1851
1862
  {
1852
1863
  type: "button",
1853
1864
  disabled: isLoading,
1854
- className: "pollar-wallet-list-btn",
1855
- onClick: () => onConnect(WalletType.ALBEDO),
1865
+ className: "pollar-wallet-entry-btn",
1866
+ onClick: () => onConnect(a.id),
1856
1867
  children: [
1857
- /* @__PURE__ */ jsx("img", { src: LOGO_ALBEDO, alt: "Albedo", className: "pollar-wallet-list-icon" }),
1858
- /* @__PURE__ */ jsx("span", { className: "pollar-wallet-list-name", children: "Albedo" })
1868
+ a.meta.iconUrl && /* @__PURE__ */ jsx("img", { src: a.meta.iconUrl, alt: a.meta.label, className: "pollar-wallet-icon" }),
1869
+ a.meta.label
1859
1870
  ]
1860
- }
1861
- )
1862
- ] });
1871
+ },
1872
+ a.id
1873
+ )) });
1874
+ }
1875
+ return /* @__PURE__ */ jsx("div", { className: "pollar-wallet-list", children: walletAdapters.map((a) => /* @__PURE__ */ jsxs(
1876
+ "button",
1877
+ {
1878
+ type: "button",
1879
+ disabled: isLoading,
1880
+ className: "pollar-wallet-list-btn",
1881
+ onClick: () => onConnect(a.id),
1882
+ children: [
1883
+ a.meta.iconUrl && /* @__PURE__ */ jsx("img", { src: a.meta.iconUrl, alt: a.meta.label, className: "pollar-wallet-list-icon" }),
1884
+ /* @__PURE__ */ jsx("span", { className: "pollar-wallet-list-name", children: a.meta.label })
1885
+ ]
1886
+ },
1887
+ a.id
1888
+ )) });
1863
1889
  }
1864
1890
  var AUTH_STATE_MESSAGES = {
1865
1891
  idle: "",
@@ -1870,6 +1896,7 @@ var AUTH_STATE_MESSAGES = {
1870
1896
  verifying_email_code: "Verifying\u2026",
1871
1897
  opening_oauth: "Redirecting\u2026",
1872
1898
  connecting_wallet: "Connecting wallet\u2026",
1899
+ signing_wallet_challenge: "Confirm in your wallet\u2026",
1873
1900
  wallet_not_installed: "Wallet not installed",
1874
1901
  authenticating_wallet: "Signing in with wallet\u2026",
1875
1902
  creating_passkey: "Waiting for passkey\u2026",
@@ -1885,6 +1912,7 @@ function authStateToStatus(step) {
1885
1912
  "verifying_email_code",
1886
1913
  "opening_oauth",
1887
1914
  "connecting_wallet",
1915
+ "signing_wallet_challenge",
1888
1916
  "authenticating_wallet",
1889
1917
  "creating_passkey",
1890
1918
  "deploying_smart_account",
@@ -1905,6 +1933,7 @@ function LoginModalTemplate({
1905
1933
  embeddedWallets,
1906
1934
  smartWallet = false,
1907
1935
  providers,
1936
+ walletAdapters,
1908
1937
  appName,
1909
1938
  email = "",
1910
1939
  onEmailChange,
@@ -1913,7 +1942,6 @@ function LoginModalTemplate({
1913
1942
  onWalletConnect,
1914
1943
  onLoginSmartWallet,
1915
1944
  onCreateSmartWallet,
1916
- renderWallets,
1917
1945
  authState,
1918
1946
  codeInputKey,
1919
1947
  onCodeSubmit,
@@ -1921,10 +1949,19 @@ function LoginModalTemplate({
1921
1949
  onCancel,
1922
1950
  onRetry
1923
1951
  }) {
1924
- const [showWalletPicker, setShowWalletPicker] = useState(false);
1925
1952
  const [showPasskeyChooser, setShowPasskeyChooser] = useState(false);
1953
+ const [activeGroup, setActiveGroup] = useState(null);
1926
1954
  const isDark = theme === "dark";
1927
1955
  const enabledSocial = Object.entries(providers).filter(([, enabled]) => enabled);
1956
+ const rootAdapters = walletAdapters.filter((a) => !a.meta.group);
1957
+ const walletGroups = walletAdapters.filter((a) => a.meta.group).reduce((acc, a) => {
1958
+ const label = a.meta.group;
1959
+ const existing = acc.find((g) => g.label === label);
1960
+ if (existing) existing.adapters.push(a);
1961
+ else acc.push({ label, adapters: [a] });
1962
+ return acc;
1963
+ }, []);
1964
+ const activeGroupAdapters = walletGroups.find((g) => g.label === activeGroup)?.adapters ?? [];
1928
1965
  const cssVars = {
1929
1966
  "--pollar-accent": accentColor,
1930
1967
  "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
@@ -1988,35 +2025,22 @@ function LoginModalTemplate({
1988
2025
  /* @__PURE__ */ jsx(BackButton, { onClick: onBack }),
1989
2026
  /* @__PURE__ */ jsx(EmailCodeInput, { email, onSubmit: onCodeSubmit ?? (() => {
1990
2027
  }) }, codeInputKey)
1991
- ] }) : showWalletPicker ? /* @__PURE__ */ jsxs(Fragment, { children: [
1992
- /* @__PURE__ */ jsx(BackButton, { onClick: () => setShowWalletPicker(false) }),
1993
- renderWallets ? renderWallets({ onConnect: onWalletConnect ?? (() => {
1994
- }), authState }) : /* @__PURE__ */ jsx(DefaultFreighterAlbedoButtons, { onConnect: onWalletConnect ?? (() => {
1995
- }), isLoading })
2028
+ ] }) : activeGroup ? /* @__PURE__ */ jsxs(Fragment, { children: [
2029
+ /* @__PURE__ */ jsx(BackButton, { onClick: () => setActiveGroup(null) }),
2030
+ /* @__PURE__ */ jsx(
2031
+ WalletAdapterButtons,
2032
+ {
2033
+ walletAdapters: activeGroupAdapters,
2034
+ onConnect: onWalletConnect ?? (() => {
2035
+ }),
2036
+ isLoading
2037
+ }
2038
+ )
1996
2039
  ] }) : showPasskeyChooser ? /* @__PURE__ */ jsxs(Fragment, { children: [
1997
2040
  /* @__PURE__ */ jsx(BackButton, { onClick: () => setShowPasskeyChooser(false) }),
1998
2041
  /* @__PURE__ */ jsxs("div", { className: "pollar-wallet-section", children: [
1999
- /* @__PURE__ */ jsx(
2000
- "button",
2001
- {
2002
- type: "button",
2003
- disabled: isLoading,
2004
- className: "pollar-btn-primary",
2005
- style: { width: "100%" },
2006
- onClick: onCreateSmartWallet,
2007
- children: "Create a new wallet"
2008
- }
2009
- ),
2010
- /* @__PURE__ */ jsx(
2011
- "button",
2012
- {
2013
- type: "button",
2014
- disabled: isLoading,
2015
- className: "pollar-wallet-entry-btn",
2016
- onClick: onLoginSmartWallet,
2017
- children: "Log in with an existing wallet"
2018
- }
2019
- )
2042
+ /* @__PURE__ */ jsx("button", { type: "button", disabled: isLoading, className: "pollar-btn-primary", onClick: onCreateSmartWallet, children: "Create a new wallet" }),
2043
+ /* @__PURE__ */ jsx("button", { type: "button", disabled: isLoading, className: "pollar-wallet-entry-btn", onClick: onLoginSmartWallet, children: "Log in with an existing wallet" })
2020
2044
  ] })
2021
2045
  ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2022
2046
  emailEnabled && /* @__PURE__ */ jsxs("div", { className: "pollar-email-section", children: [
@@ -2038,7 +2062,7 @@ function LoginModalTemplate({
2038
2062
  type: "button",
2039
2063
  disabled: isLoading || !email,
2040
2064
  className: "pollar-btn-primary",
2041
- style: { marginTop: "0.75rem", width: "100%" },
2065
+ style: { marginTop: "0.75rem" },
2042
2066
  onClick: onEmailSubmit,
2043
2067
  children: "Submit"
2044
2068
  }
@@ -2053,32 +2077,45 @@ function LoginModalTemplate({
2053
2077
  enabledSocial.some(([key]) => key === "github") && /* @__PURE__ */ jsx(GithubButton, { disabled: isLoading, onClick: () => onSocialLogin?.("github") })
2054
2078
  ] }),
2055
2079
  (embeddedWallets || smartWallet) && /* @__PURE__ */ jsxs("div", { className: "pollar-wallet-section", children: [
2056
- embeddedWallets && /* @__PURE__ */ jsxs(
2057
- "button",
2058
- {
2059
- type: "button",
2060
- disabled: isLoading,
2061
- className: "pollar-wallet-entry-btn",
2062
- onClick: () => setShowWalletPicker(true),
2063
- children: [
2064
- /* @__PURE__ */ jsx(
2065
- "svg",
2066
- {
2067
- width: "18",
2068
- height: "20",
2069
- viewBox: "0 0 24 24",
2070
- fill: "none",
2071
- stroke: "currentColor",
2072
- strokeWidth: "2",
2073
- strokeLinecap: "round",
2074
- strokeLinejoin: "round",
2075
- children: /* @__PURE__ */ jsx("path", { d: "M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" })
2076
- }
2077
- ),
2078
- "Wallet"
2079
- ]
2080
- }
2081
- ),
2080
+ embeddedWallets && /* @__PURE__ */ jsxs(Fragment, { children: [
2081
+ walletGroups.map((g) => /* @__PURE__ */ jsxs(
2082
+ "button",
2083
+ {
2084
+ type: "button",
2085
+ disabled: isLoading,
2086
+ className: "pollar-wallet-entry-btn",
2087
+ onClick: () => setActiveGroup(g.label),
2088
+ children: [
2089
+ /* @__PURE__ */ jsx(
2090
+ "svg",
2091
+ {
2092
+ width: "18",
2093
+ height: "20",
2094
+ viewBox: "0 0 24 24",
2095
+ fill: "none",
2096
+ stroke: "currentColor",
2097
+ strokeWidth: "2",
2098
+ strokeLinecap: "round",
2099
+ strokeLinejoin: "round",
2100
+ children: /* @__PURE__ */ jsx("path", { d: "M3 10h18M7 15h1m4 0h1m-7 4h12a3 3 0 003-3V8a3 3 0 00-3-3H6a3 3 0 00-3 3v8a3 3 0 003 3z" })
2101
+ }
2102
+ ),
2103
+ g.label
2104
+ ]
2105
+ },
2106
+ g.label
2107
+ )),
2108
+ rootAdapters.length > 0 && /* @__PURE__ */ jsx(
2109
+ WalletAdapterButtons,
2110
+ {
2111
+ walletAdapters: rootAdapters,
2112
+ onConnect: onWalletConnect ?? (() => {
2113
+ }),
2114
+ isLoading,
2115
+ variant: "entry"
2116
+ }
2117
+ )
2118
+ ] }),
2082
2119
  smartWallet && /* @__PURE__ */ jsxs(
2083
2120
  "button",
2084
2121
  {
@@ -2119,12 +2156,142 @@ function LoginModalTemplate({
2119
2156
  /* @__PURE__ */ jsx(PollarModalFooter, {})
2120
2157
  ] });
2121
2158
  }
2159
+ function PrivyLoginSubmodal({
2160
+ adapter,
2161
+ theme,
2162
+ accentColor,
2163
+ logoUrl,
2164
+ appName,
2165
+ onBack,
2166
+ onCancel,
2167
+ onAuthenticated
2168
+ }) {
2169
+ const options = useMemo(() => adapter.getAuthOptions(), [adapter]);
2170
+ const [email, setEmail] = useState("");
2171
+ const [view, setView] = useState("root");
2172
+ const [status, setStatus] = useState("NONE");
2173
+ const [message, setMessage] = useState("");
2174
+ const isDark = theme === "dark";
2175
+ const isLoading = status === "LOADING";
2176
+ const cssVars = {
2177
+ "--pollar-accent": accentColor,
2178
+ "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
2179
+ "--pollar-border": isDark ? "#374151" : "#e5e7eb",
2180
+ "--pollar-text": isDark ? "#ffffff" : "#111827",
2181
+ "--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
2182
+ "--pollar-input-bg": isDark ? "#374151" : "#f9fafb",
2183
+ "--pollar-error-bg": isDark ? "#2a1515" : "#fef2f2",
2184
+ "--pollar-error-border": isDark ? "#7f1d1d" : "#fecaca",
2185
+ "--pollar-error-text": isDark ? "#f87171" : "#dc2626",
2186
+ "--pollar-success-text": isDark ? "#4ade80" : "#16a34a",
2187
+ "--pollar-buttons-border-radius": "6px",
2188
+ "--pollar-buttons-height": "44px",
2189
+ "--pollar-input-height": "44px",
2190
+ "--pollar-input-border-radius": "0.5rem",
2191
+ "--pollar-card-border-radius": "10px",
2192
+ "--pollar-modal-padding": "2rem",
2193
+ "--pollar-modal-heading-size": "1.375rem",
2194
+ "--pollar-modal-subtitle-size": "0.9rem"
2195
+ };
2196
+ function fail(error) {
2197
+ setStatus("ERROR");
2198
+ setMessage(error instanceof Error ? error.message : "Something went wrong. Please try again.");
2199
+ }
2200
+ async function handleEmailSubmit() {
2201
+ if (!email) return;
2202
+ setStatus("LOADING");
2203
+ setMessage("");
2204
+ try {
2205
+ await adapter.sendEmailCode(email);
2206
+ setStatus("SUCCESS");
2207
+ setMessage("Code sent \u2014 check your inbox");
2208
+ setView("email-code");
2209
+ } catch (error) {
2210
+ fail(error);
2211
+ }
2212
+ }
2213
+ async function handleCodeSubmit(code) {
2214
+ setStatus("LOADING");
2215
+ setMessage("Verifying\u2026");
2216
+ try {
2217
+ await adapter.verifyEmailCode(code);
2218
+ onAuthenticated();
2219
+ } catch (error) {
2220
+ fail(error);
2221
+ }
2222
+ }
2223
+ async function handleOAuth(provider) {
2224
+ setStatus("LOADING");
2225
+ setMessage("");
2226
+ try {
2227
+ await adapter.loginWithOAuth(provider);
2228
+ onAuthenticated();
2229
+ } catch (error) {
2230
+ fail(error);
2231
+ }
2232
+ }
2233
+ const BackButton = ({ onClick }) => /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-back-btn", onClick, "aria-label": "Back", children: /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M15 19l-7-7 7-7" }) }) });
2234
+ const showEmail = options.includes("email");
2235
+ const showGoogle = options.includes("google");
2236
+ const showGithub = options.includes("github");
2237
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-modal-card pollar-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
2238
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-close-btn", onClick: onCancel, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) }),
2239
+ /* @__PURE__ */ jsxs("div", { className: "pollar-header", children: [
2240
+ /* @__PURE__ */ jsx("div", { className: "pollar-logo-wrap", children: /* @__PURE__ */ jsx("img", { src: logoUrl ?? LOGO_POLLAR, alt: "Logo", className: "pollar-logo" }) }),
2241
+ /* @__PURE__ */ jsx("h2", { className: "pollar-title", children: appName }),
2242
+ /* @__PURE__ */ jsx("p", { className: "pollar-subtitle", children: adapter.meta.label })
2243
+ ] }),
2244
+ view === "email-code" ? /* @__PURE__ */ jsxs(Fragment, { children: [
2245
+ /* @__PURE__ */ jsx(BackButton, { onClick: () => setView("root") }),
2246
+ /* @__PURE__ */ jsx(EmailCodeInput, { email, onSubmit: handleCodeSubmit })
2247
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2248
+ /* @__PURE__ */ jsx(BackButton, { onClick: onBack }),
2249
+ showEmail && /* @__PURE__ */ jsxs("div", { className: "pollar-email-section", children: [
2250
+ /* @__PURE__ */ jsx(
2251
+ "input",
2252
+ {
2253
+ type: "email",
2254
+ placeholder: "you@email.com",
2255
+ value: email,
2256
+ disabled: isLoading,
2257
+ className: "pollar-email-input",
2258
+ onChange: (e) => setEmail(e.target.value),
2259
+ onKeyDown: (e) => e.key === "Enter" && handleEmailSubmit()
2260
+ }
2261
+ ),
2262
+ /* @__PURE__ */ jsx(
2263
+ "button",
2264
+ {
2265
+ type: "button",
2266
+ disabled: isLoading || !email,
2267
+ className: "pollar-btn-primary",
2268
+ style: { marginTop: "0.75rem" },
2269
+ onClick: handleEmailSubmit,
2270
+ children: "Submit"
2271
+ }
2272
+ )
2273
+ ] }),
2274
+ showEmail && (showGoogle || showGithub) && /* @__PURE__ */ jsxs("div", { className: "pollar-divider", children: [
2275
+ /* @__PURE__ */ jsx("div", { className: "pollar-divider-line" }),
2276
+ /* @__PURE__ */ jsx("div", { className: "pollar-divider-label", children: /* @__PURE__ */ jsx("span", { className: "pollar-divider-text", children: "or continue with" }) })
2277
+ ] }),
2278
+ (showGoogle || showGithub) && /* @__PURE__ */ jsxs("div", { className: "pollar-social-list", children: [
2279
+ showGoogle && /* @__PURE__ */ jsx(GoogleButton, { disabled: isLoading, onClick: () => handleOAuth("google") }),
2280
+ showGithub && /* @__PURE__ */ jsx(GithubButton, { disabled: isLoading, onClick: () => handleOAuth("github") })
2281
+ ] })
2282
+ ] }),
2283
+ /* @__PURE__ */ jsx(ModalStatusBanner, { message, status, onCancel, onRetry: void 0 }),
2284
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
2285
+ ] });
2286
+ }
2122
2287
  function LoginModal({ onClose }) {
2123
2288
  const [email, setEmail] = useState("");
2124
- const { getClient, styles, appConfig: config, renderWallets } = usePollar();
2289
+ const { getClient, styles, appConfig: config } = usePollar();
2125
2290
  const [authState, setAuthState] = useState(() => getClient().getAuthState());
2291
+ const walletAdapters = useMemo(() => getClient().listWalletAdapters(), [getClient]);
2126
2292
  const [codeInputKey, setCodeInputKey] = useState(0);
2127
2293
  const pendingEmail = useRef(null);
2294
+ const [interactiveAdapter, setInteractiveAdapter] = useState(null);
2128
2295
  const onCloseRef = useRef(onClose);
2129
2296
  onCloseRef.current = onClose;
2130
2297
  const autoCloseTimer = useRef(null);
@@ -2172,7 +2339,12 @@ function LoginModal({ onClose }) {
2172
2339
  getClient().login({ provider });
2173
2340
  }
2174
2341
  function handleWalletConnect(type) {
2175
- getClient().loginWallet(type);
2342
+ const adapter = getClient().getWalletAdapter(type);
2343
+ if (isInteractiveAuthAdapter(adapter)) {
2344
+ setInteractiveAdapter(adapter);
2345
+ return;
2346
+ }
2347
+ getClient().login({ provider: type });
2176
2348
  }
2177
2349
  function handleLoginSmartWallet() {
2178
2350
  getClient().loginSmartWallet();
@@ -2193,7 +2365,26 @@ function LoginModal({ onClose }) {
2193
2365
  getClient().beginEmailLogin();
2194
2366
  }
2195
2367
  }
2196
- return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: handleClose, children: /* @__PURE__ */ jsx(
2368
+ function handleInteractiveAuthenticated() {
2369
+ const provider = interactiveAdapter?.type;
2370
+ setInteractiveAdapter(null);
2371
+ if (provider) {
2372
+ getClient().login({ provider });
2373
+ }
2374
+ }
2375
+ return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: handleClose, children: interactiveAdapter ? /* @__PURE__ */ jsx(
2376
+ PrivyLoginSubmodal,
2377
+ {
2378
+ adapter: interactiveAdapter,
2379
+ theme,
2380
+ accentColor,
2381
+ logoUrl: logoUrl ?? null,
2382
+ appName: config.application?.name ?? "Pollar",
2383
+ onBack: () => setInteractiveAdapter(null),
2384
+ onCancel: handleClose,
2385
+ onAuthenticated: handleInteractiveAuthenticated
2386
+ }
2387
+ ) : /* @__PURE__ */ jsx(
2197
2388
  LoginModalTemplate,
2198
2389
  {
2199
2390
  theme,
@@ -2209,6 +2400,7 @@ function LoginModal({ onClose }) {
2209
2400
  github: !!providers?.github,
2210
2401
  apple: !!providers?.apple
2211
2402
  },
2403
+ walletAdapters,
2212
2404
  appName: config.application?.name ?? "Pollar",
2213
2405
  email,
2214
2406
  onEmailChange: setEmail,
@@ -2217,7 +2409,6 @@ function LoginModal({ onClose }) {
2217
2409
  onWalletConnect: handleWalletConnect,
2218
2410
  onLoginSmartWallet: handleLoginSmartWallet,
2219
2411
  onCreateSmartWallet: handleCreateSmartWallet,
2220
- ...renderWallets !== void 0 && { renderWallets },
2221
2412
  authState,
2222
2413
  codeInputKey,
2223
2414
  onCodeSubmit: handleVerifyCode,
@@ -2274,6 +2465,12 @@ var COUNTRY_CURRENCIES = {
2274
2465
  PE: "PEN",
2275
2466
  AR: "ARS"
2276
2467
  };
2468
+ var STATUS_LABEL = {
2469
+ pending: "Pending",
2470
+ processing: "Processing",
2471
+ completed: "Completed",
2472
+ failed: "Failed"
2473
+ };
2277
2474
  function RampWidgetTemplate({
2278
2475
  theme,
2279
2476
  accentColor,
@@ -2283,15 +2480,23 @@ function RampWidgetTemplate({
2283
2480
  currency,
2284
2481
  country,
2285
2482
  quotes,
2286
- paymentInstructions,
2287
2483
  isLoading,
2484
+ provider,
2485
+ txStatus,
2486
+ kycUrl,
2487
+ stellarTxHash,
2488
+ canComplete,
2489
+ completing,
2490
+ errorMsg,
2288
2491
  onDirectionChange,
2289
2492
  onAmountChange,
2290
2493
  onCurrencyChange,
2291
2494
  onCountryChange,
2292
2495
  onFindRoute,
2293
2496
  onSelectQuote,
2294
- onCopy,
2497
+ onOpenKyc,
2498
+ onCompleteWithdraw,
2499
+ onRetry,
2295
2500
  onClose
2296
2501
  }) {
2297
2502
  const isDark = theme === "dark";
@@ -2319,13 +2524,15 @@ function RampWidgetTemplate({
2319
2524
  input: direction === "onramp" ? "Buy crypto" : "Sell crypto",
2320
2525
  loading_quote: "Finding best route",
2321
2526
  select_route: "Select provider",
2322
- payment_instructions: "Payment instructions"
2527
+ status: direction === "onramp" ? "Complete your deposit" : "Complete your withdrawal",
2528
+ error: "Something went wrong"
2323
2529
  };
2324
2530
  const stepSubtitle = {
2325
2531
  input: direction === "onramp" ? "Enter the amount you want to deposit" : "Enter the amount you want to withdraw",
2326
2532
  loading_quote: "Comparing providers in real time\u2026",
2327
2533
  select_route: "All prices include fees",
2328
- payment_instructions: "Send the exact amount to complete your transaction"
2534
+ status: `Finish the flow at ${provider || "the provider"} to continue`,
2535
+ error: "Please try again"
2329
2536
  };
2330
2537
  return /* @__PURE__ */ jsxs("div", { className: "pollar-modal-card pollar-ramp-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
2331
2538
  /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-header", children: [
@@ -2421,182 +2628,183 @@ function RampWidgetTemplate({
2421
2628
  /* @__PURE__ */ jsx("div", { className: "pollar-ramp-route-list", children: quotes.map((q, i) => /* @__PURE__ */ jsx(RouteDisplay, { quote: q, onSelect: onSelectQuote }, i)) }),
2422
2629
  /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Cancel" })
2423
2630
  ] }),
2424
- step === "payment_instructions" && paymentInstructions && /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment", children: [
2425
- /* @__PURE__ */ jsx("p", { className: "pollar-ramp-payment-title", children: paymentInstructions.type }),
2631
+ step === "status" && /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment", children: [
2426
2632
  /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-field", children: [
2427
- /* @__PURE__ */ jsx("span", { className: "pollar-ramp-payment-label", children: paymentInstructions.type === "CLABE" ? "CLABE number" : paymentInstructions.type === "PIX" ? "PIX key" : "Account number" }),
2428
- /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-value", children: [
2429
- /* @__PURE__ */ jsx("code", { children: paymentInstructions.value }),
2430
- /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-ramp-copy-btn", onClick: () => onCopy(paymentInstructions.value), children: "Copy" })
2431
- ] })
2633
+ /* @__PURE__ */ jsx("span", { className: "pollar-ramp-payment-label", children: "Provider" }),
2634
+ /* @__PURE__ */ jsx("div", { className: "pollar-ramp-payment-value", children: /* @__PURE__ */ jsx("code", { children: provider }) })
2432
2635
  ] }),
2433
2636
  /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-field", children: [
2434
- /* @__PURE__ */ jsx("span", { className: "pollar-ramp-payment-label", children: "Amount to send" }),
2435
- /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-value", children: [
2436
- /* @__PURE__ */ jsxs("code", { children: [
2437
- paymentInstructions.amount.toLocaleString(),
2438
- " ",
2439
- paymentInstructions.currency
2440
- ] }),
2441
- /* @__PURE__ */ jsx(
2442
- "button",
2443
- {
2444
- type: "button",
2445
- className: "pollar-ramp-copy-btn",
2446
- onClick: () => onCopy(`${paymentInstructions.amount} ${paymentInstructions.currency}`),
2447
- children: "Copy"
2448
- }
2449
- )
2450
- ] })
2637
+ /* @__PURE__ */ jsx("span", { className: "pollar-ramp-payment-label", children: "Status" }),
2638
+ /* @__PURE__ */ jsx("div", { className: "pollar-ramp-payment-value", children: /* @__PURE__ */ jsx(
2639
+ "code",
2640
+ {
2641
+ style: { color: txStatus === "completed" ? "var(--pollar-success-text)" : void 0 },
2642
+ children: txStatus ? STATUS_LABEL[txStatus] : "Processing"
2643
+ }
2644
+ ) })
2645
+ ] }),
2646
+ stellarTxHash && /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-field", children: [
2647
+ /* @__PURE__ */ jsx("span", { className: "pollar-ramp-payment-label", children: "Stellar tx" }),
2648
+ /* @__PURE__ */ jsx("div", { className: "pollar-ramp-payment-value", children: /* @__PURE__ */ jsxs("code", { children: [
2649
+ stellarTxHash.slice(0, 8),
2650
+ "\u2026",
2651
+ stellarTxHash.slice(-8)
2652
+ ] }) })
2451
2653
  ] }),
2452
- paymentInstructions.expiresAt && /* @__PURE__ */ jsxs("p", { className: "pollar-ramp-payment-note", children: [
2453
- "Instructions expire at ",
2454
- new Date(paymentInstructions.expiresAt).toLocaleTimeString()
2654
+ kycUrl && txStatus !== "completed" && /* @__PURE__ */ jsxs("button", { type: "button", className: "pollar-btn-primary", onClick: onOpenKyc, children: [
2655
+ "Continue at ",
2656
+ provider
2455
2657
  ] }),
2456
- /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onClose, children: "Done" })
2658
+ canComplete && /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-primary", disabled: completing, onClick: onCompleteWithdraw, children: completing ? "Submitting\u2026" : "I've completed KYC \u2014 withdraw" }),
2659
+ errorMsg && /* @__PURE__ */ jsx("p", { className: "pollar-ramp-payment-note", style: { color: "var(--pollar-error-text)" }, children: errorMsg }),
2660
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: txStatus === "completed" ? "Done" : "Close" })
2661
+ ] }),
2662
+ step === "error" && /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment", children: [
2663
+ /* @__PURE__ */ jsx("p", { className: "pollar-ramp-payment-note", style: { color: "var(--pollar-error-text)" }, children: errorMsg ?? "Unexpected error." }),
2664
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-actions", children: [
2665
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Close" }),
2666
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onRetry, children: "Try again" })
2667
+ ] })
2457
2668
  ] })
2458
2669
  ] });
2459
2670
  }
2460
- var MOCK_DEFAULT_QUOTES = [
2461
- {
2462
- quoteId: "meld-default",
2463
- provider: "Meld",
2464
- fee: 1.2,
2465
- feeCurrency: "USD",
2466
- rate: 1,
2467
- rail: "ACH",
2468
- protocol: "REST",
2469
- estimatedTime: "~20 min",
2470
- recommended: true
2471
- }
2472
- ];
2473
- var MOCK_QUOTES = {
2474
- MX: [
2475
- {
2476
- quoteId: "etherfuse-mx",
2477
- provider: "Etherfuse",
2478
- fee: 0.5,
2479
- feeCurrency: "MXN",
2480
- rate: 17.2,
2481
- rail: "SPEI",
2482
- protocol: "SEP-24",
2483
- estimatedTime: "~10 min",
2484
- recommended: true
2485
- },
2486
- {
2487
- quoteId: "alfredpay-mx",
2488
- provider: "AlfredPay",
2489
- fee: 0.8,
2490
- feeCurrency: "MXN",
2491
- rate: 17.1,
2492
- rail: "SPEI",
2493
- protocol: "REST",
2494
- estimatedTime: "~15 min",
2495
- recommended: false
2496
- }
2497
- ],
2498
- BR: [
2499
- {
2500
- quoteId: "abroad-br",
2501
- provider: "Abroad",
2502
- fee: 0.6,
2503
- feeCurrency: "BRL",
2504
- rate: 5.1,
2505
- rail: "PIX",
2506
- protocol: "REST",
2507
- estimatedTime: "~5 min",
2508
- recommended: true
2509
- }
2510
- ],
2511
- CO: [
2512
- {
2513
- quoteId: "abroad-co",
2514
- provider: "Abroad",
2515
- fee: 0.7,
2516
- feeCurrency: "COP",
2517
- rate: 4100,
2518
- rail: "PSE",
2519
- protocol: "REST",
2520
- estimatedTime: "~10 min",
2521
- recommended: true
2522
- },
2523
- {
2524
- quoteId: "koywe-co",
2525
- provider: "Koywe",
2526
- fee: 0.9,
2527
- feeCurrency: "COP",
2528
- rate: 4095,
2529
- rail: "PSE",
2530
- protocol: "REST",
2531
- estimatedTime: "~15 min",
2532
- recommended: false
2533
- }
2534
- ],
2535
- DEFAULT: MOCK_DEFAULT_QUOTES
2536
- };
2537
- var MOCK_PAYMENT = {
2538
- type: "CLABE",
2539
- value: "646180157088723456",
2540
- amount: 1e3,
2541
- currency: "MXN",
2542
- expiresAt: new Date(Date.now() + 30 * 60 * 1e3).toISOString()
2543
- };
2671
+ var TERMINAL = ["completed", "failed"];
2544
2672
  function RampWidget({ onClose }) {
2545
- const { getClient, walletAddress, styles } = usePollar();
2673
+ const { getClient, signTx, wallet, styles } = usePollar();
2674
+ const walletAddress = wallet?.address ?? "";
2675
+ const client = getClient();
2676
+ const { theme = "light", accentColor = "#005DB4" } = styles;
2546
2677
  const [step, setStep] = useState("input");
2547
2678
  const [direction, setDirection] = useState("onramp");
2548
2679
  const [amount, setAmount] = useState("");
2549
- const [currency, setCurrency] = useState("MXN");
2550
- const [country, setCountry] = useState("MX");
2680
+ const [currency, setCurrency] = useState("ARS");
2681
+ const [country, setCountry] = useState("AR");
2551
2682
  const [quotes, setQuotes] = useState([]);
2552
- const [paymentInstructions, setPaymentInstructions] = useState(null);
2553
2683
  const [isLoading, setIsLoading] = useState(false);
2554
- const client = getClient();
2555
- const { theme = "light", accentColor = "#005DB4" } = styles;
2684
+ const [txId, setTxId] = useState(null);
2685
+ const [provider, setProvider] = useState("");
2686
+ const [kycUrl, setKycUrl] = useState(null);
2687
+ const [txStatus, setTxStatus] = useState(null);
2688
+ const [stellarTxHash, setStellarTxHash] = useState(null);
2689
+ const [completing, setCompleting] = useState(false);
2690
+ const [errorMsg, setErrorMsg] = useState(null);
2691
+ const directionRef = useRef(direction);
2692
+ directionRef.current = direction;
2693
+ useEffect(() => {
2694
+ if (step !== "status" || !txId) return;
2695
+ if (txStatus && TERMINAL.includes(txStatus)) return;
2696
+ let active = true;
2697
+ const id = setInterval(async () => {
2698
+ try {
2699
+ const tx = await client.getRampTransaction(txId);
2700
+ if (!active) return;
2701
+ setTxStatus(tx.status);
2702
+ if (tx.stellarTxHash) setStellarTxHash(tx.stellarTxHash);
2703
+ if (tx.kycUrl) setKycUrl(tx.kycUrl);
2704
+ if (TERMINAL.includes(tx.status)) clearInterval(id);
2705
+ } catch {
2706
+ }
2707
+ }, 5e3);
2708
+ return () => {
2709
+ active = false;
2710
+ clearInterval(id);
2711
+ };
2712
+ }, [step, txId, txStatus, client]);
2713
+ function resetToInput() {
2714
+ setStep("input");
2715
+ setQuotes([]);
2716
+ setTxId(null);
2717
+ setProvider("");
2718
+ setKycUrl(null);
2719
+ setTxStatus(null);
2720
+ setStellarTxHash(null);
2721
+ setErrorMsg(null);
2722
+ }
2723
+ async function resumeWithSignature(id, ps) {
2724
+ const outcome = await signTx(ps.unsignedXdr);
2725
+ if (outcome.status !== "signed") {
2726
+ setErrorMsg(outcome.message ?? outcome.details ?? "Signing was cancelled.");
2727
+ setStep("error");
2728
+ return;
2729
+ }
2730
+ const result = await client.submitRampSignature(id, {
2731
+ signedXdr: outcome.signedXdr,
2732
+ action: ps.action
2733
+ });
2734
+ await applyResult(result);
2735
+ }
2736
+ async function applyResult(result) {
2737
+ setTxId(result.txId);
2738
+ setProvider(result.provider);
2739
+ if (result.pendingSignature) {
2740
+ await resumeWithSignature(result.txId, result.pendingSignature);
2741
+ return;
2742
+ }
2743
+ setKycUrl(result.kycUrl ?? null);
2744
+ setTxStatus(result.status);
2745
+ setStellarTxHash(result.stellarTxHash ?? null);
2746
+ setStep("status");
2747
+ }
2556
2748
  async function handleFindRoute() {
2557
2749
  setStep("loading_quote");
2558
2750
  setIsLoading(true);
2751
+ setErrorMsg(null);
2559
2752
  try {
2560
- const result = await client.getRampsQuote({
2561
- country,
2562
- amount: Number(amount),
2563
- currency,
2564
- direction
2565
- });
2566
- if (result.quotes) setQuotes(result.quotes);
2567
- } catch {
2568
- await new Promise((r) => setTimeout(r, 1500));
2569
- setQuotes(MOCK_QUOTES[country] ?? MOCK_DEFAULT_QUOTES);
2753
+ const result = await client.getRampsQuote({ country, amount: Number(amount), currency, direction });
2754
+ const list = result.quotes ?? [];
2755
+ if (list.length === 0) {
2756
+ setErrorMsg(`No ramp providers available for ${country} yet.`);
2757
+ setStep("error");
2758
+ return;
2759
+ }
2760
+ setQuotes(list);
2761
+ setStep("select_route");
2762
+ } catch (e) {
2763
+ setErrorMsg(e instanceof Error ? e.message : "Failed to fetch quotes.");
2764
+ setStep("error");
2570
2765
  } finally {
2571
2766
  setIsLoading(false);
2572
- setStep("select_route");
2573
2767
  }
2574
2768
  }
2575
2769
  async function handleSelectQuote(quote) {
2576
- if (!walletAddress) return;
2577
2770
  setIsLoading(true);
2578
- const body = {
2579
- quoteId: `${quote.provider}-${Date.now()}`,
2580
- amount: Number(amount),
2581
- currency,
2582
- country,
2583
- walletAddress
2584
- };
2771
+ setErrorMsg(null);
2585
2772
  try {
2586
- const result = await client.createOnRamp(body);
2587
- setPaymentInstructions(result.paymentInstructions);
2588
- } catch {
2589
- await new Promise((r) => setTimeout(r, 800));
2590
- setPaymentInstructions({ ...MOCK_PAYMENT, currency });
2773
+ const base = { quoteId: quote.quoteId, amount: Number(amount), currency, country };
2774
+ const result = direction === "onramp" ? await client.createOnRamp({ ...base, ...walletAddress ? { walletAddress } : {} }) : await client.createOffRamp({ ...base, ...walletAddress ? { walletAddress } : {} });
2775
+ await applyResult(result);
2776
+ } catch (e) {
2777
+ setErrorMsg(e instanceof Error ? e.message : "Failed to start the ramp.");
2778
+ setStep("error");
2591
2779
  } finally {
2592
2780
  setIsLoading(false);
2593
- setStep("payment_instructions");
2594
2781
  }
2595
2782
  }
2596
- function handleCopy(value) {
2597
- navigator.clipboard.writeText(value).catch(() => {
2598
- });
2783
+ function handleOpenKyc() {
2784
+ if (kycUrl) window.open(kycUrl, "_blank", "noopener,noreferrer");
2785
+ }
2786
+ async function handleCompleteWithdraw() {
2787
+ if (!txId) return;
2788
+ setCompleting(true);
2789
+ setErrorMsg(null);
2790
+ try {
2791
+ const result = await client.completeWithdraw(txId);
2792
+ if (result.pendingSignature) {
2793
+ await resumeWithSignature(txId, result.pendingSignature);
2794
+ return;
2795
+ }
2796
+ setTxStatus(result.status);
2797
+ setStellarTxHash(result.stellarTxHash ?? null);
2798
+ } catch (e) {
2799
+ const msg = e instanceof Error ? e.message : "";
2800
+ setErrorMsg(
2801
+ msg.includes("KYC") ? "Finish KYC at the provider first, then try again." : msg || "Failed to complete the withdrawal."
2802
+ );
2803
+ } finally {
2804
+ setCompleting(false);
2805
+ }
2599
2806
  }
2807
+ const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash;
2600
2808
  return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsx(
2601
2809
  RampWidgetTemplate,
2602
2810
  {
@@ -2608,15 +2816,23 @@ function RampWidget({ onClose }) {
2608
2816
  currency,
2609
2817
  country,
2610
2818
  quotes,
2611
- paymentInstructions,
2612
2819
  isLoading,
2820
+ provider,
2821
+ txStatus,
2822
+ kycUrl,
2823
+ stellarTxHash,
2824
+ canComplete,
2825
+ completing,
2826
+ errorMsg,
2613
2827
  onDirectionChange: setDirection,
2614
2828
  onAmountChange: setAmount,
2615
2829
  onCurrencyChange: setCurrency,
2616
2830
  onCountryChange: setCountry,
2617
2831
  onFindRoute: handleFindRoute,
2618
2832
  onSelectQuote: handleSelectQuote,
2619
- onCopy: handleCopy,
2833
+ onOpenKyc: handleOpenKyc,
2834
+ onCompleteWithdraw: handleCompleteWithdraw,
2835
+ onRetry: resetToInput,
2620
2836
  onClose
2621
2837
  }
2622
2838
  ) });
@@ -2745,7 +2961,8 @@ function ReceiveModalTemplate({
2745
2961
  );
2746
2962
  }
2747
2963
  function ReceiveModal({ onClose }) {
2748
- const { walletAddress, styles } = usePollar();
2964
+ const { wallet, styles } = usePollar();
2965
+ const walletAddress = wallet?.address ?? "";
2749
2966
  const { theme = "light", accentColor = "#005DB4" } = styles;
2750
2967
  const [copied, setCopied] = useState(false);
2751
2968
  const copyTimerRef = useRef(null);
@@ -3153,10 +3370,11 @@ function SendModal({ onClose }) {
3153
3370
  buildTx,
3154
3371
  signAndSubmitTx,
3155
3372
  tx: transaction,
3156
- walletType,
3373
+ wallet,
3157
3374
  network,
3158
3375
  styles
3159
3376
  } = usePollar();
3377
+ const walletType = wallet?.custody === "external" ? wallet.provider : null;
3160
3378
  const { theme = "light", accentColor = "#005DB4" } = styles;
3161
3379
  const [step, setStep] = useState("form");
3162
3380
  const [amount, setAmount] = useState("");
@@ -3278,6 +3496,415 @@ function SendModal({ onClose }) {
3278
3496
  }
3279
3497
  ) });
3280
3498
  }
3499
+ function assetOptionKey(o) {
3500
+ return `${o.code}:${o.issuer ?? "native"}`;
3501
+ }
3502
+ var PROVIDER_LABELS = {
3503
+ auto: "Best price (auto)",
3504
+ aquarius: "Aquarius",
3505
+ soroswap: "Soroswap",
3506
+ sdex: "Stellar DEX"
3507
+ };
3508
+ var IMPLEMENTED_PROVIDERS = ["auto", "aquarius"];
3509
+ function formatAmount2(value) {
3510
+ const n = parseFloat(value);
3511
+ return isNaN(n) ? value : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
3512
+ }
3513
+ function SwapModalTemplate({
3514
+ theme,
3515
+ accentColor,
3516
+ step,
3517
+ txTitle,
3518
+ sellOptions,
3519
+ buyOptions,
3520
+ selectedSell,
3521
+ selectedBuy,
3522
+ amount,
3523
+ provider,
3524
+ providers,
3525
+ quote,
3526
+ quoteLoading,
3527
+ quoteError,
3528
+ formError,
3529
+ isLoadingData,
3530
+ smartUnsupported,
3531
+ transaction,
3532
+ showXdr,
3533
+ copied,
3534
+ explorerUrl,
3535
+ walletType,
3536
+ showBack,
3537
+ isInProgress,
3538
+ onClose,
3539
+ onBack,
3540
+ onSelectSell,
3541
+ onSelectBuy,
3542
+ onAmountChange,
3543
+ onProviderChange,
3544
+ onSwap,
3545
+ onToggleXdr,
3546
+ onCopyHash,
3547
+ onRetry,
3548
+ onDone
3549
+ }) {
3550
+ const isDark = theme === "dark";
3551
+ const cssVars = {
3552
+ "--pollar-accent": accentColor,
3553
+ "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
3554
+ "--pollar-border": isDark ? "#374151" : "#e5e7eb",
3555
+ "--pollar-text": isDark ? "#ffffff" : "#111827",
3556
+ "--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
3557
+ "--pollar-input-bg": isDark ? "#374151" : "#f9fafb",
3558
+ "--pollar-error-bg": isDark ? "#2a1515" : "#fef2f2",
3559
+ "--pollar-error-border": isDark ? "#7f1d1d" : "#fecaca",
3560
+ "--pollar-error-text": isDark ? "#f87171" : "#dc2626",
3561
+ "--pollar-success-text": isDark ? "#4ade80" : "#16a34a",
3562
+ "--pollar-buttons-border-radius": "6px",
3563
+ "--pollar-buttons-height": "44px",
3564
+ "--pollar-input-height": "44px",
3565
+ "--pollar-input-border-radius": "0.5rem",
3566
+ "--pollar-card-border-radius": "10px"
3567
+ };
3568
+ const sellKey = selectedSell ? assetOptionKey(selectedSell) : "";
3569
+ const buyKey = selectedBuy ? assetOptionKey(selectedBuy) : "";
3570
+ const canSwap = !smartUnsupported && !!selectedSell && !!selectedBuy && !!amount && !!quote && !quoteLoading && !isLoadingData;
3571
+ const title = step === "form" ? "Swap" : txTitle;
3572
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-modal-card pollar-send-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
3573
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
3574
+ /* @__PURE__ */ jsxs("div", { className: "pollar-send-header-left", children: [
3575
+ showBack && /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-modal-close", onClick: onBack, "aria-label": "Back", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M10 3L5 8l5 5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
3576
+ /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: title })
3577
+ ] }),
3578
+ !isInProgress && /* @__PURE__ */ jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) }) })
3579
+ ] }),
3580
+ step === "form" && /* @__PURE__ */ jsxs(Fragment, { children: [
3581
+ smartUnsupported && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: "Swaps are not yet available for smart (passkey) wallets." }),
3582
+ /* @__PURE__ */ jsxs("div", { className: "pollar-send-field", children: [
3583
+ /* @__PURE__ */ jsx("label", { className: "pollar-send-label", children: "You pay" }),
3584
+ isLoadingData ? /* @__PURE__ */ jsx("div", { className: "pollar-send-skeleton" }) : /* @__PURE__ */ jsxs(
3585
+ "select",
3586
+ {
3587
+ className: "pollar-input pollar-send-select",
3588
+ value: sellKey,
3589
+ onChange: (e) => {
3590
+ const found = sellOptions.find((o) => assetOptionKey(o) === e.target.value);
3591
+ if (found) onSelectSell(found);
3592
+ },
3593
+ children: [
3594
+ /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: "Select asset to sell" }),
3595
+ sellOptions.map((o) => /* @__PURE__ */ jsxs("option", { value: assetOptionKey(o), children: [
3596
+ o.code,
3597
+ o.available !== void 0 ? ` \u2014 ${formatAmount2(o.available)} available` : ""
3598
+ ] }, assetOptionKey(o)))
3599
+ ]
3600
+ }
3601
+ )
3602
+ ] }),
3603
+ /* @__PURE__ */ jsxs("div", { className: "pollar-send-field", children: [
3604
+ /* @__PURE__ */ jsxs("div", { className: "pollar-send-label-row", children: [
3605
+ /* @__PURE__ */ jsx("label", { className: "pollar-send-label", children: "Amount" }),
3606
+ selectedSell?.available !== void 0 && /* @__PURE__ */ jsxs("span", { className: "pollar-send-hint", children: [
3607
+ "Available: ",
3608
+ formatAmount2(selectedSell.available),
3609
+ " ",
3610
+ selectedSell.code
3611
+ ] })
3612
+ ] }),
3613
+ /* @__PURE__ */ jsx(
3614
+ "input",
3615
+ {
3616
+ className: "pollar-input",
3617
+ type: "text",
3618
+ inputMode: "decimal",
3619
+ placeholder: "0.00",
3620
+ value: amount,
3621
+ onChange: (e) => onAmountChange(e.target.value)
3622
+ }
3623
+ )
3624
+ ] }),
3625
+ /* @__PURE__ */ jsxs("div", { className: "pollar-send-field", children: [
3626
+ /* @__PURE__ */ jsx("label", { className: "pollar-send-label", children: "You receive" }),
3627
+ isLoadingData ? /* @__PURE__ */ jsx("div", { className: "pollar-send-skeleton" }) : /* @__PURE__ */ jsxs(
3628
+ "select",
3629
+ {
3630
+ className: "pollar-input pollar-send-select",
3631
+ value: buyKey,
3632
+ onChange: (e) => {
3633
+ const found = buyOptions.find((o) => assetOptionKey(o) === e.target.value);
3634
+ if (found) onSelectBuy(found);
3635
+ },
3636
+ children: [
3637
+ /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: "Select asset to buy" }),
3638
+ buyOptions.map((o) => /* @__PURE__ */ jsxs("option", { value: assetOptionKey(o), children: [
3639
+ o.code,
3640
+ o.enabledInApp ? "" : " (external)"
3641
+ ] }, assetOptionKey(o)))
3642
+ ]
3643
+ }
3644
+ )
3645
+ ] }),
3646
+ /* @__PURE__ */ jsxs("div", { className: "pollar-send-field", children: [
3647
+ /* @__PURE__ */ jsx("label", { className: "pollar-send-label", children: "Route" }),
3648
+ /* @__PURE__ */ jsx(
3649
+ "select",
3650
+ {
3651
+ className: "pollar-input pollar-send-select",
3652
+ value: provider,
3653
+ onChange: (e) => onProviderChange(e.target.value),
3654
+ children: providers.map((p) => {
3655
+ const implemented = IMPLEMENTED_PROVIDERS.includes(p);
3656
+ return /* @__PURE__ */ jsxs("option", { value: p, disabled: !implemented, children: [
3657
+ PROVIDER_LABELS[p],
3658
+ implemented ? "" : " (coming soon)"
3659
+ ] }, p);
3660
+ })
3661
+ }
3662
+ )
3663
+ ] }),
3664
+ quoteLoading && /* @__PURE__ */ jsx("div", { className: "pollar-send-hint", children: "Fetching best price\u2026" }),
3665
+ !quoteLoading && quoteError && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: quoteError }),
3666
+ !quoteLoading && !quoteError && quote && selectedBuy && /* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote", children: [
3667
+ /* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
3668
+ /* @__PURE__ */ jsx("span", { className: "pollar-send-hint", children: "You receive" }),
3669
+ /* @__PURE__ */ jsxs("span", { children: [
3670
+ "~ ",
3671
+ formatAmount2(quote.amountOut),
3672
+ " ",
3673
+ selectedBuy.code
3674
+ ] })
3675
+ ] }),
3676
+ /* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
3677
+ /* @__PURE__ */ jsx("span", { className: "pollar-send-hint", children: "Minimum received" }),
3678
+ /* @__PURE__ */ jsxs("span", { children: [
3679
+ formatAmount2(quote.minReceived),
3680
+ " ",
3681
+ selectedBuy.code
3682
+ ] })
3683
+ ] }),
3684
+ /* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
3685
+ /* @__PURE__ */ jsx("span", { className: "pollar-send-hint", children: "Price impact" }),
3686
+ /* @__PURE__ */ jsxs("span", { children: [
3687
+ quote.priceImpactPct,
3688
+ "%"
3689
+ ] })
3690
+ ] }),
3691
+ /* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
3692
+ /* @__PURE__ */ jsx("span", { className: "pollar-send-hint", children: "Route" }),
3693
+ /* @__PURE__ */ jsx("span", { children: PROVIDER_LABELS[quote.provider] })
3694
+ ] })
3695
+ ] }),
3696
+ !quoteLoading && !quoteError && !quote && selectedSell && selectedBuy && !!amount && /* @__PURE__ */ jsx("div", { className: "pollar-send-hint", children: "No route found for this pair." }),
3697
+ formError && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: formError }),
3698
+ /* @__PURE__ */ jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsx("button", { className: "pollar-btn-primary", onClick: onSwap, disabled: !canSwap, children: "Swap" }) })
3699
+ ] }),
3700
+ step === "tx" && /* @__PURE__ */ jsx(
3701
+ TxStatusView,
3702
+ {
3703
+ transaction,
3704
+ showXdr,
3705
+ copied,
3706
+ explorerUrl,
3707
+ walletType,
3708
+ onSignAndSend: () => {
3709
+ },
3710
+ onToggleXdr,
3711
+ onCopyHash,
3712
+ onRetry,
3713
+ onDone
3714
+ }
3715
+ ),
3716
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
3717
+ ] });
3718
+ }
3719
+ var QUOTE_DEBOUNCE_MS = 400;
3720
+ var ALL_PROVIDERS = ["auto", "aquarius", "soroswap", "sdex"];
3721
+ function toRef(a) {
3722
+ if (a.type === "native") return { type: "native" };
3723
+ if (a.type === "credit_alphanum4") return { type: "credit_alphanum4", code: a.code, issuer: a.issuer };
3724
+ return { type: "credit_alphanum12", code: a.code, issuer: a.issuer };
3725
+ }
3726
+ function SwapModal({ onClose }) {
3727
+ const {
3728
+ getSwapQuote,
3729
+ swap,
3730
+ walletBalance,
3731
+ refreshWalletBalance,
3732
+ enabledAssets,
3733
+ refreshAssets,
3734
+ tx: transaction,
3735
+ wallet,
3736
+ network,
3737
+ styles
3738
+ } = usePollar();
3739
+ const walletType = wallet?.custody === "external" ? wallet.provider : null;
3740
+ const smartUnsupported = wallet?.custody === "smart";
3741
+ const { theme = "light", accentColor = "#005DB4" } = styles;
3742
+ const [step, setStep] = useState("form");
3743
+ const [selectedSell, setSelectedSell] = useState(null);
3744
+ const [selectedBuy, setSelectedBuy] = useState(null);
3745
+ const [amount, setAmount] = useState("");
3746
+ const [provider, setProvider] = useState("auto");
3747
+ const [quotes, setQuotes] = useState([]);
3748
+ const [quoteLoading, setQuoteLoading] = useState(false);
3749
+ const [quoteError, setQuoteError] = useState("");
3750
+ const [formError, setFormError] = useState("");
3751
+ const [showXdr, setShowXdr] = useState(false);
3752
+ const [copied, setCopied] = useState(false);
3753
+ const copyTimerRef = useRef(null);
3754
+ const slippageBps = 50;
3755
+ useEffect(() => {
3756
+ void refreshWalletBalance();
3757
+ void refreshAssets();
3758
+ }, [refreshWalletBalance, refreshAssets]);
3759
+ useEffect(
3760
+ () => () => {
3761
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
3762
+ },
3763
+ []
3764
+ );
3765
+ const balances = walletBalance.step === "loaded" ? walletBalance.data.balances : [];
3766
+ const assetRecords = enabledAssets.step === "loaded" ? enabledAssets.data.assets : [];
3767
+ const isLoadingData = walletBalance.step === "loading" || enabledAssets.step === "loading";
3768
+ const sellOptions = balances.filter((b) => parseFloat(b.available) > 0).map((b) => ({ ref: toRef(b), code: b.code, issuer: b.issuer, available: b.available, enabledInApp: b.enabledInApp }));
3769
+ const buyKeyOfSell = selectedSell ? `${selectedSell.code}:${selectedSell.issuer ?? "native"}` : "";
3770
+ const buyOptions = assetRecords.map((a) => ({ ref: toRef(a), code: a.code, issuer: a.issuer, enabledInApp: a.enabledInApp })).filter((o) => `${o.code}:${o.issuer ?? "native"}` !== buyKeyOfSell);
3771
+ const providers = smartUnsupported ? ALL_PROVIDERS.filter((p) => p !== "sdex") : ALL_PROVIDERS;
3772
+ const quote = quotes[0] ?? null;
3773
+ useEffect(() => {
3774
+ if (step !== "form" || !selectedSell || !selectedBuy || !amount || parseFloat(amount) <= 0) {
3775
+ setQuotes([]);
3776
+ setQuoteError("");
3777
+ setQuoteLoading(false);
3778
+ return;
3779
+ }
3780
+ let cancelled = false;
3781
+ setQuoteLoading(true);
3782
+ setQuoteError("");
3783
+ const t = setTimeout(async () => {
3784
+ try {
3785
+ const qs = await getSwapQuote({
3786
+ sellAsset: selectedSell.ref,
3787
+ buyAsset: selectedBuy.ref,
3788
+ amount,
3789
+ provider,
3790
+ slippageBps
3791
+ });
3792
+ if (!cancelled) setQuotes(qs);
3793
+ } catch (e) {
3794
+ if (!cancelled) {
3795
+ setQuotes([]);
3796
+ setQuoteError(e instanceof Error ? e.message : "Failed to fetch quote");
3797
+ }
3798
+ } finally {
3799
+ if (!cancelled) setQuoteLoading(false);
3800
+ }
3801
+ }, QUOTE_DEBOUNCE_MS);
3802
+ return () => {
3803
+ cancelled = true;
3804
+ clearTimeout(t);
3805
+ };
3806
+ }, [step, selectedSell, selectedBuy, amount, provider, getSwapQuote]);
3807
+ const hash = transaction.step === "success" ? transaction.hash : null;
3808
+ const buildData = "buildData" in transaction ? transaction.buildData : null;
3809
+ const explorerNetwork = buildData?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : buildData ? "public" : network === "testnet" ? "testnet" : "public";
3810
+ const explorerUrl = hash ? `https://stellar.expert/explorer/${explorerNetwork}/tx/${hash}` : null;
3811
+ const IN_FLIGHT_STEPS2 = [
3812
+ "building",
3813
+ "signing",
3814
+ "submitting",
3815
+ "submitted",
3816
+ "signing-submitting",
3817
+ "building-signing-submitting"
3818
+ ];
3819
+ const isInProgress = IN_FLIGHT_STEPS2.includes(transaction.step);
3820
+ const showBack = step === "tx" && (transaction.step === "error" || transaction.step === "success") && !isInProgress;
3821
+ const txTitle = isInProgress ? "Swapping\u2026" : transaction.step === "success" ? "Swapped!" : transaction.step === "error" ? "Swap failed" : "Confirm Swap";
3822
+ async function handleSwap() {
3823
+ setFormError("");
3824
+ if (smartUnsupported) {
3825
+ setFormError("Swaps are not yet supported for smart (passkey) wallets");
3826
+ return;
3827
+ }
3828
+ if (!selectedSell || !selectedBuy) {
3829
+ setFormError("Select both assets");
3830
+ return;
3831
+ }
3832
+ const parsed = parseFloat(amount);
3833
+ if (!amount || isNaN(parsed) || parsed <= 0) {
3834
+ setFormError("Enter a valid amount");
3835
+ return;
3836
+ }
3837
+ if (selectedSell.available !== void 0 && parsed > parseFloat(selectedSell.available)) {
3838
+ setFormError("Insufficient balance");
3839
+ return;
3840
+ }
3841
+ if (!quote) {
3842
+ setFormError("No route available for this pair");
3843
+ return;
3844
+ }
3845
+ setStep("tx");
3846
+ await swap(quote);
3847
+ }
3848
+ async function handleRetry() {
3849
+ if (transaction.step === "error" && quote) await swap(quote);
3850
+ }
3851
+ function handleCopyHash() {
3852
+ if (!hash) return;
3853
+ navigator.clipboard.writeText(hash).then(() => {
3854
+ setCopied(true);
3855
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
3856
+ copyTimerRef.current = setTimeout(() => {
3857
+ copyTimerRef.current = null;
3858
+ setCopied(false);
3859
+ }, 2e3);
3860
+ });
3861
+ }
3862
+ function handleBack() {
3863
+ setStep("form");
3864
+ setShowXdr(false);
3865
+ setCopied(false);
3866
+ }
3867
+ return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: !isInProgress ? onClose : void 0, children: /* @__PURE__ */ jsx(
3868
+ SwapModalTemplate,
3869
+ {
3870
+ theme,
3871
+ accentColor,
3872
+ step,
3873
+ txTitle,
3874
+ sellOptions,
3875
+ buyOptions,
3876
+ selectedSell,
3877
+ selectedBuy,
3878
+ amount,
3879
+ provider,
3880
+ providers,
3881
+ quote,
3882
+ quoteLoading,
3883
+ quoteError,
3884
+ formError,
3885
+ isLoadingData,
3886
+ smartUnsupported,
3887
+ transaction,
3888
+ showXdr,
3889
+ copied,
3890
+ explorerUrl,
3891
+ walletType,
3892
+ showBack,
3893
+ isInProgress,
3894
+ onClose,
3895
+ onBack: handleBack,
3896
+ onSelectSell: setSelectedSell,
3897
+ onSelectBuy: setSelectedBuy,
3898
+ onAmountChange: setAmount,
3899
+ onProviderChange: setProvider,
3900
+ onSwap: () => void handleSwap(),
3901
+ onToggleXdr: () => setShowXdr((v) => !v),
3902
+ onCopyHash: handleCopyHash,
3903
+ onRetry: () => void handleRetry(),
3904
+ onDone: onClose
3905
+ }
3906
+ ) });
3907
+ }
3281
3908
  function describeDevice(s) {
3282
3909
  if (s.deviceLabel) return s.deviceLabel;
3283
3910
  if (!s.userAgent) return "Unknown device";
@@ -3565,7 +4192,8 @@ function TransactionModalTemplate({
3565
4192
  ] });
3566
4193
  }
3567
4194
  function TransactionModal({ onClose }) {
3568
- const { getClient, styles, tx: transaction, network, walletType } = usePollar();
4195
+ const { getClient, styles, tx: transaction, network, wallet } = usePollar();
4196
+ const walletType = wallet?.custody === "external" ? wallet.provider : null;
3569
4197
  const { theme = "light", accentColor = "#005DB4" } = styles;
3570
4198
  const [showXdr, setShowXdr] = useState(false);
3571
4199
  const [copied, setCopied] = useState(false);
@@ -3887,7 +4515,8 @@ function WalletBalanceModalTemplate({
3887
4515
  ] });
3888
4516
  }
3889
4517
  function WalletBalanceModal({ onClose }) {
3890
- const { walletBalance, refreshWalletBalance, walletAddress, styles } = usePollar();
4518
+ const { walletBalance, refreshWalletBalance, wallet, styles } = usePollar();
4519
+ const walletAddress = wallet?.address ?? "";
3891
4520
  const { theme = "light", accentColor = "#005DB4" } = styles;
3892
4521
  useEffect(() => {
3893
4522
  void refreshWalletBalance();
@@ -3970,7 +4599,6 @@ var PollarContext = createContext(null);
3970
4599
  function PollarProvider({
3971
4600
  client,
3972
4601
  appConfig: appConfigProp,
3973
- ui,
3974
4602
  adapters,
3975
4603
  onStorageDegrade,
3976
4604
  children
@@ -4022,6 +4650,30 @@ function PollarProvider({
4022
4650
  }
4023
4651
  });
4024
4652
  }, [pollarClient]);
4653
+ const sessionRef = useRef(sessionState);
4654
+ sessionRef.current = sessionState;
4655
+ useEffect(() => {
4656
+ const unsubscribes = [];
4657
+ for (const { id } of pollarClient.listWalletAdapters()) {
4658
+ const adapter = pollarClient.getWalletAdapter(id);
4659
+ if (!isInteractiveAuthAdapter(adapter) || !adapter.onProviderAuthChange) continue;
4660
+ let triggered = false;
4661
+ unsubscribes.push(
4662
+ adapter.onProviderAuthChange((state) => {
4663
+ if (!state.authenticated || !state.address) {
4664
+ triggered = false;
4665
+ return;
4666
+ }
4667
+ if (triggered || sessionRef.current?.wallet?.address) return;
4668
+ triggered = true;
4669
+ pollarClient.login({ provider: id });
4670
+ })
4671
+ );
4672
+ }
4673
+ return () => {
4674
+ for (const unsubscribe of unsubscribes) unsubscribe();
4675
+ };
4676
+ }, [pollarClient]);
4025
4677
  useEffect(() => {
4026
4678
  setModalErrorLogger(pollarClient.getLogger());
4027
4679
  }, [pollarClient]);
@@ -4047,6 +4699,7 @@ function PollarProvider({
4047
4699
  const [walletBalanceModalOpen, setWalletBalanceModalOpen] = useState(false);
4048
4700
  const [enabledAssetsModalOpen, setEnabledAssetsModalOpen] = useState(false);
4049
4701
  const [sendModalOpen, setSendModalOpen] = useState(false);
4702
+ const [swapModalOpen, setSwapModalOpen] = useState(false);
4050
4703
  const [receiveModalOpen, setReceiveModalOpen] = useState(false);
4051
4704
  const [sessionsModalOpen, setSessionsModalOpen] = useState(false);
4052
4705
  const [distributionRulesModalOpen, setDistributionRulesModalOpen] = useState(false);
@@ -4054,15 +4707,13 @@ function PollarProvider({
4054
4707
  const getClient = useCallback(() => pollarClient, [pollarClient]);
4055
4708
  const refreshWalletBalance = useCallback(() => pollarClient.refreshBalance(), [pollarClient, walletAddress]);
4056
4709
  const refreshAssets = useCallback(() => pollarClient.refreshAssets(), [pollarClient, walletAddress]);
4057
- const renderWallets = ui?.renderWallets;
4058
4710
  const contextValue = useMemo(() => {
4059
4711
  const styles = resolvedConfig.styles ?? {};
4060
4712
  return {
4061
4713
  // session
4062
- walletAddress,
4714
+ wallet: pollarClient.getWallet(),
4063
4715
  isAuthenticated: !!walletAddress,
4064
4716
  verified,
4065
- walletType: pollarClient.getWalletType(),
4066
4717
  // client
4067
4718
  getClient,
4068
4719
  // auth
@@ -4093,6 +4744,10 @@ function PollarProvider({
4093
4744
  // send / receive
4094
4745
  openSendModal: () => setSendModalOpen(true),
4095
4746
  openReceiveModal: () => setReceiveModalOpen(true),
4747
+ // swap
4748
+ getSwapQuote: (params) => pollarClient.getSwapQuote(params),
4749
+ swap: (quote, opts) => pollarClient.swap(quote, opts),
4750
+ openSwapModal: () => setSwapModalOpen(true),
4096
4751
  // sessions
4097
4752
  sessions,
4098
4753
  openSessionsModal: () => setSessionsModalOpen(true),
@@ -4111,7 +4766,6 @@ function PollarProvider({
4111
4766
  // config
4112
4767
  appConfig: resolvedConfig,
4113
4768
  styles,
4114
- renderWallets,
4115
4769
  adapters
4116
4770
  };
4117
4771
  }, [
@@ -4128,8 +4782,7 @@ function PollarProvider({
4128
4782
  refreshAssets,
4129
4783
  networkState,
4130
4784
  resolvedConfig,
4131
- adapters,
4132
- renderWallets
4785
+ adapters
4133
4786
  ]);
4134
4787
  return /* @__PURE__ */ jsxs(PollarContext.Provider, { value: contextValue, children: [
4135
4788
  children,
@@ -4149,6 +4802,7 @@ function PollarProvider({
4149
4802
  walletBalanceModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setWalletBalanceModalOpen(false), children: /* @__PURE__ */ jsx(WalletBalanceModal, { onClose: () => setWalletBalanceModalOpen(false) }) }),
4150
4803
  enabledAssetsModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setEnabledAssetsModalOpen(false), children: /* @__PURE__ */ jsx(EnabledAssetsModal, { onClose: () => setEnabledAssetsModalOpen(false) }) }),
4151
4804
  sendModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setSendModalOpen(false), children: /* @__PURE__ */ jsx(SendModal, { onClose: () => setSendModalOpen(false) }) }),
4805
+ swapModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setSwapModalOpen(false), children: /* @__PURE__ */ jsx(SwapModal, { onClose: () => setSwapModalOpen(false) }) }),
4152
4806
  receiveModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setReceiveModalOpen(false), children: /* @__PURE__ */ jsx(ReceiveModal, { onClose: () => setReceiveModalOpen(false) }) }),
4153
4807
  sessionsModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setSessionsModalOpen(false), children: /* @__PURE__ */ jsx(SessionsModal, { onClose: () => setSessionsModalOpen(false) }) }),
4154
4808
  distributionRulesModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setDistributionRulesModalOpen(false), children: /* @__PURE__ */ jsx(DistributionRulesModal, { onClose: () => setDistributionRulesModalOpen(false) }) })
@@ -4482,7 +5136,7 @@ function WalletButtonTemplate({
4482
5136
  function WalletButton() {
4483
5137
  const {
4484
5138
  getClient,
4485
- walletAddress,
5139
+ wallet,
4486
5140
  styles,
4487
5141
  openLoginModal,
4488
5142
  openTxHistoryModal,
@@ -4493,9 +5147,10 @@ function WalletButton() {
4493
5147
  openKycModal,
4494
5148
  openRampModal,
4495
5149
  openDistributionRulesModal,
4496
- tx: transaction,
4497
- walletType
5150
+ tx: transaction
4498
5151
  } = usePollar();
5152
+ const walletAddress = wallet?.address ?? "";
5153
+ const walletType = wallet?.custody === "external" ? wallet.provider : null;
4499
5154
  const [open, setOpen] = useState(false);
4500
5155
  const [copied, setCopied] = useState(false);
4501
5156
  const wrapperRef = useRef(null);
@@ -4596,6 +5251,6 @@ function WalletButton() {
4596
5251
  );
4597
5252
  }
4598
5253
 
4599
- export { DistributionRulesModal, DistributionRulesModalTemplate, EnabledAssetsModal, EnabledAssetsModalTemplate, KycModal, KycModalTemplate, KycStatus, LoginModalTemplate, PollarProvider, RampWidget, RampWidgetTemplate, ReceiveModal, ReceiveModalTemplate, RouteDisplay, SendModal, SendModalTemplate, SessionsModal, SessionsModalTemplate, TransactionModalTemplate, TxHistoryModalTemplate, TxStatusView, WalletBalanceModal, WalletBalanceModalTemplate, WalletButton, WalletButtonTemplate, createPollarAdapterHook, usePollar };
5254
+ export { DistributionRulesModal, DistributionRulesModalTemplate, EnabledAssetsModal, EnabledAssetsModalTemplate, KycModal, KycModalTemplate, KycStatus, LoginModalTemplate, PollarProvider, RampWidget, RampWidgetTemplate, ReceiveModal, ReceiveModalTemplate, RouteDisplay, SendModal, SendModalTemplate, SessionsModal, SessionsModalTemplate, SwapModal, SwapModalTemplate, TransactionModalTemplate, TxHistoryModalTemplate, TxStatusView, WalletBalanceModal, WalletBalanceModalTemplate, WalletButton, WalletButtonTemplate, createPollarAdapterHook, usePollar };
4600
5255
  //# sourceMappingURL=index.mjs.map
4601
5256
  //# sourceMappingURL=index.mjs.map