@pollar/react 0.10.0-rc.8 → 0.10.1-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.10.0-rc.8"
1038
+ "0.10.1-rc.0"
1039
1039
  ] })
1040
1040
  ] })
1041
1041
  ] });
@@ -1855,12 +1855,39 @@ var GoogleButton = ({ disabled, onClick }) => {
1855
1855
  function WalletAdapterButtons({
1856
1856
  walletAdapters,
1857
1857
  onConnect,
1858
- isLoading
1858
+ isLoading,
1859
+ variant = "list"
1859
1860
  }) {
1860
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-list", children: walletAdapters.map((a) => /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", disabled: isLoading, className: "pollar-wallet-list-btn", onClick: () => onConnect(a.id), children: [
1861
- a.meta.iconUrl && /* @__PURE__ */ jsxRuntime.jsx("img", { src: a.meta.iconUrl, alt: a.meta.label, className: "pollar-wallet-list-icon" }),
1862
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-wallet-list-name", children: a.meta.label })
1863
- ] }, a.id)) });
1861
+ if (variant === "entry") {
1862
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: walletAdapters.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(
1863
+ "button",
1864
+ {
1865
+ type: "button",
1866
+ disabled: isLoading,
1867
+ className: "pollar-wallet-entry-btn",
1868
+ onClick: () => onConnect(a.id),
1869
+ children: [
1870
+ a.meta.iconUrl && /* @__PURE__ */ jsxRuntime.jsx("img", { src: a.meta.iconUrl, alt: a.meta.label, className: "pollar-wallet-icon" }),
1871
+ a.meta.label
1872
+ ]
1873
+ },
1874
+ a.id
1875
+ )) });
1876
+ }
1877
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-list", children: walletAdapters.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(
1878
+ "button",
1879
+ {
1880
+ type: "button",
1881
+ disabled: isLoading,
1882
+ className: "pollar-wallet-list-btn",
1883
+ onClick: () => onConnect(a.id),
1884
+ children: [
1885
+ a.meta.iconUrl && /* @__PURE__ */ jsxRuntime.jsx("img", { src: a.meta.iconUrl, alt: a.meta.label, className: "pollar-wallet-list-icon" }),
1886
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-wallet-list-name", children: a.meta.label })
1887
+ ]
1888
+ },
1889
+ a.id
1890
+ )) });
1864
1891
  }
1865
1892
  var AUTH_STATE_MESSAGES = {
1866
1893
  idle: "",
@@ -1917,7 +1944,6 @@ function LoginModalTemplate({
1917
1944
  onWalletConnect,
1918
1945
  onLoginSmartWallet,
1919
1946
  onCreateSmartWallet,
1920
- renderWallets,
1921
1947
  authState,
1922
1948
  codeInputKey,
1923
1949
  onCodeSubmit,
@@ -1925,10 +1951,19 @@ function LoginModalTemplate({
1925
1951
  onCancel,
1926
1952
  onRetry
1927
1953
  }) {
1928
- const [showWalletPicker, setShowWalletPicker] = react.useState(false);
1929
1954
  const [showPasskeyChooser, setShowPasskeyChooser] = react.useState(false);
1955
+ const [activeGroup, setActiveGroup] = react.useState(null);
1930
1956
  const isDark = theme === "dark";
1931
1957
  const enabledSocial = Object.entries(providers).filter(([, enabled]) => enabled);
1958
+ const rootAdapters = walletAdapters.filter((a) => !a.meta.group);
1959
+ const walletGroups = walletAdapters.filter((a) => a.meta.group).reduce((acc, a) => {
1960
+ const label = a.meta.group;
1961
+ const existing = acc.find((g) => g.label === label);
1962
+ if (existing) existing.adapters.push(a);
1963
+ else acc.push({ label, adapters: [a] });
1964
+ return acc;
1965
+ }, []);
1966
+ const activeGroupAdapters = walletGroups.find((g) => g.label === activeGroup)?.adapters ?? [];
1932
1967
  const cssVars = {
1933
1968
  "--pollar-accent": accentColor,
1934
1969
  "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
@@ -1992,11 +2027,17 @@ function LoginModalTemplate({
1992
2027
  /* @__PURE__ */ jsxRuntime.jsx(BackButton, { onClick: onBack }),
1993
2028
  /* @__PURE__ */ jsxRuntime.jsx(EmailCodeInput, { email, onSubmit: onCodeSubmit ?? (() => {
1994
2029
  }) }, codeInputKey)
1995
- ] }) : showWalletPicker ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1996
- /* @__PURE__ */ jsxRuntime.jsx(BackButton, { onClick: () => setShowWalletPicker(false) }),
1997
- renderWallets ? renderWallets({ onConnect: onWalletConnect ?? (() => {
1998
- }), authState }) : /* @__PURE__ */ jsxRuntime.jsx(WalletAdapterButtons, { walletAdapters, onConnect: onWalletConnect ?? (() => {
1999
- }), isLoading })
2030
+ ] }) : activeGroup ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2031
+ /* @__PURE__ */ jsxRuntime.jsx(BackButton, { onClick: () => setActiveGroup(null) }),
2032
+ /* @__PURE__ */ jsxRuntime.jsx(
2033
+ WalletAdapterButtons,
2034
+ {
2035
+ walletAdapters: activeGroupAdapters,
2036
+ onConnect: onWalletConnect ?? (() => {
2037
+ }),
2038
+ isLoading
2039
+ }
2040
+ )
2000
2041
  ] }) : showPasskeyChooser ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2001
2042
  /* @__PURE__ */ jsxRuntime.jsx(BackButton, { onClick: () => setShowPasskeyChooser(false) }),
2002
2043
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-section", children: [
@@ -2038,32 +2079,45 @@ function LoginModalTemplate({
2038
2079
  enabledSocial.some(([key]) => key === "github") && /* @__PURE__ */ jsxRuntime.jsx(GithubButton, { disabled: isLoading, onClick: () => onSocialLogin?.("github") })
2039
2080
  ] }),
2040
2081
  (embeddedWallets || smartWallet) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-section", children: [
2041
- embeddedWallets && /* @__PURE__ */ jsxRuntime.jsxs(
2042
- "button",
2043
- {
2044
- type: "button",
2045
- disabled: isLoading,
2046
- className: "pollar-wallet-entry-btn",
2047
- onClick: () => setShowWalletPicker(true),
2048
- children: [
2049
- /* @__PURE__ */ jsxRuntime.jsx(
2050
- "svg",
2051
- {
2052
- width: "18",
2053
- height: "20",
2054
- viewBox: "0 0 24 24",
2055
- fill: "none",
2056
- stroke: "currentColor",
2057
- strokeWidth: "2",
2058
- strokeLinecap: "round",
2059
- strokeLinejoin: "round",
2060
- children: /* @__PURE__ */ jsxRuntime.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" })
2061
- }
2062
- ),
2063
- "Wallet"
2064
- ]
2065
- }
2066
- ),
2082
+ embeddedWallets && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2083
+ walletGroups.map((g) => /* @__PURE__ */ jsxRuntime.jsxs(
2084
+ "button",
2085
+ {
2086
+ type: "button",
2087
+ disabled: isLoading,
2088
+ className: "pollar-wallet-entry-btn",
2089
+ onClick: () => setActiveGroup(g.label),
2090
+ children: [
2091
+ /* @__PURE__ */ jsxRuntime.jsx(
2092
+ "svg",
2093
+ {
2094
+ width: "18",
2095
+ height: "20",
2096
+ viewBox: "0 0 24 24",
2097
+ fill: "none",
2098
+ stroke: "currentColor",
2099
+ strokeWidth: "2",
2100
+ strokeLinecap: "round",
2101
+ strokeLinejoin: "round",
2102
+ children: /* @__PURE__ */ jsxRuntime.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" })
2103
+ }
2104
+ ),
2105
+ g.label
2106
+ ]
2107
+ },
2108
+ g.label
2109
+ )),
2110
+ rootAdapters.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
2111
+ WalletAdapterButtons,
2112
+ {
2113
+ walletAdapters: rootAdapters,
2114
+ onConnect: onWalletConnect ?? (() => {
2115
+ }),
2116
+ isLoading,
2117
+ variant: "entry"
2118
+ }
2119
+ )
2120
+ ] }),
2067
2121
  smartWallet && /* @__PURE__ */ jsxRuntime.jsxs(
2068
2122
  "button",
2069
2123
  {
@@ -2104,13 +2158,142 @@ function LoginModalTemplate({
2104
2158
  /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
2105
2159
  ] });
2106
2160
  }
2161
+ function PrivyLoginSubmodal({
2162
+ adapter,
2163
+ theme,
2164
+ accentColor,
2165
+ logoUrl,
2166
+ appName,
2167
+ onBack,
2168
+ onCancel,
2169
+ onAuthenticated
2170
+ }) {
2171
+ const options = react.useMemo(() => adapter.getAuthOptions(), [adapter]);
2172
+ const [email, setEmail] = react.useState("");
2173
+ const [view, setView] = react.useState("root");
2174
+ const [status, setStatus] = react.useState("NONE");
2175
+ const [message, setMessage] = react.useState("");
2176
+ const isDark = theme === "dark";
2177
+ const isLoading = status === "LOADING";
2178
+ const cssVars = {
2179
+ "--pollar-accent": accentColor,
2180
+ "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
2181
+ "--pollar-border": isDark ? "#374151" : "#e5e7eb",
2182
+ "--pollar-text": isDark ? "#ffffff" : "#111827",
2183
+ "--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
2184
+ "--pollar-input-bg": isDark ? "#374151" : "#f9fafb",
2185
+ "--pollar-error-bg": isDark ? "#2a1515" : "#fef2f2",
2186
+ "--pollar-error-border": isDark ? "#7f1d1d" : "#fecaca",
2187
+ "--pollar-error-text": isDark ? "#f87171" : "#dc2626",
2188
+ "--pollar-success-text": isDark ? "#4ade80" : "#16a34a",
2189
+ "--pollar-buttons-border-radius": "6px",
2190
+ "--pollar-buttons-height": "44px",
2191
+ "--pollar-input-height": "44px",
2192
+ "--pollar-input-border-radius": "0.5rem",
2193
+ "--pollar-card-border-radius": "10px",
2194
+ "--pollar-modal-padding": "2rem",
2195
+ "--pollar-modal-heading-size": "1.375rem",
2196
+ "--pollar-modal-subtitle-size": "0.9rem"
2197
+ };
2198
+ function fail(error) {
2199
+ setStatus("ERROR");
2200
+ setMessage(error instanceof Error ? error.message : "Something went wrong. Please try again.");
2201
+ }
2202
+ async function handleEmailSubmit() {
2203
+ if (!email) return;
2204
+ setStatus("LOADING");
2205
+ setMessage("");
2206
+ try {
2207
+ await adapter.sendEmailCode(email);
2208
+ setStatus("SUCCESS");
2209
+ setMessage("Code sent \u2014 check your inbox");
2210
+ setView("email-code");
2211
+ } catch (error) {
2212
+ fail(error);
2213
+ }
2214
+ }
2215
+ async function handleCodeSubmit(code) {
2216
+ setStatus("LOADING");
2217
+ setMessage("Verifying\u2026");
2218
+ try {
2219
+ await adapter.verifyEmailCode(code);
2220
+ onAuthenticated();
2221
+ } catch (error) {
2222
+ fail(error);
2223
+ }
2224
+ }
2225
+ async function handleOAuth(provider) {
2226
+ setStatus("LOADING");
2227
+ setMessage("");
2228
+ try {
2229
+ await adapter.loginWithOAuth(provider);
2230
+ onAuthenticated();
2231
+ } catch (error) {
2232
+ fail(error);
2233
+ }
2234
+ }
2235
+ const BackButton = ({ onClick }) => /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-back-btn", onClick, "aria-label": "Back", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 19l-7-7 7-7" }) }) });
2236
+ const showEmail = options.includes("email");
2237
+ const showGoogle = options.includes("google");
2238
+ const showGithub = options.includes("github");
2239
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-card pollar-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
2240
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-close-btn", onClick: onCancel, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" }) }) }),
2241
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-header", children: [
2242
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-logo-wrap", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: logoUrl ?? LOGO_POLLAR, alt: "Logo", className: "pollar-logo" }) }),
2243
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-title", children: appName }),
2244
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-subtitle", children: adapter.meta.label })
2245
+ ] }),
2246
+ view === "email-code" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2247
+ /* @__PURE__ */ jsxRuntime.jsx(BackButton, { onClick: () => setView("root") }),
2248
+ /* @__PURE__ */ jsxRuntime.jsx(EmailCodeInput, { email, onSubmit: handleCodeSubmit })
2249
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2250
+ /* @__PURE__ */ jsxRuntime.jsx(BackButton, { onClick: onBack }),
2251
+ showEmail && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-email-section", children: [
2252
+ /* @__PURE__ */ jsxRuntime.jsx(
2253
+ "input",
2254
+ {
2255
+ type: "email",
2256
+ placeholder: "you@email.com",
2257
+ value: email,
2258
+ disabled: isLoading,
2259
+ className: "pollar-email-input",
2260
+ onChange: (e) => setEmail(e.target.value),
2261
+ onKeyDown: (e) => e.key === "Enter" && handleEmailSubmit()
2262
+ }
2263
+ ),
2264
+ /* @__PURE__ */ jsxRuntime.jsx(
2265
+ "button",
2266
+ {
2267
+ type: "button",
2268
+ disabled: isLoading || !email,
2269
+ className: "pollar-btn-primary",
2270
+ style: { marginTop: "0.75rem" },
2271
+ onClick: handleEmailSubmit,
2272
+ children: "Submit"
2273
+ }
2274
+ )
2275
+ ] }),
2276
+ showEmail && (showGoogle || showGithub) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-divider", children: [
2277
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-divider-line" }),
2278
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-divider-label", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-divider-text", children: "or continue with" }) })
2279
+ ] }),
2280
+ (showGoogle || showGithub) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-social-list", children: [
2281
+ showGoogle && /* @__PURE__ */ jsxRuntime.jsx(GoogleButton, { disabled: isLoading, onClick: () => handleOAuth("google") }),
2282
+ showGithub && /* @__PURE__ */ jsxRuntime.jsx(GithubButton, { disabled: isLoading, onClick: () => handleOAuth("github") })
2283
+ ] })
2284
+ ] }),
2285
+ /* @__PURE__ */ jsxRuntime.jsx(ModalStatusBanner, { message, status, onCancel, onRetry: void 0 }),
2286
+ /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
2287
+ ] });
2288
+ }
2107
2289
  function LoginModal({ onClose }) {
2108
2290
  const [email, setEmail] = react.useState("");
2109
- const { getClient, styles, appConfig: config, renderWallets } = usePollar();
2291
+ const { getClient, styles, appConfig: config } = usePollar();
2110
2292
  const [authState, setAuthState] = react.useState(() => getClient().getAuthState());
2111
2293
  const walletAdapters = react.useMemo(() => getClient().listWalletAdapters(), [getClient]);
2112
2294
  const [codeInputKey, setCodeInputKey] = react.useState(0);
2113
2295
  const pendingEmail = react.useRef(null);
2296
+ const [interactiveAdapter, setInteractiveAdapter] = react.useState(null);
2114
2297
  const onCloseRef = react.useRef(onClose);
2115
2298
  onCloseRef.current = onClose;
2116
2299
  const autoCloseTimer = react.useRef(null);
@@ -2158,6 +2341,11 @@ function LoginModal({ onClose }) {
2158
2341
  getClient().login({ provider });
2159
2342
  }
2160
2343
  function handleWalletConnect(type) {
2344
+ const adapter = getClient().getWalletAdapter(type);
2345
+ if (core.isInteractiveAuthAdapter(adapter)) {
2346
+ setInteractiveAdapter(adapter);
2347
+ return;
2348
+ }
2161
2349
  getClient().login({ provider: type });
2162
2350
  }
2163
2351
  function handleLoginSmartWallet() {
@@ -2179,7 +2367,26 @@ function LoginModal({ onClose }) {
2179
2367
  getClient().beginEmailLogin();
2180
2368
  }
2181
2369
  }
2182
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", onClick: handleClose, children: /* @__PURE__ */ jsxRuntime.jsx(
2370
+ function handleInteractiveAuthenticated() {
2371
+ const provider = interactiveAdapter?.type;
2372
+ setInteractiveAdapter(null);
2373
+ if (provider) {
2374
+ getClient().login({ provider });
2375
+ }
2376
+ }
2377
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", onClick: handleClose, children: interactiveAdapter ? /* @__PURE__ */ jsxRuntime.jsx(
2378
+ PrivyLoginSubmodal,
2379
+ {
2380
+ adapter: interactiveAdapter,
2381
+ theme,
2382
+ accentColor,
2383
+ logoUrl: logoUrl ?? null,
2384
+ appName: config.application?.name ?? "Pollar",
2385
+ onBack: () => setInteractiveAdapter(null),
2386
+ onCancel: handleClose,
2387
+ onAuthenticated: handleInteractiveAuthenticated
2388
+ }
2389
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
2183
2390
  LoginModalTemplate,
2184
2391
  {
2185
2392
  theme,
@@ -2204,7 +2411,6 @@ function LoginModal({ onClose }) {
2204
2411
  onWalletConnect: handleWalletConnect,
2205
2412
  onLoginSmartWallet: handleLoginSmartWallet,
2206
2413
  onCreateSmartWallet: handleCreateSmartWallet,
2207
- ...renderWallets !== void 0 && { renderWallets },
2208
2414
  authState,
2209
2415
  codeInputKey,
2210
2416
  onCodeSubmit: handleVerifyCode,
@@ -2261,6 +2467,12 @@ var COUNTRY_CURRENCIES = {
2261
2467
  PE: "PEN",
2262
2468
  AR: "ARS"
2263
2469
  };
2470
+ var STATUS_LABEL = {
2471
+ pending: "Pending",
2472
+ processing: "Processing",
2473
+ completed: "Completed",
2474
+ failed: "Failed"
2475
+ };
2264
2476
  function RampWidgetTemplate({
2265
2477
  theme,
2266
2478
  accentColor,
@@ -2270,15 +2482,23 @@ function RampWidgetTemplate({
2270
2482
  currency,
2271
2483
  country,
2272
2484
  quotes,
2273
- paymentInstructions,
2274
2485
  isLoading,
2486
+ provider,
2487
+ txStatus,
2488
+ kycUrl,
2489
+ stellarTxHash,
2490
+ canComplete,
2491
+ completing,
2492
+ errorMsg,
2275
2493
  onDirectionChange,
2276
2494
  onAmountChange,
2277
2495
  onCurrencyChange,
2278
2496
  onCountryChange,
2279
2497
  onFindRoute,
2280
2498
  onSelectQuote,
2281
- onCopy,
2499
+ onOpenKyc,
2500
+ onCompleteWithdraw,
2501
+ onRetry,
2282
2502
  onClose
2283
2503
  }) {
2284
2504
  const isDark = theme === "dark";
@@ -2306,13 +2526,15 @@ function RampWidgetTemplate({
2306
2526
  input: direction === "onramp" ? "Buy crypto" : "Sell crypto",
2307
2527
  loading_quote: "Finding best route",
2308
2528
  select_route: "Select provider",
2309
- payment_instructions: "Payment instructions"
2529
+ status: direction === "onramp" ? "Complete your deposit" : "Complete your withdrawal",
2530
+ error: "Something went wrong"
2310
2531
  };
2311
2532
  const stepSubtitle = {
2312
2533
  input: direction === "onramp" ? "Enter the amount you want to deposit" : "Enter the amount you want to withdraw",
2313
2534
  loading_quote: "Comparing providers in real time\u2026",
2314
2535
  select_route: "All prices include fees",
2315
- payment_instructions: "Send the exact amount to complete your transaction"
2536
+ status: `Finish the flow at ${provider || "the provider"} to continue`,
2537
+ error: "Please try again"
2316
2538
  };
2317
2539
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-card pollar-ramp-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
2318
2540
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-header", children: [
@@ -2408,183 +2630,183 @@ function RampWidgetTemplate({
2408
2630
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-route-list", children: quotes.map((q, i) => /* @__PURE__ */ jsxRuntime.jsx(RouteDisplay, { quote: q, onSelect: onSelectQuote }, i)) }),
2409
2631
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Cancel" })
2410
2632
  ] }),
2411
- step === "payment_instructions" && paymentInstructions && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment", children: [
2412
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-title", children: paymentInstructions.type }),
2633
+ step === "status" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment", children: [
2413
2634
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
2414
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: paymentInstructions.type === "CLABE" ? "CLABE number" : paymentInstructions.type === "PIX" ? "PIX key" : "Account number" }),
2415
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-value", children: [
2416
- /* @__PURE__ */ jsxRuntime.jsx("code", { children: paymentInstructions.value }),
2417
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-ramp-copy-btn", onClick: () => onCopy(paymentInstructions.value), children: "Copy" })
2418
- ] })
2635
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "Provider" }),
2636
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-payment-value", children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: provider }) })
2419
2637
  ] }),
2420
2638
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
2421
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "Amount to send" }),
2422
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-value", children: [
2423
- /* @__PURE__ */ jsxRuntime.jsxs("code", { children: [
2424
- paymentInstructions.amount.toLocaleString(),
2425
- " ",
2426
- paymentInstructions.currency
2427
- ] }),
2428
- /* @__PURE__ */ jsxRuntime.jsx(
2429
- "button",
2430
- {
2431
- type: "button",
2432
- className: "pollar-ramp-copy-btn",
2433
- onClick: () => onCopy(`${paymentInstructions.amount} ${paymentInstructions.currency}`),
2434
- children: "Copy"
2435
- }
2436
- )
2437
- ] })
2639
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "Status" }),
2640
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-payment-value", children: /* @__PURE__ */ jsxRuntime.jsx(
2641
+ "code",
2642
+ {
2643
+ style: { color: txStatus === "completed" ? "var(--pollar-success-text)" : void 0 },
2644
+ children: txStatus ? STATUS_LABEL[txStatus] : "Processing"
2645
+ }
2646
+ ) })
2438
2647
  ] }),
2439
- paymentInstructions.expiresAt && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-ramp-payment-note", children: [
2440
- "Instructions expire at ",
2441
- new Date(paymentInstructions.expiresAt).toLocaleTimeString()
2648
+ stellarTxHash && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
2649
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "Stellar tx" }),
2650
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-payment-value", children: /* @__PURE__ */ jsxRuntime.jsxs("code", { children: [
2651
+ stellarTxHash.slice(0, 8),
2652
+ "\u2026",
2653
+ stellarTxHash.slice(-8)
2654
+ ] }) })
2442
2655
  ] }),
2443
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onClose, children: "Done" })
2656
+ kycUrl && txStatus !== "completed" && /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "pollar-btn-primary", onClick: onOpenKyc, children: [
2657
+ "Continue at ",
2658
+ provider
2659
+ ] }),
2660
+ canComplete && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", disabled: completing, onClick: onCompleteWithdraw, children: completing ? "Submitting\u2026" : "I've completed KYC \u2014 withdraw" }),
2661
+ errorMsg && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", style: { color: "var(--pollar-error-text)" }, children: errorMsg }),
2662
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: txStatus === "completed" ? "Done" : "Close" })
2663
+ ] }),
2664
+ step === "error" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment", children: [
2665
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", style: { color: "var(--pollar-error-text)" }, children: errorMsg ?? "Unexpected error." }),
2666
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-actions", children: [
2667
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Close" }),
2668
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onRetry, children: "Try again" })
2669
+ ] })
2444
2670
  ] })
2445
2671
  ] });
2446
2672
  }
2447
- var MOCK_DEFAULT_QUOTES = [
2448
- {
2449
- quoteId: "meld-default",
2450
- provider: "Meld",
2451
- fee: 1.2,
2452
- feeCurrency: "USD",
2453
- rate: 1,
2454
- rail: "ACH",
2455
- protocol: "REST",
2456
- estimatedTime: "~20 min",
2457
- recommended: true
2458
- }
2459
- ];
2460
- var MOCK_QUOTES = {
2461
- MX: [
2462
- {
2463
- quoteId: "etherfuse-mx",
2464
- provider: "Etherfuse",
2465
- fee: 0.5,
2466
- feeCurrency: "MXN",
2467
- rate: 17.2,
2468
- rail: "SPEI",
2469
- protocol: "SEP-24",
2470
- estimatedTime: "~10 min",
2471
- recommended: true
2472
- },
2473
- {
2474
- quoteId: "alfredpay-mx",
2475
- provider: "AlfredPay",
2476
- fee: 0.8,
2477
- feeCurrency: "MXN",
2478
- rate: 17.1,
2479
- rail: "SPEI",
2480
- protocol: "REST",
2481
- estimatedTime: "~15 min",
2482
- recommended: false
2483
- }
2484
- ],
2485
- BR: [
2486
- {
2487
- quoteId: "abroad-br",
2488
- provider: "Abroad",
2489
- fee: 0.6,
2490
- feeCurrency: "BRL",
2491
- rate: 5.1,
2492
- rail: "PIX",
2493
- protocol: "REST",
2494
- estimatedTime: "~5 min",
2495
- recommended: true
2496
- }
2497
- ],
2498
- CO: [
2499
- {
2500
- quoteId: "abroad-co",
2501
- provider: "Abroad",
2502
- fee: 0.7,
2503
- feeCurrency: "COP",
2504
- rate: 4100,
2505
- rail: "PSE",
2506
- protocol: "REST",
2507
- estimatedTime: "~10 min",
2508
- recommended: true
2509
- },
2510
- {
2511
- quoteId: "koywe-co",
2512
- provider: "Koywe",
2513
- fee: 0.9,
2514
- feeCurrency: "COP",
2515
- rate: 4095,
2516
- rail: "PSE",
2517
- protocol: "REST",
2518
- estimatedTime: "~15 min",
2519
- recommended: false
2520
- }
2521
- ],
2522
- DEFAULT: MOCK_DEFAULT_QUOTES
2523
- };
2524
- var MOCK_PAYMENT = {
2525
- type: "CLABE",
2526
- value: "646180157088723456",
2527
- amount: 1e3,
2528
- currency: "MXN",
2529
- expiresAt: new Date(Date.now() + 30 * 60 * 1e3).toISOString()
2530
- };
2673
+ var TERMINAL = ["completed", "failed"];
2531
2674
  function RampWidget({ onClose }) {
2532
- const { getClient, wallet, styles } = usePollar();
2675
+ const { getClient, signTx, wallet, styles } = usePollar();
2533
2676
  const walletAddress = wallet?.address ?? "";
2677
+ const client = getClient();
2678
+ const { theme = "light", accentColor = "#005DB4" } = styles;
2534
2679
  const [step, setStep] = react.useState("input");
2535
2680
  const [direction, setDirection] = react.useState("onramp");
2536
2681
  const [amount, setAmount] = react.useState("");
2537
- const [currency, setCurrency] = react.useState("MXN");
2538
- const [country, setCountry] = react.useState("MX");
2682
+ const [currency, setCurrency] = react.useState("ARS");
2683
+ const [country, setCountry] = react.useState("AR");
2539
2684
  const [quotes, setQuotes] = react.useState([]);
2540
- const [paymentInstructions, setPaymentInstructions] = react.useState(null);
2541
2685
  const [isLoading, setIsLoading] = react.useState(false);
2542
- const client = getClient();
2543
- const { theme = "light", accentColor = "#005DB4" } = styles;
2686
+ const [txId, setTxId] = react.useState(null);
2687
+ const [provider, setProvider] = react.useState("");
2688
+ const [kycUrl, setKycUrl] = react.useState(null);
2689
+ const [txStatus, setTxStatus] = react.useState(null);
2690
+ const [stellarTxHash, setStellarTxHash] = react.useState(null);
2691
+ const [completing, setCompleting] = react.useState(false);
2692
+ const [errorMsg, setErrorMsg] = react.useState(null);
2693
+ const directionRef = react.useRef(direction);
2694
+ directionRef.current = direction;
2695
+ react.useEffect(() => {
2696
+ if (step !== "status" || !txId) return;
2697
+ if (txStatus && TERMINAL.includes(txStatus)) return;
2698
+ let active = true;
2699
+ const id = setInterval(async () => {
2700
+ try {
2701
+ const tx = await client.getRampTransaction(txId);
2702
+ if (!active) return;
2703
+ setTxStatus(tx.status);
2704
+ if (tx.stellarTxHash) setStellarTxHash(tx.stellarTxHash);
2705
+ if (tx.kycUrl) setKycUrl(tx.kycUrl);
2706
+ if (TERMINAL.includes(tx.status)) clearInterval(id);
2707
+ } catch {
2708
+ }
2709
+ }, 5e3);
2710
+ return () => {
2711
+ active = false;
2712
+ clearInterval(id);
2713
+ };
2714
+ }, [step, txId, txStatus, client]);
2715
+ function resetToInput() {
2716
+ setStep("input");
2717
+ setQuotes([]);
2718
+ setTxId(null);
2719
+ setProvider("");
2720
+ setKycUrl(null);
2721
+ setTxStatus(null);
2722
+ setStellarTxHash(null);
2723
+ setErrorMsg(null);
2724
+ }
2725
+ async function resumeWithSignature(id, ps) {
2726
+ const outcome = await signTx(ps.unsignedXdr);
2727
+ if (outcome.status !== "signed") {
2728
+ setErrorMsg(outcome.message ?? outcome.details ?? "Signing was cancelled.");
2729
+ setStep("error");
2730
+ return;
2731
+ }
2732
+ const result = await client.submitRampSignature(id, {
2733
+ signedXdr: outcome.signedXdr,
2734
+ action: ps.action
2735
+ });
2736
+ await applyResult(result);
2737
+ }
2738
+ async function applyResult(result) {
2739
+ setTxId(result.txId);
2740
+ setProvider(result.provider);
2741
+ if (result.pendingSignature) {
2742
+ await resumeWithSignature(result.txId, result.pendingSignature);
2743
+ return;
2744
+ }
2745
+ setKycUrl(result.kycUrl ?? null);
2746
+ setTxStatus(result.status);
2747
+ setStellarTxHash(result.stellarTxHash ?? null);
2748
+ setStep("status");
2749
+ }
2544
2750
  async function handleFindRoute() {
2545
2751
  setStep("loading_quote");
2546
2752
  setIsLoading(true);
2753
+ setErrorMsg(null);
2547
2754
  try {
2548
- const result = await client.getRampsQuote({
2549
- country,
2550
- amount: Number(amount),
2551
- currency,
2552
- direction
2553
- });
2554
- if (result.quotes) setQuotes(result.quotes);
2555
- } catch {
2556
- await new Promise((r) => setTimeout(r, 1500));
2557
- setQuotes(MOCK_QUOTES[country] ?? MOCK_DEFAULT_QUOTES);
2755
+ const result = await client.getRampsQuote({ country, amount: Number(amount), currency, direction });
2756
+ const list = result.quotes ?? [];
2757
+ if (list.length === 0) {
2758
+ setErrorMsg(`No ramp providers available for ${country} yet.`);
2759
+ setStep("error");
2760
+ return;
2761
+ }
2762
+ setQuotes(list);
2763
+ setStep("select_route");
2764
+ } catch (e) {
2765
+ setErrorMsg(e instanceof Error ? e.message : "Failed to fetch quotes.");
2766
+ setStep("error");
2558
2767
  } finally {
2559
2768
  setIsLoading(false);
2560
- setStep("select_route");
2561
2769
  }
2562
2770
  }
2563
2771
  async function handleSelectQuote(quote) {
2564
- if (!walletAddress) return;
2565
2772
  setIsLoading(true);
2566
- const body = {
2567
- quoteId: `${quote.provider}-${Date.now()}`,
2568
- amount: Number(amount),
2569
- currency,
2570
- country,
2571
- walletAddress
2572
- };
2773
+ setErrorMsg(null);
2573
2774
  try {
2574
- const result = await client.createOnRamp(body);
2575
- setPaymentInstructions(result.paymentInstructions);
2576
- } catch {
2577
- await new Promise((r) => setTimeout(r, 800));
2578
- setPaymentInstructions({ ...MOCK_PAYMENT, currency });
2775
+ const base = { quoteId: quote.quoteId, amount: Number(amount), currency, country };
2776
+ const result = direction === "onramp" ? await client.createOnRamp({ ...base, ...walletAddress ? { walletAddress } : {} }) : await client.createOffRamp({ ...base, ...walletAddress ? { walletAddress } : {} });
2777
+ await applyResult(result);
2778
+ } catch (e) {
2779
+ setErrorMsg(e instanceof Error ? e.message : "Failed to start the ramp.");
2780
+ setStep("error");
2579
2781
  } finally {
2580
2782
  setIsLoading(false);
2581
- setStep("payment_instructions");
2582
2783
  }
2583
2784
  }
2584
- function handleCopy(value) {
2585
- navigator.clipboard.writeText(value).catch(() => {
2586
- });
2785
+ function handleOpenKyc() {
2786
+ if (kycUrl) window.open(kycUrl, "_blank", "noopener,noreferrer");
2787
+ }
2788
+ async function handleCompleteWithdraw() {
2789
+ if (!txId) return;
2790
+ setCompleting(true);
2791
+ setErrorMsg(null);
2792
+ try {
2793
+ const result = await client.completeWithdraw(txId);
2794
+ if (result.pendingSignature) {
2795
+ await resumeWithSignature(txId, result.pendingSignature);
2796
+ return;
2797
+ }
2798
+ setTxStatus(result.status);
2799
+ setStellarTxHash(result.stellarTxHash ?? null);
2800
+ } catch (e) {
2801
+ const msg = e instanceof Error ? e.message : "";
2802
+ setErrorMsg(
2803
+ msg.includes("KYC") ? "Finish KYC at the provider first, then try again." : msg || "Failed to complete the withdrawal."
2804
+ );
2805
+ } finally {
2806
+ setCompleting(false);
2807
+ }
2587
2808
  }
2809
+ const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash;
2588
2810
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
2589
2811
  RampWidgetTemplate,
2590
2812
  {
@@ -2596,15 +2818,23 @@ function RampWidget({ onClose }) {
2596
2818
  currency,
2597
2819
  country,
2598
2820
  quotes,
2599
- paymentInstructions,
2600
2821
  isLoading,
2822
+ provider,
2823
+ txStatus,
2824
+ kycUrl,
2825
+ stellarTxHash,
2826
+ canComplete,
2827
+ completing,
2828
+ errorMsg,
2601
2829
  onDirectionChange: setDirection,
2602
2830
  onAmountChange: setAmount,
2603
2831
  onCurrencyChange: setCurrency,
2604
2832
  onCountryChange: setCountry,
2605
2833
  onFindRoute: handleFindRoute,
2606
2834
  onSelectQuote: handleSelectQuote,
2607
- onCopy: handleCopy,
2835
+ onOpenKyc: handleOpenKyc,
2836
+ onCompleteWithdraw: handleCompleteWithdraw,
2837
+ onRetry: resetToInput,
2608
2838
  onClose
2609
2839
  }
2610
2840
  ) });
@@ -3268,6 +3498,494 @@ function SendModal({ onClose }) {
3268
3498
  }
3269
3499
  ) });
3270
3500
  }
3501
+ function assetOptionKey(o) {
3502
+ return `${o.code}:${o.issuer ?? "native"}`;
3503
+ }
3504
+ var PROVIDER_LABELS = {
3505
+ auto: "Best price (auto)",
3506
+ aquarius: "Aquarius",
3507
+ soroswap: "Soroswap",
3508
+ sdex: "Stellar DEX"
3509
+ };
3510
+ function formatAmount2(value) {
3511
+ const n = parseFloat(value);
3512
+ return isNaN(n) ? value : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
3513
+ }
3514
+ function SwapModalTemplate({
3515
+ theme,
3516
+ accentColor,
3517
+ step,
3518
+ txTitle,
3519
+ sellOptions,
3520
+ buyOptions,
3521
+ selectedSell,
3522
+ selectedBuy,
3523
+ amount,
3524
+ provider,
3525
+ providers,
3526
+ quote,
3527
+ quoteLoading,
3528
+ quoteError,
3529
+ formError,
3530
+ isLoadingData,
3531
+ smartUnsupported,
3532
+ configLoading,
3533
+ swapUnavailable,
3534
+ buyNeedsTrustline,
3535
+ transaction,
3536
+ showXdr,
3537
+ copied,
3538
+ explorerUrl,
3539
+ walletType,
3540
+ showBack,
3541
+ isInProgress,
3542
+ onClose,
3543
+ onBack,
3544
+ onRefresh,
3545
+ onSelectSell,
3546
+ onSelectBuy,
3547
+ onAmountChange,
3548
+ onProviderChange,
3549
+ onSwap,
3550
+ onToggleXdr,
3551
+ onCopyHash,
3552
+ onRetry,
3553
+ onDone
3554
+ }) {
3555
+ const isDark = theme === "dark";
3556
+ const cssVars = {
3557
+ "--pollar-accent": accentColor,
3558
+ "--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
3559
+ "--pollar-border": isDark ? "#374151" : "#e5e7eb",
3560
+ "--pollar-text": isDark ? "#ffffff" : "#111827",
3561
+ "--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
3562
+ "--pollar-input-bg": isDark ? "#374151" : "#f9fafb",
3563
+ "--pollar-error-bg": isDark ? "#2a1515" : "#fef2f2",
3564
+ "--pollar-error-border": isDark ? "#7f1d1d" : "#fecaca",
3565
+ "--pollar-error-text": isDark ? "#f87171" : "#dc2626",
3566
+ "--pollar-success-text": isDark ? "#4ade80" : "#16a34a",
3567
+ "--pollar-buttons-border-radius": "6px",
3568
+ "--pollar-buttons-height": "44px",
3569
+ "--pollar-input-height": "44px",
3570
+ "--pollar-input-border-radius": "0.5rem",
3571
+ "--pollar-card-border-radius": "10px"
3572
+ };
3573
+ const sellKey = selectedSell ? assetOptionKey(selectedSell) : "";
3574
+ const buyKey = selectedBuy ? assetOptionKey(selectedBuy) : "";
3575
+ const canSwap = !smartUnsupported && !!selectedSell && !!selectedBuy && !!amount && !!quote && !quoteLoading && !isLoadingData;
3576
+ const title = step === "form" ? "Swap" : txTitle;
3577
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-card pollar-send-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
3578
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
3579
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-header-left", children: [
3580
+ showBack && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onBack, "aria-label": "Back", 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: "M10 3L5 8l5 5", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
3581
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: title })
3582
+ ] }),
3583
+ !isInProgress && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header-actions", children: [
3584
+ step === "form" && /* @__PURE__ */ jsxRuntime.jsx(
3585
+ "button",
3586
+ {
3587
+ type: "button",
3588
+ className: "pollar-modal-close",
3589
+ onClick: onRefresh,
3590
+ disabled: configLoading || isLoadingData,
3591
+ "aria-label": "Refresh",
3592
+ title: "Refresh balances and options",
3593
+ children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx(
3594
+ "path",
3595
+ {
3596
+ d: "M13.5 8a5.5 5.5 0 1 1-1.6-3.9M13.5 2.5v3h-3",
3597
+ stroke: "currentColor",
3598
+ strokeWidth: "1.6",
3599
+ strokeLinecap: "round",
3600
+ strokeLinejoin: "round"
3601
+ }
3602
+ ) })
3603
+ }
3604
+ ),
3605
+ /* @__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" }) }) })
3606
+ ] })
3607
+ ] }),
3608
+ step === "form" && configLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-hint", children: "Loading swap options\u2026" }),
3609
+ step === "form" && !configLoading && swapUnavailable && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: "Swap is not available for this app." }),
3610
+ step === "form" && !configLoading && !swapUnavailable && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3611
+ smartUnsupported && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: "Swaps are not yet available for smart (passkey) wallets." }),
3612
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
3613
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "You pay" }),
3614
+ isLoadingData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-skeleton" }) : /* @__PURE__ */ jsxRuntime.jsxs(
3615
+ "select",
3616
+ {
3617
+ className: "pollar-input pollar-send-select",
3618
+ value: sellKey,
3619
+ onChange: (e) => {
3620
+ const found = sellOptions.find((o) => assetOptionKey(o) === e.target.value);
3621
+ if (found) onSelectSell(found);
3622
+ },
3623
+ children: [
3624
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: "Select asset to sell" }),
3625
+ sellOptions.map((o) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: assetOptionKey(o), children: [
3626
+ o.code,
3627
+ o.available !== void 0 ? ` \u2014 ${formatAmount2(o.available)} available` : ""
3628
+ ] }, assetOptionKey(o)))
3629
+ ]
3630
+ }
3631
+ )
3632
+ ] }),
3633
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
3634
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-label-row", children: [
3635
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "Amount" }),
3636
+ selectedSell?.available !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-send-hint", children: [
3637
+ "Available: ",
3638
+ formatAmount2(selectedSell.available),
3639
+ " ",
3640
+ selectedSell.code
3641
+ ] })
3642
+ ] }),
3643
+ /* @__PURE__ */ jsxRuntime.jsx(
3644
+ "input",
3645
+ {
3646
+ className: "pollar-input",
3647
+ type: "text",
3648
+ inputMode: "decimal",
3649
+ placeholder: "0.00",
3650
+ value: amount,
3651
+ onChange: (e) => onAmountChange(e.target.value)
3652
+ }
3653
+ )
3654
+ ] }),
3655
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
3656
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "You receive" }),
3657
+ isLoadingData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-skeleton" }) : /* @__PURE__ */ jsxRuntime.jsxs(
3658
+ "select",
3659
+ {
3660
+ className: "pollar-input pollar-send-select",
3661
+ value: buyKey,
3662
+ onChange: (e) => {
3663
+ const found = buyOptions.find((o) => assetOptionKey(o) === e.target.value);
3664
+ if (found) onSelectBuy(found);
3665
+ },
3666
+ children: [
3667
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: "Select asset to buy" }),
3668
+ buyOptions.map((o) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: assetOptionKey(o), children: [
3669
+ o.code,
3670
+ o.enabledInApp ? "" : " (external)"
3671
+ ] }, assetOptionKey(o)))
3672
+ ]
3673
+ }
3674
+ )
3675
+ ] }),
3676
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
3677
+ /* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "Route" }),
3678
+ /* @__PURE__ */ jsxRuntime.jsx(
3679
+ "select",
3680
+ {
3681
+ className: "pollar-input pollar-send-select",
3682
+ value: provider,
3683
+ onChange: (e) => onProviderChange(e.target.value),
3684
+ children: providers.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p, children: PROVIDER_LABELS[p] }, p))
3685
+ }
3686
+ )
3687
+ ] }),
3688
+ quoteLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-hint", children: "Fetching best price\u2026" }),
3689
+ !quoteLoading && quoteError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: quoteError }),
3690
+ !quoteLoading && !quoteError && quote && selectedBuy && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote", children: [
3691
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
3692
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-hint", children: "You receive" }),
3693
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3694
+ "~ ",
3695
+ formatAmount2(quote.amountOut),
3696
+ " ",
3697
+ selectedBuy.code
3698
+ ] })
3699
+ ] }),
3700
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
3701
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-hint", children: "Minimum received" }),
3702
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3703
+ formatAmount2(quote.minReceived),
3704
+ " ",
3705
+ selectedBuy.code
3706
+ ] })
3707
+ ] }),
3708
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
3709
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-hint", children: "Price impact" }),
3710
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3711
+ quote.priceImpactPct,
3712
+ "%"
3713
+ ] })
3714
+ ] }),
3715
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
3716
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-hint", children: "Route" }),
3717
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: PROVIDER_LABELS[quote.provider] })
3718
+ ] })
3719
+ ] }),
3720
+ !quoteLoading && !quoteError && !quote && selectedSell && selectedBuy && !!amount && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-hint", children: "No route found for this pair." }),
3721
+ buyNeedsTrustline && selectedBuy && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-trustline-notice", children: [
3722
+ "To receive ",
3723
+ selectedBuy.code,
3724
+ " your wallet needs a trustline. Swapping will create it first (~0.5 XLM reserve, refundable if you later remove it)."
3725
+ ] }),
3726
+ formError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: formError }),
3727
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-primary", onClick: onSwap, disabled: !canSwap, children: buyNeedsTrustline ? "Create trustline & swap" : "Swap" }) })
3728
+ ] }),
3729
+ step === "tx" && /* @__PURE__ */ jsxRuntime.jsx(
3730
+ TxStatusView,
3731
+ {
3732
+ transaction,
3733
+ showXdr,
3734
+ copied,
3735
+ explorerUrl,
3736
+ walletType,
3737
+ onSignAndSend: () => {
3738
+ },
3739
+ onToggleXdr,
3740
+ onCopyHash,
3741
+ onRetry,
3742
+ onDone
3743
+ }
3744
+ ),
3745
+ /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
3746
+ ] });
3747
+ }
3748
+ var QUOTE_DEBOUNCE_MS = 400;
3749
+ function toRef(a) {
3750
+ if (a.type === "native") return { type: "native" };
3751
+ if (a.type === "credit_alphanum4") return { type: "credit_alphanum4", code: a.code, issuer: a.issuer };
3752
+ return { type: "credit_alphanum12", code: a.code, issuer: a.issuer };
3753
+ }
3754
+ function catalogRef(code, issuer) {
3755
+ return code.length <= 4 ? { type: "credit_alphanum4", code, issuer } : { type: "credit_alphanum12", code, issuer };
3756
+ }
3757
+ function SwapModal({ onClose }) {
3758
+ const {
3759
+ getSwapConfig,
3760
+ getSwapTokens,
3761
+ getSwapQuote,
3762
+ swap,
3763
+ walletBalance,
3764
+ refreshWalletBalance,
3765
+ enabledAssets,
3766
+ refreshAssets,
3767
+ tx: transaction,
3768
+ wallet,
3769
+ network,
3770
+ styles
3771
+ } = usePollar();
3772
+ const walletType = wallet?.custody === "external" ? wallet.provider : null;
3773
+ const smartUnsupported = wallet?.custody === "smart";
3774
+ const { theme = "light", accentColor = "#005DB4" } = styles;
3775
+ const [step, setStep] = react.useState("form");
3776
+ const [selectedSell, setSelectedSell] = react.useState(null);
3777
+ const [selectedBuy, setSelectedBuy] = react.useState(null);
3778
+ const [amount, setAmount] = react.useState("");
3779
+ const [provider, setProvider] = react.useState("auto");
3780
+ const [venues, setVenues] = react.useState(null);
3781
+ const [catalogTokens, setCatalogTokens] = react.useState([]);
3782
+ const [quotes, setQuotes] = react.useState([]);
3783
+ const [quoteLoading, setQuoteLoading] = react.useState(false);
3784
+ const [quoteError, setQuoteError] = react.useState("");
3785
+ const [formError, setFormError] = react.useState("");
3786
+ const [showXdr, setShowXdr] = react.useState(false);
3787
+ const [copied, setCopied] = react.useState(false);
3788
+ const copyTimerRef = react.useRef(null);
3789
+ const slippageBps = 50;
3790
+ react.useEffect(() => {
3791
+ void refreshWalletBalance();
3792
+ void refreshAssets();
3793
+ }, [refreshWalletBalance, refreshAssets]);
3794
+ const loadConfig = react.useCallback(() => {
3795
+ setVenues(null);
3796
+ return getSwapConfig().then(setVenues).catch(() => setVenues([]));
3797
+ }, [getSwapConfig]);
3798
+ react.useEffect(() => {
3799
+ void loadConfig();
3800
+ }, [loadConfig]);
3801
+ const loadCatalog = react.useCallback(
3802
+ () => getSwapTokens().then(setCatalogTokens).catch(() => setCatalogTokens([])),
3803
+ [getSwapTokens]
3804
+ );
3805
+ react.useEffect(() => {
3806
+ void loadCatalog();
3807
+ }, [loadCatalog]);
3808
+ function handleRefresh() {
3809
+ void refreshWalletBalance();
3810
+ void refreshAssets();
3811
+ void loadConfig();
3812
+ void loadCatalog();
3813
+ }
3814
+ react.useEffect(
3815
+ () => () => {
3816
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
3817
+ },
3818
+ []
3819
+ );
3820
+ const balances = walletBalance.step === "loaded" ? walletBalance.data.balances : [];
3821
+ const assetRecords = enabledAssets.step === "loaded" ? enabledAssets.data.assets : [];
3822
+ const isLoadingData = walletBalance.step === "loading" || enabledAssets.step === "loading";
3823
+ 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 }));
3824
+ const buyKeyOfSell = selectedSell ? `${selectedSell.code}:${selectedSell.issuer ?? "native"}` : "";
3825
+ const optKey = (o) => `${o.code}:${o.issuer ?? "native"}`;
3826
+ const enabledBuy = assetRecords.map((a) => ({
3827
+ ref: toRef(a),
3828
+ code: a.code,
3829
+ issuer: a.issuer,
3830
+ enabledInApp: a.enabledInApp
3831
+ }));
3832
+ const enabledKeys = new Set(enabledBuy.map(optKey));
3833
+ const catalogBuy = catalogTokens.map((tk) => ({
3834
+ ref: catalogRef(tk.code, tk.issuer),
3835
+ code: tk.code,
3836
+ issuer: tk.issuer,
3837
+ enabledInApp: false
3838
+ })).filter((o) => !enabledKeys.has(optKey(o)));
3839
+ const buyOptions = [...enabledBuy, ...catalogBuy].filter((o) => optKey(o) !== buyKeyOfSell);
3840
+ const buyNeedsTrustline = (() => {
3841
+ if (!selectedBuy || smartUnsupported) return false;
3842
+ if (selectedBuy.ref.type === "native") return false;
3843
+ const rec = assetRecords.find((a) => a.code === selectedBuy.code && a.issuer === selectedBuy.issuer);
3844
+ return !rec?.trustlineEstablished;
3845
+ })();
3846
+ const configLoading = venues === null;
3847
+ const swapUnavailable = venues !== null && venues.length === 0;
3848
+ const providers = venues && venues.length > 0 ? ["auto", ...venues] : [];
3849
+ const quote = quotes[0] ?? null;
3850
+ react.useEffect(() => {
3851
+ if (step !== "form" || swapUnavailable || configLoading || !selectedSell || !selectedBuy || !amount || parseFloat(amount) <= 0) {
3852
+ setQuotes([]);
3853
+ setQuoteError("");
3854
+ setQuoteLoading(false);
3855
+ return;
3856
+ }
3857
+ let cancelled = false;
3858
+ setQuoteLoading(true);
3859
+ setQuoteError("");
3860
+ const t = setTimeout(async () => {
3861
+ try {
3862
+ const qs = await getSwapQuote({
3863
+ sellAsset: selectedSell.ref,
3864
+ buyAsset: selectedBuy.ref,
3865
+ amount,
3866
+ provider,
3867
+ slippageBps
3868
+ });
3869
+ if (!cancelled) setQuotes(qs);
3870
+ } catch (e) {
3871
+ if (!cancelled) {
3872
+ setQuotes([]);
3873
+ setQuoteError(e instanceof Error ? e.message : "Failed to fetch quote");
3874
+ }
3875
+ } finally {
3876
+ if (!cancelled) setQuoteLoading(false);
3877
+ }
3878
+ }, QUOTE_DEBOUNCE_MS);
3879
+ return () => {
3880
+ cancelled = true;
3881
+ clearTimeout(t);
3882
+ };
3883
+ }, [step, swapUnavailable, configLoading, selectedSell, selectedBuy, amount, provider, getSwapQuote]);
3884
+ const hash = transaction.step === "success" ? transaction.hash : null;
3885
+ const buildData = "buildData" in transaction ? transaction.buildData : null;
3886
+ const explorerNetwork = buildData?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : buildData ? "public" : network === "testnet" ? "testnet" : "public";
3887
+ const explorerUrl = hash ? `https://stellar.expert/explorer/${explorerNetwork}/tx/${hash}` : null;
3888
+ const IN_FLIGHT_STEPS2 = [
3889
+ "building",
3890
+ "signing",
3891
+ "submitting",
3892
+ "submitted",
3893
+ "signing-submitting",
3894
+ "building-signing-submitting"
3895
+ ];
3896
+ const isInProgress = IN_FLIGHT_STEPS2.includes(transaction.step);
3897
+ const showBack = step === "tx" && (transaction.step === "error" || transaction.step === "success") && !isInProgress;
3898
+ const txTitle = isInProgress ? "Swapping\u2026" : transaction.step === "success" ? "Swapped!" : transaction.step === "error" ? "Swap failed" : "Confirm Swap";
3899
+ async function handleSwap() {
3900
+ setFormError("");
3901
+ if (smartUnsupported) {
3902
+ setFormError("Swaps are not yet supported for smart (passkey) wallets");
3903
+ return;
3904
+ }
3905
+ if (!selectedSell || !selectedBuy) {
3906
+ setFormError("Select both assets");
3907
+ return;
3908
+ }
3909
+ const parsed = parseFloat(amount);
3910
+ if (!amount || isNaN(parsed) || parsed <= 0) {
3911
+ setFormError("Enter a valid amount");
3912
+ return;
3913
+ }
3914
+ if (selectedSell.available !== void 0 && parsed > parseFloat(selectedSell.available)) {
3915
+ setFormError("Insufficient balance");
3916
+ return;
3917
+ }
3918
+ if (!quote) {
3919
+ setFormError("No route available for this pair");
3920
+ return;
3921
+ }
3922
+ setStep("tx");
3923
+ await swap(quote);
3924
+ }
3925
+ async function handleRetry() {
3926
+ if (transaction.step === "error" && quote) await swap(quote);
3927
+ }
3928
+ function handleCopyHash() {
3929
+ if (!hash) return;
3930
+ navigator.clipboard.writeText(hash).then(() => {
3931
+ setCopied(true);
3932
+ if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
3933
+ copyTimerRef.current = setTimeout(() => {
3934
+ copyTimerRef.current = null;
3935
+ setCopied(false);
3936
+ }, 2e3);
3937
+ });
3938
+ }
3939
+ function handleBack() {
3940
+ setStep("form");
3941
+ setShowXdr(false);
3942
+ setCopied(false);
3943
+ }
3944
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", onClick: !isInProgress ? onClose : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(
3945
+ SwapModalTemplate,
3946
+ {
3947
+ theme,
3948
+ accentColor,
3949
+ step,
3950
+ txTitle,
3951
+ sellOptions,
3952
+ buyOptions,
3953
+ selectedSell,
3954
+ selectedBuy,
3955
+ amount,
3956
+ provider,
3957
+ providers,
3958
+ quote,
3959
+ quoteLoading,
3960
+ quoteError,
3961
+ formError,
3962
+ isLoadingData,
3963
+ smartUnsupported,
3964
+ configLoading,
3965
+ swapUnavailable,
3966
+ buyNeedsTrustline,
3967
+ transaction,
3968
+ showXdr,
3969
+ copied,
3970
+ explorerUrl,
3971
+ walletType,
3972
+ showBack,
3973
+ isInProgress,
3974
+ onClose,
3975
+ onBack: handleBack,
3976
+ onRefresh: handleRefresh,
3977
+ onSelectSell: setSelectedSell,
3978
+ onSelectBuy: setSelectedBuy,
3979
+ onAmountChange: setAmount,
3980
+ onProviderChange: setProvider,
3981
+ onSwap: () => void handleSwap(),
3982
+ onToggleXdr: () => setShowXdr((v) => !v),
3983
+ onCopyHash: handleCopyHash,
3984
+ onRetry: () => void handleRetry(),
3985
+ onDone: onClose
3986
+ }
3987
+ ) });
3988
+ }
3271
3989
  function describeDevice(s) {
3272
3990
  if (s.deviceLabel) return s.deviceLabel;
3273
3991
  if (!s.userAgent) return "Unknown device";
@@ -3962,7 +4680,6 @@ var PollarContext = react.createContext(null);
3962
4680
  function PollarProvider({
3963
4681
  client,
3964
4682
  appConfig: appConfigProp,
3965
- ui,
3966
4683
  adapters,
3967
4684
  onStorageDegrade,
3968
4685
  children
@@ -3970,6 +4687,18 @@ function PollarProvider({
3970
4687
  const [pollarClient] = react.useState(
3971
4688
  () => client instanceof core.PollarClient ? client : new core.PollarClient({ passkey: browserPasskeyCeremony, passkeySign: browserPasskeySigner, ...client })
3972
4689
  );
4690
+ const ownsClientRef = react.useRef(!(client instanceof core.PollarClient));
4691
+ const destroyTimerRef = react.useRef(null);
4692
+ react.useEffect(() => {
4693
+ if (!ownsClientRef.current) return;
4694
+ if (destroyTimerRef.current) {
4695
+ clearTimeout(destroyTimerRef.current);
4696
+ destroyTimerRef.current = null;
4697
+ }
4698
+ return () => {
4699
+ destroyTimerRef.current = setTimeout(() => pollarClient.destroy(), 0);
4700
+ };
4701
+ }, [pollarClient]);
3973
4702
  const [networkState, setNetworkState] = react.useState(() => pollarClient.getNetworkState());
3974
4703
  const [sessionState, setSessionState] = react.useState(null);
3975
4704
  const [verified, setVerified] = react.useState(false);
@@ -4014,6 +4743,30 @@ function PollarProvider({
4014
4743
  }
4015
4744
  });
4016
4745
  }, [pollarClient]);
4746
+ const sessionRef = react.useRef(sessionState);
4747
+ sessionRef.current = sessionState;
4748
+ react.useEffect(() => {
4749
+ const unsubscribes = [];
4750
+ for (const { id } of pollarClient.listWalletAdapters()) {
4751
+ const adapter = pollarClient.getWalletAdapter(id);
4752
+ if (!core.isInteractiveAuthAdapter(adapter) || !adapter.onProviderAuthChange) continue;
4753
+ let triggered = false;
4754
+ unsubscribes.push(
4755
+ adapter.onProviderAuthChange((state) => {
4756
+ if (!state.authenticated || !state.address) {
4757
+ triggered = false;
4758
+ return;
4759
+ }
4760
+ if (triggered || sessionRef.current?.wallet?.address) return;
4761
+ triggered = true;
4762
+ pollarClient.login({ provider: id });
4763
+ })
4764
+ );
4765
+ }
4766
+ return () => {
4767
+ for (const unsubscribe of unsubscribes) unsubscribe();
4768
+ };
4769
+ }, [pollarClient]);
4017
4770
  react.useEffect(() => {
4018
4771
  setModalErrorLogger(pollarClient.getLogger());
4019
4772
  }, [pollarClient]);
@@ -4039,6 +4792,7 @@ function PollarProvider({
4039
4792
  const [walletBalanceModalOpen, setWalletBalanceModalOpen] = react.useState(false);
4040
4793
  const [enabledAssetsModalOpen, setEnabledAssetsModalOpen] = react.useState(false);
4041
4794
  const [sendModalOpen, setSendModalOpen] = react.useState(false);
4795
+ const [swapModalOpen, setSwapModalOpen] = react.useState(false);
4042
4796
  const [receiveModalOpen, setReceiveModalOpen] = react.useState(false);
4043
4797
  const [sessionsModalOpen, setSessionsModalOpen] = react.useState(false);
4044
4798
  const [distributionRulesModalOpen, setDistributionRulesModalOpen] = react.useState(false);
@@ -4046,7 +4800,6 @@ function PollarProvider({
4046
4800
  const getClient = react.useCallback(() => pollarClient, [pollarClient]);
4047
4801
  const refreshWalletBalance = react.useCallback(() => pollarClient.refreshBalance(), [pollarClient, walletAddress]);
4048
4802
  const refreshAssets = react.useCallback(() => pollarClient.refreshAssets(), [pollarClient, walletAddress]);
4049
- const renderWallets = ui?.renderWallets;
4050
4803
  const contextValue = react.useMemo(() => {
4051
4804
  const styles = resolvedConfig.styles ?? {};
4052
4805
  return {
@@ -4084,6 +4837,12 @@ function PollarProvider({
4084
4837
  // send / receive
4085
4838
  openSendModal: () => setSendModalOpen(true),
4086
4839
  openReceiveModal: () => setReceiveModalOpen(true),
4840
+ // swap
4841
+ getSwapConfig: () => pollarClient.getSwapConfig(),
4842
+ getSwapTokens: () => pollarClient.getSwapTokens(),
4843
+ getSwapQuote: (params) => pollarClient.getSwapQuote(params),
4844
+ swap: (quote, opts) => pollarClient.swap(quote, opts),
4845
+ openSwapModal: () => setSwapModalOpen(true),
4087
4846
  // sessions
4088
4847
  sessions,
4089
4848
  openSessionsModal: () => setSessionsModalOpen(true),
@@ -4102,7 +4861,6 @@ function PollarProvider({
4102
4861
  // config
4103
4862
  appConfig: resolvedConfig,
4104
4863
  styles,
4105
- renderWallets,
4106
4864
  adapters
4107
4865
  };
4108
4866
  }, [
@@ -4119,8 +4877,7 @@ function PollarProvider({
4119
4877
  refreshAssets,
4120
4878
  networkState,
4121
4879
  resolvedConfig,
4122
- adapters,
4123
- renderWallets
4880
+ adapters
4124
4881
  ]);
4125
4882
  return /* @__PURE__ */ jsxRuntime.jsxs(PollarContext.Provider, { value: contextValue, children: [
4126
4883
  children,
@@ -4140,6 +4897,7 @@ function PollarProvider({
4140
4897
  walletBalanceModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setWalletBalanceModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(WalletBalanceModal, { onClose: () => setWalletBalanceModalOpen(false) }) }),
4141
4898
  enabledAssetsModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setEnabledAssetsModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(EnabledAssetsModal, { onClose: () => setEnabledAssetsModalOpen(false) }) }),
4142
4899
  sendModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSendModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SendModal, { onClose: () => setSendModalOpen(false) }) }),
4900
+ swapModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSwapModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SwapModal, { onClose: () => setSwapModalOpen(false) }) }),
4143
4901
  receiveModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setReceiveModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(ReceiveModal, { onClose: () => setReceiveModalOpen(false) }) }),
4144
4902
  sessionsModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSessionsModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SessionsModal, { onClose: () => setSessionsModalOpen(false) }) }),
4145
4903
  distributionRulesModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setDistributionRulesModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(DistributionRulesModal, { onClose: () => setDistributionRulesModalOpen(false) }) })
@@ -4606,6 +5364,8 @@ exports.SendModal = SendModal;
4606
5364
  exports.SendModalTemplate = SendModalTemplate;
4607
5365
  exports.SessionsModal = SessionsModal;
4608
5366
  exports.SessionsModalTemplate = SessionsModalTemplate;
5367
+ exports.SwapModal = SwapModal;
5368
+ exports.SwapModalTemplate = SwapModalTemplate;
4609
5369
  exports.TransactionModalTemplate = TransactionModalTemplate;
4610
5370
  exports.TxHistoryModalTemplate = TxHistoryModalTemplate;
4611
5371
  exports.TxStatusView = TxStatusView;