@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/README.md +109 -103
- package/dist/index.css +50 -11
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +100 -34
- package/dist/index.d.ts +100 -34
- package/dist/index.js +959 -199
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +959 -201
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
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.10.
|
|
1036
|
+
"0.10.1-rc.0"
|
|
1037
1037
|
] })
|
|
1038
1038
|
] })
|
|
1039
1039
|
] });
|
|
@@ -1853,12 +1853,39 @@ var GoogleButton = ({ disabled, onClick }) => {
|
|
|
1853
1853
|
function WalletAdapterButtons({
|
|
1854
1854
|
walletAdapters,
|
|
1855
1855
|
onConnect,
|
|
1856
|
-
isLoading
|
|
1856
|
+
isLoading,
|
|
1857
|
+
variant = "list"
|
|
1857
1858
|
}) {
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1859
|
+
if (variant === "entry") {
|
|
1860
|
+
return /* @__PURE__ */ jsx(Fragment, { children: walletAdapters.map((a) => /* @__PURE__ */ jsxs(
|
|
1861
|
+
"button",
|
|
1862
|
+
{
|
|
1863
|
+
type: "button",
|
|
1864
|
+
disabled: isLoading,
|
|
1865
|
+
className: "pollar-wallet-entry-btn",
|
|
1866
|
+
onClick: () => onConnect(a.id),
|
|
1867
|
+
children: [
|
|
1868
|
+
a.meta.iconUrl && /* @__PURE__ */ jsx("img", { src: a.meta.iconUrl, alt: a.meta.label, className: "pollar-wallet-icon" }),
|
|
1869
|
+
a.meta.label
|
|
1870
|
+
]
|
|
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
|
+
)) });
|
|
1862
1889
|
}
|
|
1863
1890
|
var AUTH_STATE_MESSAGES = {
|
|
1864
1891
|
idle: "",
|
|
@@ -1915,7 +1942,6 @@ function LoginModalTemplate({
|
|
|
1915
1942
|
onWalletConnect,
|
|
1916
1943
|
onLoginSmartWallet,
|
|
1917
1944
|
onCreateSmartWallet,
|
|
1918
|
-
renderWallets,
|
|
1919
1945
|
authState,
|
|
1920
1946
|
codeInputKey,
|
|
1921
1947
|
onCodeSubmit,
|
|
@@ -1923,10 +1949,19 @@ function LoginModalTemplate({
|
|
|
1923
1949
|
onCancel,
|
|
1924
1950
|
onRetry
|
|
1925
1951
|
}) {
|
|
1926
|
-
const [showWalletPicker, setShowWalletPicker] = useState(false);
|
|
1927
1952
|
const [showPasskeyChooser, setShowPasskeyChooser] = useState(false);
|
|
1953
|
+
const [activeGroup, setActiveGroup] = useState(null);
|
|
1928
1954
|
const isDark = theme === "dark";
|
|
1929
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 ?? [];
|
|
1930
1965
|
const cssVars = {
|
|
1931
1966
|
"--pollar-accent": accentColor,
|
|
1932
1967
|
"--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
|
|
@@ -1990,11 +2025,17 @@ function LoginModalTemplate({
|
|
|
1990
2025
|
/* @__PURE__ */ jsx(BackButton, { onClick: onBack }),
|
|
1991
2026
|
/* @__PURE__ */ jsx(EmailCodeInput, { email, onSubmit: onCodeSubmit ?? (() => {
|
|
1992
2027
|
}) }, codeInputKey)
|
|
1993
|
-
] }) :
|
|
1994
|
-
/* @__PURE__ */ jsx(BackButton, { onClick: () =>
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
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
|
+
)
|
|
1998
2039
|
] }) : showPasskeyChooser ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1999
2040
|
/* @__PURE__ */ jsx(BackButton, { onClick: () => setShowPasskeyChooser(false) }),
|
|
2000
2041
|
/* @__PURE__ */ jsxs("div", { className: "pollar-wallet-section", children: [
|
|
@@ -2036,32 +2077,45 @@ function LoginModalTemplate({
|
|
|
2036
2077
|
enabledSocial.some(([key]) => key === "github") && /* @__PURE__ */ jsx(GithubButton, { disabled: isLoading, onClick: () => onSocialLogin?.("github") })
|
|
2037
2078
|
] }),
|
|
2038
2079
|
(embeddedWallets || smartWallet) && /* @__PURE__ */ jsxs("div", { className: "pollar-wallet-section", children: [
|
|
2039
|
-
embeddedWallets && /* @__PURE__ */ jsxs(
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
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
|
+
] }),
|
|
2065
2119
|
smartWallet && /* @__PURE__ */ jsxs(
|
|
2066
2120
|
"button",
|
|
2067
2121
|
{
|
|
@@ -2102,13 +2156,142 @@ function LoginModalTemplate({
|
|
|
2102
2156
|
/* @__PURE__ */ jsx(PollarModalFooter, {})
|
|
2103
2157
|
] });
|
|
2104
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
|
+
}
|
|
2105
2287
|
function LoginModal({ onClose }) {
|
|
2106
2288
|
const [email, setEmail] = useState("");
|
|
2107
|
-
const { getClient, styles, appConfig: config
|
|
2289
|
+
const { getClient, styles, appConfig: config } = usePollar();
|
|
2108
2290
|
const [authState, setAuthState] = useState(() => getClient().getAuthState());
|
|
2109
2291
|
const walletAdapters = useMemo(() => getClient().listWalletAdapters(), [getClient]);
|
|
2110
2292
|
const [codeInputKey, setCodeInputKey] = useState(0);
|
|
2111
2293
|
const pendingEmail = useRef(null);
|
|
2294
|
+
const [interactiveAdapter, setInteractiveAdapter] = useState(null);
|
|
2112
2295
|
const onCloseRef = useRef(onClose);
|
|
2113
2296
|
onCloseRef.current = onClose;
|
|
2114
2297
|
const autoCloseTimer = useRef(null);
|
|
@@ -2156,6 +2339,11 @@ function LoginModal({ onClose }) {
|
|
|
2156
2339
|
getClient().login({ provider });
|
|
2157
2340
|
}
|
|
2158
2341
|
function handleWalletConnect(type) {
|
|
2342
|
+
const adapter = getClient().getWalletAdapter(type);
|
|
2343
|
+
if (isInteractiveAuthAdapter(adapter)) {
|
|
2344
|
+
setInteractiveAdapter(adapter);
|
|
2345
|
+
return;
|
|
2346
|
+
}
|
|
2159
2347
|
getClient().login({ provider: type });
|
|
2160
2348
|
}
|
|
2161
2349
|
function handleLoginSmartWallet() {
|
|
@@ -2177,7 +2365,26 @@ function LoginModal({ onClose }) {
|
|
|
2177
2365
|
getClient().beginEmailLogin();
|
|
2178
2366
|
}
|
|
2179
2367
|
}
|
|
2180
|
-
|
|
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(
|
|
2181
2388
|
LoginModalTemplate,
|
|
2182
2389
|
{
|
|
2183
2390
|
theme,
|
|
@@ -2202,7 +2409,6 @@ function LoginModal({ onClose }) {
|
|
|
2202
2409
|
onWalletConnect: handleWalletConnect,
|
|
2203
2410
|
onLoginSmartWallet: handleLoginSmartWallet,
|
|
2204
2411
|
onCreateSmartWallet: handleCreateSmartWallet,
|
|
2205
|
-
...renderWallets !== void 0 && { renderWallets },
|
|
2206
2412
|
authState,
|
|
2207
2413
|
codeInputKey,
|
|
2208
2414
|
onCodeSubmit: handleVerifyCode,
|
|
@@ -2259,6 +2465,12 @@ var COUNTRY_CURRENCIES = {
|
|
|
2259
2465
|
PE: "PEN",
|
|
2260
2466
|
AR: "ARS"
|
|
2261
2467
|
};
|
|
2468
|
+
var STATUS_LABEL = {
|
|
2469
|
+
pending: "Pending",
|
|
2470
|
+
processing: "Processing",
|
|
2471
|
+
completed: "Completed",
|
|
2472
|
+
failed: "Failed"
|
|
2473
|
+
};
|
|
2262
2474
|
function RampWidgetTemplate({
|
|
2263
2475
|
theme,
|
|
2264
2476
|
accentColor,
|
|
@@ -2268,15 +2480,23 @@ function RampWidgetTemplate({
|
|
|
2268
2480
|
currency,
|
|
2269
2481
|
country,
|
|
2270
2482
|
quotes,
|
|
2271
|
-
paymentInstructions,
|
|
2272
2483
|
isLoading,
|
|
2484
|
+
provider,
|
|
2485
|
+
txStatus,
|
|
2486
|
+
kycUrl,
|
|
2487
|
+
stellarTxHash,
|
|
2488
|
+
canComplete,
|
|
2489
|
+
completing,
|
|
2490
|
+
errorMsg,
|
|
2273
2491
|
onDirectionChange,
|
|
2274
2492
|
onAmountChange,
|
|
2275
2493
|
onCurrencyChange,
|
|
2276
2494
|
onCountryChange,
|
|
2277
2495
|
onFindRoute,
|
|
2278
2496
|
onSelectQuote,
|
|
2279
|
-
|
|
2497
|
+
onOpenKyc,
|
|
2498
|
+
onCompleteWithdraw,
|
|
2499
|
+
onRetry,
|
|
2280
2500
|
onClose
|
|
2281
2501
|
}) {
|
|
2282
2502
|
const isDark = theme === "dark";
|
|
@@ -2304,13 +2524,15 @@ function RampWidgetTemplate({
|
|
|
2304
2524
|
input: direction === "onramp" ? "Buy crypto" : "Sell crypto",
|
|
2305
2525
|
loading_quote: "Finding best route",
|
|
2306
2526
|
select_route: "Select provider",
|
|
2307
|
-
|
|
2527
|
+
status: direction === "onramp" ? "Complete your deposit" : "Complete your withdrawal",
|
|
2528
|
+
error: "Something went wrong"
|
|
2308
2529
|
};
|
|
2309
2530
|
const stepSubtitle = {
|
|
2310
2531
|
input: direction === "onramp" ? "Enter the amount you want to deposit" : "Enter the amount you want to withdraw",
|
|
2311
2532
|
loading_quote: "Comparing providers in real time\u2026",
|
|
2312
2533
|
select_route: "All prices include fees",
|
|
2313
|
-
|
|
2534
|
+
status: `Finish the flow at ${provider || "the provider"} to continue`,
|
|
2535
|
+
error: "Please try again"
|
|
2314
2536
|
};
|
|
2315
2537
|
return /* @__PURE__ */ jsxs("div", { className: "pollar-modal-card pollar-ramp-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
|
|
2316
2538
|
/* @__PURE__ */ jsxs("div", { className: "pollar-ramp-header", children: [
|
|
@@ -2406,183 +2628,183 @@ function RampWidgetTemplate({
|
|
|
2406
2628
|
/* @__PURE__ */ jsx("div", { className: "pollar-ramp-route-list", children: quotes.map((q, i) => /* @__PURE__ */ jsx(RouteDisplay, { quote: q, onSelect: onSelectQuote }, i)) }),
|
|
2407
2629
|
/* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Cancel" })
|
|
2408
2630
|
] }),
|
|
2409
|
-
step === "
|
|
2410
|
-
/* @__PURE__ */ jsx("p", { className: "pollar-ramp-payment-title", children: paymentInstructions.type }),
|
|
2631
|
+
step === "status" && /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment", children: [
|
|
2411
2632
|
/* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
2412
|
-
/* @__PURE__ */ jsx("span", { className: "pollar-ramp-payment-label", children:
|
|
2413
|
-
/* @__PURE__ */
|
|
2414
|
-
/* @__PURE__ */ jsx("code", { children: paymentInstructions.value }),
|
|
2415
|
-
/* @__PURE__ */ jsx("button", { type: "button", className: "pollar-ramp-copy-btn", onClick: () => onCopy(paymentInstructions.value), children: "Copy" })
|
|
2416
|
-
] })
|
|
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 }) })
|
|
2417
2635
|
] }),
|
|
2418
2636
|
/* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
2419
|
-
/* @__PURE__ */ jsx("span", { className: "pollar-ramp-payment-label", children: "
|
|
2420
|
-
/* @__PURE__ */
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
" ",
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
"button",
|
|
2428
|
-
{
|
|
2429
|
-
type: "button",
|
|
2430
|
-
className: "pollar-ramp-copy-btn",
|
|
2431
|
-
onClick: () => onCopy(`${paymentInstructions.amount} ${paymentInstructions.currency}`),
|
|
2432
|
-
children: "Copy"
|
|
2433
|
-
}
|
|
2434
|
-
)
|
|
2435
|
-
] })
|
|
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
|
+
) })
|
|
2436
2645
|
] }),
|
|
2437
|
-
|
|
2438
|
-
"
|
|
2439
|
-
|
|
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
|
+
] }) })
|
|
2440
2653
|
] }),
|
|
2441
|
-
/* @__PURE__ */
|
|
2654
|
+
kycUrl && txStatus !== "completed" && /* @__PURE__ */ jsxs("button", { type: "button", className: "pollar-btn-primary", onClick: onOpenKyc, children: [
|
|
2655
|
+
"Continue at ",
|
|
2656
|
+
provider
|
|
2657
|
+
] }),
|
|
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
|
+
] })
|
|
2442
2668
|
] })
|
|
2443
2669
|
] });
|
|
2444
2670
|
}
|
|
2445
|
-
var
|
|
2446
|
-
{
|
|
2447
|
-
quoteId: "meld-default",
|
|
2448
|
-
provider: "Meld",
|
|
2449
|
-
fee: 1.2,
|
|
2450
|
-
feeCurrency: "USD",
|
|
2451
|
-
rate: 1,
|
|
2452
|
-
rail: "ACH",
|
|
2453
|
-
protocol: "REST",
|
|
2454
|
-
estimatedTime: "~20 min",
|
|
2455
|
-
recommended: true
|
|
2456
|
-
}
|
|
2457
|
-
];
|
|
2458
|
-
var MOCK_QUOTES = {
|
|
2459
|
-
MX: [
|
|
2460
|
-
{
|
|
2461
|
-
quoteId: "etherfuse-mx",
|
|
2462
|
-
provider: "Etherfuse",
|
|
2463
|
-
fee: 0.5,
|
|
2464
|
-
feeCurrency: "MXN",
|
|
2465
|
-
rate: 17.2,
|
|
2466
|
-
rail: "SPEI",
|
|
2467
|
-
protocol: "SEP-24",
|
|
2468
|
-
estimatedTime: "~10 min",
|
|
2469
|
-
recommended: true
|
|
2470
|
-
},
|
|
2471
|
-
{
|
|
2472
|
-
quoteId: "alfredpay-mx",
|
|
2473
|
-
provider: "AlfredPay",
|
|
2474
|
-
fee: 0.8,
|
|
2475
|
-
feeCurrency: "MXN",
|
|
2476
|
-
rate: 17.1,
|
|
2477
|
-
rail: "SPEI",
|
|
2478
|
-
protocol: "REST",
|
|
2479
|
-
estimatedTime: "~15 min",
|
|
2480
|
-
recommended: false
|
|
2481
|
-
}
|
|
2482
|
-
],
|
|
2483
|
-
BR: [
|
|
2484
|
-
{
|
|
2485
|
-
quoteId: "abroad-br",
|
|
2486
|
-
provider: "Abroad",
|
|
2487
|
-
fee: 0.6,
|
|
2488
|
-
feeCurrency: "BRL",
|
|
2489
|
-
rate: 5.1,
|
|
2490
|
-
rail: "PIX",
|
|
2491
|
-
protocol: "REST",
|
|
2492
|
-
estimatedTime: "~5 min",
|
|
2493
|
-
recommended: true
|
|
2494
|
-
}
|
|
2495
|
-
],
|
|
2496
|
-
CO: [
|
|
2497
|
-
{
|
|
2498
|
-
quoteId: "abroad-co",
|
|
2499
|
-
provider: "Abroad",
|
|
2500
|
-
fee: 0.7,
|
|
2501
|
-
feeCurrency: "COP",
|
|
2502
|
-
rate: 4100,
|
|
2503
|
-
rail: "PSE",
|
|
2504
|
-
protocol: "REST",
|
|
2505
|
-
estimatedTime: "~10 min",
|
|
2506
|
-
recommended: true
|
|
2507
|
-
},
|
|
2508
|
-
{
|
|
2509
|
-
quoteId: "koywe-co",
|
|
2510
|
-
provider: "Koywe",
|
|
2511
|
-
fee: 0.9,
|
|
2512
|
-
feeCurrency: "COP",
|
|
2513
|
-
rate: 4095,
|
|
2514
|
-
rail: "PSE",
|
|
2515
|
-
protocol: "REST",
|
|
2516
|
-
estimatedTime: "~15 min",
|
|
2517
|
-
recommended: false
|
|
2518
|
-
}
|
|
2519
|
-
],
|
|
2520
|
-
DEFAULT: MOCK_DEFAULT_QUOTES
|
|
2521
|
-
};
|
|
2522
|
-
var MOCK_PAYMENT = {
|
|
2523
|
-
type: "CLABE",
|
|
2524
|
-
value: "646180157088723456",
|
|
2525
|
-
amount: 1e3,
|
|
2526
|
-
currency: "MXN",
|
|
2527
|
-
expiresAt: new Date(Date.now() + 30 * 60 * 1e3).toISOString()
|
|
2528
|
-
};
|
|
2671
|
+
var TERMINAL = ["completed", "failed"];
|
|
2529
2672
|
function RampWidget({ onClose }) {
|
|
2530
|
-
const { getClient, wallet, styles } = usePollar();
|
|
2673
|
+
const { getClient, signTx, wallet, styles } = usePollar();
|
|
2531
2674
|
const walletAddress = wallet?.address ?? "";
|
|
2675
|
+
const client = getClient();
|
|
2676
|
+
const { theme = "light", accentColor = "#005DB4" } = styles;
|
|
2532
2677
|
const [step, setStep] = useState("input");
|
|
2533
2678
|
const [direction, setDirection] = useState("onramp");
|
|
2534
2679
|
const [amount, setAmount] = useState("");
|
|
2535
|
-
const [currency, setCurrency] = useState("
|
|
2536
|
-
const [country, setCountry] = useState("
|
|
2680
|
+
const [currency, setCurrency] = useState("ARS");
|
|
2681
|
+
const [country, setCountry] = useState("AR");
|
|
2537
2682
|
const [quotes, setQuotes] = useState([]);
|
|
2538
|
-
const [paymentInstructions, setPaymentInstructions] = useState(null);
|
|
2539
2683
|
const [isLoading, setIsLoading] = useState(false);
|
|
2540
|
-
const
|
|
2541
|
-
const
|
|
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
|
+
}
|
|
2542
2748
|
async function handleFindRoute() {
|
|
2543
2749
|
setStep("loading_quote");
|
|
2544
2750
|
setIsLoading(true);
|
|
2751
|
+
setErrorMsg(null);
|
|
2545
2752
|
try {
|
|
2546
|
-
const result = await client.getRampsQuote({
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
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");
|
|
2556
2765
|
} finally {
|
|
2557
2766
|
setIsLoading(false);
|
|
2558
|
-
setStep("select_route");
|
|
2559
2767
|
}
|
|
2560
2768
|
}
|
|
2561
2769
|
async function handleSelectQuote(quote) {
|
|
2562
|
-
if (!walletAddress) return;
|
|
2563
2770
|
setIsLoading(true);
|
|
2564
|
-
|
|
2565
|
-
quoteId: `${quote.provider}-${Date.now()}`,
|
|
2566
|
-
amount: Number(amount),
|
|
2567
|
-
currency,
|
|
2568
|
-
country,
|
|
2569
|
-
walletAddress
|
|
2570
|
-
};
|
|
2771
|
+
setErrorMsg(null);
|
|
2571
2772
|
try {
|
|
2572
|
-
const
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
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");
|
|
2577
2779
|
} finally {
|
|
2578
2780
|
setIsLoading(false);
|
|
2579
|
-
setStep("payment_instructions");
|
|
2580
2781
|
}
|
|
2581
2782
|
}
|
|
2582
|
-
function
|
|
2583
|
-
|
|
2584
|
-
|
|
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
|
+
}
|
|
2585
2806
|
}
|
|
2807
|
+
const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash;
|
|
2586
2808
|
return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsx(
|
|
2587
2809
|
RampWidgetTemplate,
|
|
2588
2810
|
{
|
|
@@ -2594,15 +2816,23 @@ function RampWidget({ onClose }) {
|
|
|
2594
2816
|
currency,
|
|
2595
2817
|
country,
|
|
2596
2818
|
quotes,
|
|
2597
|
-
paymentInstructions,
|
|
2598
2819
|
isLoading,
|
|
2820
|
+
provider,
|
|
2821
|
+
txStatus,
|
|
2822
|
+
kycUrl,
|
|
2823
|
+
stellarTxHash,
|
|
2824
|
+
canComplete,
|
|
2825
|
+
completing,
|
|
2826
|
+
errorMsg,
|
|
2599
2827
|
onDirectionChange: setDirection,
|
|
2600
2828
|
onAmountChange: setAmount,
|
|
2601
2829
|
onCurrencyChange: setCurrency,
|
|
2602
2830
|
onCountryChange: setCountry,
|
|
2603
2831
|
onFindRoute: handleFindRoute,
|
|
2604
2832
|
onSelectQuote: handleSelectQuote,
|
|
2605
|
-
|
|
2833
|
+
onOpenKyc: handleOpenKyc,
|
|
2834
|
+
onCompleteWithdraw: handleCompleteWithdraw,
|
|
2835
|
+
onRetry: resetToInput,
|
|
2606
2836
|
onClose
|
|
2607
2837
|
}
|
|
2608
2838
|
) });
|
|
@@ -3266,6 +3496,494 @@ function SendModal({ onClose }) {
|
|
|
3266
3496
|
}
|
|
3267
3497
|
) });
|
|
3268
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
|
+
function formatAmount2(value) {
|
|
3509
|
+
const n = parseFloat(value);
|
|
3510
|
+
return isNaN(n) ? value : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
|
|
3511
|
+
}
|
|
3512
|
+
function SwapModalTemplate({
|
|
3513
|
+
theme,
|
|
3514
|
+
accentColor,
|
|
3515
|
+
step,
|
|
3516
|
+
txTitle,
|
|
3517
|
+
sellOptions,
|
|
3518
|
+
buyOptions,
|
|
3519
|
+
selectedSell,
|
|
3520
|
+
selectedBuy,
|
|
3521
|
+
amount,
|
|
3522
|
+
provider,
|
|
3523
|
+
providers,
|
|
3524
|
+
quote,
|
|
3525
|
+
quoteLoading,
|
|
3526
|
+
quoteError,
|
|
3527
|
+
formError,
|
|
3528
|
+
isLoadingData,
|
|
3529
|
+
smartUnsupported,
|
|
3530
|
+
configLoading,
|
|
3531
|
+
swapUnavailable,
|
|
3532
|
+
buyNeedsTrustline,
|
|
3533
|
+
transaction,
|
|
3534
|
+
showXdr,
|
|
3535
|
+
copied,
|
|
3536
|
+
explorerUrl,
|
|
3537
|
+
walletType,
|
|
3538
|
+
showBack,
|
|
3539
|
+
isInProgress,
|
|
3540
|
+
onClose,
|
|
3541
|
+
onBack,
|
|
3542
|
+
onRefresh,
|
|
3543
|
+
onSelectSell,
|
|
3544
|
+
onSelectBuy,
|
|
3545
|
+
onAmountChange,
|
|
3546
|
+
onProviderChange,
|
|
3547
|
+
onSwap,
|
|
3548
|
+
onToggleXdr,
|
|
3549
|
+
onCopyHash,
|
|
3550
|
+
onRetry,
|
|
3551
|
+
onDone
|
|
3552
|
+
}) {
|
|
3553
|
+
const isDark = theme === "dark";
|
|
3554
|
+
const cssVars = {
|
|
3555
|
+
"--pollar-accent": accentColor,
|
|
3556
|
+
"--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
|
|
3557
|
+
"--pollar-border": isDark ? "#374151" : "#e5e7eb",
|
|
3558
|
+
"--pollar-text": isDark ? "#ffffff" : "#111827",
|
|
3559
|
+
"--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
|
|
3560
|
+
"--pollar-input-bg": isDark ? "#374151" : "#f9fafb",
|
|
3561
|
+
"--pollar-error-bg": isDark ? "#2a1515" : "#fef2f2",
|
|
3562
|
+
"--pollar-error-border": isDark ? "#7f1d1d" : "#fecaca",
|
|
3563
|
+
"--pollar-error-text": isDark ? "#f87171" : "#dc2626",
|
|
3564
|
+
"--pollar-success-text": isDark ? "#4ade80" : "#16a34a",
|
|
3565
|
+
"--pollar-buttons-border-radius": "6px",
|
|
3566
|
+
"--pollar-buttons-height": "44px",
|
|
3567
|
+
"--pollar-input-height": "44px",
|
|
3568
|
+
"--pollar-input-border-radius": "0.5rem",
|
|
3569
|
+
"--pollar-card-border-radius": "10px"
|
|
3570
|
+
};
|
|
3571
|
+
const sellKey = selectedSell ? assetOptionKey(selectedSell) : "";
|
|
3572
|
+
const buyKey = selectedBuy ? assetOptionKey(selectedBuy) : "";
|
|
3573
|
+
const canSwap = !smartUnsupported && !!selectedSell && !!selectedBuy && !!amount && !!quote && !quoteLoading && !isLoadingData;
|
|
3574
|
+
const title = step === "form" ? "Swap" : txTitle;
|
|
3575
|
+
return /* @__PURE__ */ jsxs("div", { className: "pollar-modal-card pollar-send-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
|
|
3576
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
|
|
3577
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-send-header-left", children: [
|
|
3578
|
+
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" }) }) }),
|
|
3579
|
+
/* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: title })
|
|
3580
|
+
] }),
|
|
3581
|
+
!isInProgress && /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header-actions", children: [
|
|
3582
|
+
step === "form" && /* @__PURE__ */ jsx(
|
|
3583
|
+
"button",
|
|
3584
|
+
{
|
|
3585
|
+
type: "button",
|
|
3586
|
+
className: "pollar-modal-close",
|
|
3587
|
+
onClick: onRefresh,
|
|
3588
|
+
disabled: configLoading || isLoadingData,
|
|
3589
|
+
"aria-label": "Refresh",
|
|
3590
|
+
title: "Refresh balances and options",
|
|
3591
|
+
children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx(
|
|
3592
|
+
"path",
|
|
3593
|
+
{
|
|
3594
|
+
d: "M13.5 8a5.5 5.5 0 1 1-1.6-3.9M13.5 2.5v3h-3",
|
|
3595
|
+
stroke: "currentColor",
|
|
3596
|
+
strokeWidth: "1.6",
|
|
3597
|
+
strokeLinecap: "round",
|
|
3598
|
+
strokeLinejoin: "round"
|
|
3599
|
+
}
|
|
3600
|
+
) })
|
|
3601
|
+
}
|
|
3602
|
+
),
|
|
3603
|
+
/* @__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" }) }) })
|
|
3604
|
+
] })
|
|
3605
|
+
] }),
|
|
3606
|
+
step === "form" && configLoading && /* @__PURE__ */ jsx("div", { className: "pollar-send-hint", children: "Loading swap options\u2026" }),
|
|
3607
|
+
step === "form" && !configLoading && swapUnavailable && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: "Swap is not available for this app." }),
|
|
3608
|
+
step === "form" && !configLoading && !swapUnavailable && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3609
|
+
smartUnsupported && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: "Swaps are not yet available for smart (passkey) wallets." }),
|
|
3610
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-send-field", children: [
|
|
3611
|
+
/* @__PURE__ */ jsx("label", { className: "pollar-send-label", children: "You pay" }),
|
|
3612
|
+
isLoadingData ? /* @__PURE__ */ jsx("div", { className: "pollar-send-skeleton" }) : /* @__PURE__ */ jsxs(
|
|
3613
|
+
"select",
|
|
3614
|
+
{
|
|
3615
|
+
className: "pollar-input pollar-send-select",
|
|
3616
|
+
value: sellKey,
|
|
3617
|
+
onChange: (e) => {
|
|
3618
|
+
const found = sellOptions.find((o) => assetOptionKey(o) === e.target.value);
|
|
3619
|
+
if (found) onSelectSell(found);
|
|
3620
|
+
},
|
|
3621
|
+
children: [
|
|
3622
|
+
/* @__PURE__ */ jsx("option", { value: "", disabled: true, children: "Select asset to sell" }),
|
|
3623
|
+
sellOptions.map((o) => /* @__PURE__ */ jsxs("option", { value: assetOptionKey(o), children: [
|
|
3624
|
+
o.code,
|
|
3625
|
+
o.available !== void 0 ? ` \u2014 ${formatAmount2(o.available)} available` : ""
|
|
3626
|
+
] }, assetOptionKey(o)))
|
|
3627
|
+
]
|
|
3628
|
+
}
|
|
3629
|
+
)
|
|
3630
|
+
] }),
|
|
3631
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-send-field", children: [
|
|
3632
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-send-label-row", children: [
|
|
3633
|
+
/* @__PURE__ */ jsx("label", { className: "pollar-send-label", children: "Amount" }),
|
|
3634
|
+
selectedSell?.available !== void 0 && /* @__PURE__ */ jsxs("span", { className: "pollar-send-hint", children: [
|
|
3635
|
+
"Available: ",
|
|
3636
|
+
formatAmount2(selectedSell.available),
|
|
3637
|
+
" ",
|
|
3638
|
+
selectedSell.code
|
|
3639
|
+
] })
|
|
3640
|
+
] }),
|
|
3641
|
+
/* @__PURE__ */ jsx(
|
|
3642
|
+
"input",
|
|
3643
|
+
{
|
|
3644
|
+
className: "pollar-input",
|
|
3645
|
+
type: "text",
|
|
3646
|
+
inputMode: "decimal",
|
|
3647
|
+
placeholder: "0.00",
|
|
3648
|
+
value: amount,
|
|
3649
|
+
onChange: (e) => onAmountChange(e.target.value)
|
|
3650
|
+
}
|
|
3651
|
+
)
|
|
3652
|
+
] }),
|
|
3653
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-send-field", children: [
|
|
3654
|
+
/* @__PURE__ */ jsx("label", { className: "pollar-send-label", children: "You receive" }),
|
|
3655
|
+
isLoadingData ? /* @__PURE__ */ jsx("div", { className: "pollar-send-skeleton" }) : /* @__PURE__ */ jsxs(
|
|
3656
|
+
"select",
|
|
3657
|
+
{
|
|
3658
|
+
className: "pollar-input pollar-send-select",
|
|
3659
|
+
value: buyKey,
|
|
3660
|
+
onChange: (e) => {
|
|
3661
|
+
const found = buyOptions.find((o) => assetOptionKey(o) === e.target.value);
|
|
3662
|
+
if (found) onSelectBuy(found);
|
|
3663
|
+
},
|
|
3664
|
+
children: [
|
|
3665
|
+
/* @__PURE__ */ jsx("option", { value: "", disabled: true, children: "Select asset to buy" }),
|
|
3666
|
+
buyOptions.map((o) => /* @__PURE__ */ jsxs("option", { value: assetOptionKey(o), children: [
|
|
3667
|
+
o.code,
|
|
3668
|
+
o.enabledInApp ? "" : " (external)"
|
|
3669
|
+
] }, assetOptionKey(o)))
|
|
3670
|
+
]
|
|
3671
|
+
}
|
|
3672
|
+
)
|
|
3673
|
+
] }),
|
|
3674
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-send-field", children: [
|
|
3675
|
+
/* @__PURE__ */ jsx("label", { className: "pollar-send-label", children: "Route" }),
|
|
3676
|
+
/* @__PURE__ */ jsx(
|
|
3677
|
+
"select",
|
|
3678
|
+
{
|
|
3679
|
+
className: "pollar-input pollar-send-select",
|
|
3680
|
+
value: provider,
|
|
3681
|
+
onChange: (e) => onProviderChange(e.target.value),
|
|
3682
|
+
children: providers.map((p) => /* @__PURE__ */ jsx("option", { value: p, children: PROVIDER_LABELS[p] }, p))
|
|
3683
|
+
}
|
|
3684
|
+
)
|
|
3685
|
+
] }),
|
|
3686
|
+
quoteLoading && /* @__PURE__ */ jsx("div", { className: "pollar-send-hint", children: "Fetching best price\u2026" }),
|
|
3687
|
+
!quoteLoading && quoteError && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: quoteError }),
|
|
3688
|
+
!quoteLoading && !quoteError && quote && selectedBuy && /* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote", children: [
|
|
3689
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
3690
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-send-hint", children: "You receive" }),
|
|
3691
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
3692
|
+
"~ ",
|
|
3693
|
+
formatAmount2(quote.amountOut),
|
|
3694
|
+
" ",
|
|
3695
|
+
selectedBuy.code
|
|
3696
|
+
] })
|
|
3697
|
+
] }),
|
|
3698
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
3699
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-send-hint", children: "Minimum received" }),
|
|
3700
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
3701
|
+
formatAmount2(quote.minReceived),
|
|
3702
|
+
" ",
|
|
3703
|
+
selectedBuy.code
|
|
3704
|
+
] })
|
|
3705
|
+
] }),
|
|
3706
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
3707
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-send-hint", children: "Price impact" }),
|
|
3708
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
3709
|
+
quote.priceImpactPct,
|
|
3710
|
+
"%"
|
|
3711
|
+
] })
|
|
3712
|
+
] }),
|
|
3713
|
+
/* @__PURE__ */ jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
3714
|
+
/* @__PURE__ */ jsx("span", { className: "pollar-send-hint", children: "Route" }),
|
|
3715
|
+
/* @__PURE__ */ jsx("span", { children: PROVIDER_LABELS[quote.provider] })
|
|
3716
|
+
] })
|
|
3717
|
+
] }),
|
|
3718
|
+
!quoteLoading && !quoteError && !quote && selectedSell && selectedBuy && !!amount && /* @__PURE__ */ jsx("div", { className: "pollar-send-hint", children: "No route found for this pair." }),
|
|
3719
|
+
buyNeedsTrustline && selectedBuy && /* @__PURE__ */ jsxs("div", { className: "pollar-swap-trustline-notice", children: [
|
|
3720
|
+
"To receive ",
|
|
3721
|
+
selectedBuy.code,
|
|
3722
|
+
" your wallet needs a trustline. Swapping will create it first (~0.5 XLM reserve, refundable if you later remove it)."
|
|
3723
|
+
] }),
|
|
3724
|
+
formError && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: formError }),
|
|
3725
|
+
/* @__PURE__ */ jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsx("button", { className: "pollar-btn-primary", onClick: onSwap, disabled: !canSwap, children: buyNeedsTrustline ? "Create trustline & swap" : "Swap" }) })
|
|
3726
|
+
] }),
|
|
3727
|
+
step === "tx" && /* @__PURE__ */ jsx(
|
|
3728
|
+
TxStatusView,
|
|
3729
|
+
{
|
|
3730
|
+
transaction,
|
|
3731
|
+
showXdr,
|
|
3732
|
+
copied,
|
|
3733
|
+
explorerUrl,
|
|
3734
|
+
walletType,
|
|
3735
|
+
onSignAndSend: () => {
|
|
3736
|
+
},
|
|
3737
|
+
onToggleXdr,
|
|
3738
|
+
onCopyHash,
|
|
3739
|
+
onRetry,
|
|
3740
|
+
onDone
|
|
3741
|
+
}
|
|
3742
|
+
),
|
|
3743
|
+
/* @__PURE__ */ jsx(PollarModalFooter, {})
|
|
3744
|
+
] });
|
|
3745
|
+
}
|
|
3746
|
+
var QUOTE_DEBOUNCE_MS = 400;
|
|
3747
|
+
function toRef(a) {
|
|
3748
|
+
if (a.type === "native") return { type: "native" };
|
|
3749
|
+
if (a.type === "credit_alphanum4") return { type: "credit_alphanum4", code: a.code, issuer: a.issuer };
|
|
3750
|
+
return { type: "credit_alphanum12", code: a.code, issuer: a.issuer };
|
|
3751
|
+
}
|
|
3752
|
+
function catalogRef(code, issuer) {
|
|
3753
|
+
return code.length <= 4 ? { type: "credit_alphanum4", code, issuer } : { type: "credit_alphanum12", code, issuer };
|
|
3754
|
+
}
|
|
3755
|
+
function SwapModal({ onClose }) {
|
|
3756
|
+
const {
|
|
3757
|
+
getSwapConfig,
|
|
3758
|
+
getSwapTokens,
|
|
3759
|
+
getSwapQuote,
|
|
3760
|
+
swap,
|
|
3761
|
+
walletBalance,
|
|
3762
|
+
refreshWalletBalance,
|
|
3763
|
+
enabledAssets,
|
|
3764
|
+
refreshAssets,
|
|
3765
|
+
tx: transaction,
|
|
3766
|
+
wallet,
|
|
3767
|
+
network,
|
|
3768
|
+
styles
|
|
3769
|
+
} = usePollar();
|
|
3770
|
+
const walletType = wallet?.custody === "external" ? wallet.provider : null;
|
|
3771
|
+
const smartUnsupported = wallet?.custody === "smart";
|
|
3772
|
+
const { theme = "light", accentColor = "#005DB4" } = styles;
|
|
3773
|
+
const [step, setStep] = useState("form");
|
|
3774
|
+
const [selectedSell, setSelectedSell] = useState(null);
|
|
3775
|
+
const [selectedBuy, setSelectedBuy] = useState(null);
|
|
3776
|
+
const [amount, setAmount] = useState("");
|
|
3777
|
+
const [provider, setProvider] = useState("auto");
|
|
3778
|
+
const [venues, setVenues] = useState(null);
|
|
3779
|
+
const [catalogTokens, setCatalogTokens] = useState([]);
|
|
3780
|
+
const [quotes, setQuotes] = useState([]);
|
|
3781
|
+
const [quoteLoading, setQuoteLoading] = useState(false);
|
|
3782
|
+
const [quoteError, setQuoteError] = useState("");
|
|
3783
|
+
const [formError, setFormError] = useState("");
|
|
3784
|
+
const [showXdr, setShowXdr] = useState(false);
|
|
3785
|
+
const [copied, setCopied] = useState(false);
|
|
3786
|
+
const copyTimerRef = useRef(null);
|
|
3787
|
+
const slippageBps = 50;
|
|
3788
|
+
useEffect(() => {
|
|
3789
|
+
void refreshWalletBalance();
|
|
3790
|
+
void refreshAssets();
|
|
3791
|
+
}, [refreshWalletBalance, refreshAssets]);
|
|
3792
|
+
const loadConfig = useCallback(() => {
|
|
3793
|
+
setVenues(null);
|
|
3794
|
+
return getSwapConfig().then(setVenues).catch(() => setVenues([]));
|
|
3795
|
+
}, [getSwapConfig]);
|
|
3796
|
+
useEffect(() => {
|
|
3797
|
+
void loadConfig();
|
|
3798
|
+
}, [loadConfig]);
|
|
3799
|
+
const loadCatalog = useCallback(
|
|
3800
|
+
() => getSwapTokens().then(setCatalogTokens).catch(() => setCatalogTokens([])),
|
|
3801
|
+
[getSwapTokens]
|
|
3802
|
+
);
|
|
3803
|
+
useEffect(() => {
|
|
3804
|
+
void loadCatalog();
|
|
3805
|
+
}, [loadCatalog]);
|
|
3806
|
+
function handleRefresh() {
|
|
3807
|
+
void refreshWalletBalance();
|
|
3808
|
+
void refreshAssets();
|
|
3809
|
+
void loadConfig();
|
|
3810
|
+
void loadCatalog();
|
|
3811
|
+
}
|
|
3812
|
+
useEffect(
|
|
3813
|
+
() => () => {
|
|
3814
|
+
if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
|
|
3815
|
+
},
|
|
3816
|
+
[]
|
|
3817
|
+
);
|
|
3818
|
+
const balances = walletBalance.step === "loaded" ? walletBalance.data.balances : [];
|
|
3819
|
+
const assetRecords = enabledAssets.step === "loaded" ? enabledAssets.data.assets : [];
|
|
3820
|
+
const isLoadingData = walletBalance.step === "loading" || enabledAssets.step === "loading";
|
|
3821
|
+
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 }));
|
|
3822
|
+
const buyKeyOfSell = selectedSell ? `${selectedSell.code}:${selectedSell.issuer ?? "native"}` : "";
|
|
3823
|
+
const optKey = (o) => `${o.code}:${o.issuer ?? "native"}`;
|
|
3824
|
+
const enabledBuy = assetRecords.map((a) => ({
|
|
3825
|
+
ref: toRef(a),
|
|
3826
|
+
code: a.code,
|
|
3827
|
+
issuer: a.issuer,
|
|
3828
|
+
enabledInApp: a.enabledInApp
|
|
3829
|
+
}));
|
|
3830
|
+
const enabledKeys = new Set(enabledBuy.map(optKey));
|
|
3831
|
+
const catalogBuy = catalogTokens.map((tk) => ({
|
|
3832
|
+
ref: catalogRef(tk.code, tk.issuer),
|
|
3833
|
+
code: tk.code,
|
|
3834
|
+
issuer: tk.issuer,
|
|
3835
|
+
enabledInApp: false
|
|
3836
|
+
})).filter((o) => !enabledKeys.has(optKey(o)));
|
|
3837
|
+
const buyOptions = [...enabledBuy, ...catalogBuy].filter((o) => optKey(o) !== buyKeyOfSell);
|
|
3838
|
+
const buyNeedsTrustline = (() => {
|
|
3839
|
+
if (!selectedBuy || smartUnsupported) return false;
|
|
3840
|
+
if (selectedBuy.ref.type === "native") return false;
|
|
3841
|
+
const rec = assetRecords.find((a) => a.code === selectedBuy.code && a.issuer === selectedBuy.issuer);
|
|
3842
|
+
return !rec?.trustlineEstablished;
|
|
3843
|
+
})();
|
|
3844
|
+
const configLoading = venues === null;
|
|
3845
|
+
const swapUnavailable = venues !== null && venues.length === 0;
|
|
3846
|
+
const providers = venues && venues.length > 0 ? ["auto", ...venues] : [];
|
|
3847
|
+
const quote = quotes[0] ?? null;
|
|
3848
|
+
useEffect(() => {
|
|
3849
|
+
if (step !== "form" || swapUnavailable || configLoading || !selectedSell || !selectedBuy || !amount || parseFloat(amount) <= 0) {
|
|
3850
|
+
setQuotes([]);
|
|
3851
|
+
setQuoteError("");
|
|
3852
|
+
setQuoteLoading(false);
|
|
3853
|
+
return;
|
|
3854
|
+
}
|
|
3855
|
+
let cancelled = false;
|
|
3856
|
+
setQuoteLoading(true);
|
|
3857
|
+
setQuoteError("");
|
|
3858
|
+
const t = setTimeout(async () => {
|
|
3859
|
+
try {
|
|
3860
|
+
const qs = await getSwapQuote({
|
|
3861
|
+
sellAsset: selectedSell.ref,
|
|
3862
|
+
buyAsset: selectedBuy.ref,
|
|
3863
|
+
amount,
|
|
3864
|
+
provider,
|
|
3865
|
+
slippageBps
|
|
3866
|
+
});
|
|
3867
|
+
if (!cancelled) setQuotes(qs);
|
|
3868
|
+
} catch (e) {
|
|
3869
|
+
if (!cancelled) {
|
|
3870
|
+
setQuotes([]);
|
|
3871
|
+
setQuoteError(e instanceof Error ? e.message : "Failed to fetch quote");
|
|
3872
|
+
}
|
|
3873
|
+
} finally {
|
|
3874
|
+
if (!cancelled) setQuoteLoading(false);
|
|
3875
|
+
}
|
|
3876
|
+
}, QUOTE_DEBOUNCE_MS);
|
|
3877
|
+
return () => {
|
|
3878
|
+
cancelled = true;
|
|
3879
|
+
clearTimeout(t);
|
|
3880
|
+
};
|
|
3881
|
+
}, [step, swapUnavailable, configLoading, selectedSell, selectedBuy, amount, provider, getSwapQuote]);
|
|
3882
|
+
const hash = transaction.step === "success" ? transaction.hash : null;
|
|
3883
|
+
const buildData = "buildData" in transaction ? transaction.buildData : null;
|
|
3884
|
+
const explorerNetwork = buildData?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : buildData ? "public" : network === "testnet" ? "testnet" : "public";
|
|
3885
|
+
const explorerUrl = hash ? `https://stellar.expert/explorer/${explorerNetwork}/tx/${hash}` : null;
|
|
3886
|
+
const IN_FLIGHT_STEPS2 = [
|
|
3887
|
+
"building",
|
|
3888
|
+
"signing",
|
|
3889
|
+
"submitting",
|
|
3890
|
+
"submitted",
|
|
3891
|
+
"signing-submitting",
|
|
3892
|
+
"building-signing-submitting"
|
|
3893
|
+
];
|
|
3894
|
+
const isInProgress = IN_FLIGHT_STEPS2.includes(transaction.step);
|
|
3895
|
+
const showBack = step === "tx" && (transaction.step === "error" || transaction.step === "success") && !isInProgress;
|
|
3896
|
+
const txTitle = isInProgress ? "Swapping\u2026" : transaction.step === "success" ? "Swapped!" : transaction.step === "error" ? "Swap failed" : "Confirm Swap";
|
|
3897
|
+
async function handleSwap() {
|
|
3898
|
+
setFormError("");
|
|
3899
|
+
if (smartUnsupported) {
|
|
3900
|
+
setFormError("Swaps are not yet supported for smart (passkey) wallets");
|
|
3901
|
+
return;
|
|
3902
|
+
}
|
|
3903
|
+
if (!selectedSell || !selectedBuy) {
|
|
3904
|
+
setFormError("Select both assets");
|
|
3905
|
+
return;
|
|
3906
|
+
}
|
|
3907
|
+
const parsed = parseFloat(amount);
|
|
3908
|
+
if (!amount || isNaN(parsed) || parsed <= 0) {
|
|
3909
|
+
setFormError("Enter a valid amount");
|
|
3910
|
+
return;
|
|
3911
|
+
}
|
|
3912
|
+
if (selectedSell.available !== void 0 && parsed > parseFloat(selectedSell.available)) {
|
|
3913
|
+
setFormError("Insufficient balance");
|
|
3914
|
+
return;
|
|
3915
|
+
}
|
|
3916
|
+
if (!quote) {
|
|
3917
|
+
setFormError("No route available for this pair");
|
|
3918
|
+
return;
|
|
3919
|
+
}
|
|
3920
|
+
setStep("tx");
|
|
3921
|
+
await swap(quote);
|
|
3922
|
+
}
|
|
3923
|
+
async function handleRetry() {
|
|
3924
|
+
if (transaction.step === "error" && quote) await swap(quote);
|
|
3925
|
+
}
|
|
3926
|
+
function handleCopyHash() {
|
|
3927
|
+
if (!hash) return;
|
|
3928
|
+
navigator.clipboard.writeText(hash).then(() => {
|
|
3929
|
+
setCopied(true);
|
|
3930
|
+
if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
|
|
3931
|
+
copyTimerRef.current = setTimeout(() => {
|
|
3932
|
+
copyTimerRef.current = null;
|
|
3933
|
+
setCopied(false);
|
|
3934
|
+
}, 2e3);
|
|
3935
|
+
});
|
|
3936
|
+
}
|
|
3937
|
+
function handleBack() {
|
|
3938
|
+
setStep("form");
|
|
3939
|
+
setShowXdr(false);
|
|
3940
|
+
setCopied(false);
|
|
3941
|
+
}
|
|
3942
|
+
return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", onClick: !isInProgress ? onClose : void 0, children: /* @__PURE__ */ jsx(
|
|
3943
|
+
SwapModalTemplate,
|
|
3944
|
+
{
|
|
3945
|
+
theme,
|
|
3946
|
+
accentColor,
|
|
3947
|
+
step,
|
|
3948
|
+
txTitle,
|
|
3949
|
+
sellOptions,
|
|
3950
|
+
buyOptions,
|
|
3951
|
+
selectedSell,
|
|
3952
|
+
selectedBuy,
|
|
3953
|
+
amount,
|
|
3954
|
+
provider,
|
|
3955
|
+
providers,
|
|
3956
|
+
quote,
|
|
3957
|
+
quoteLoading,
|
|
3958
|
+
quoteError,
|
|
3959
|
+
formError,
|
|
3960
|
+
isLoadingData,
|
|
3961
|
+
smartUnsupported,
|
|
3962
|
+
configLoading,
|
|
3963
|
+
swapUnavailable,
|
|
3964
|
+
buyNeedsTrustline,
|
|
3965
|
+
transaction,
|
|
3966
|
+
showXdr,
|
|
3967
|
+
copied,
|
|
3968
|
+
explorerUrl,
|
|
3969
|
+
walletType,
|
|
3970
|
+
showBack,
|
|
3971
|
+
isInProgress,
|
|
3972
|
+
onClose,
|
|
3973
|
+
onBack: handleBack,
|
|
3974
|
+
onRefresh: handleRefresh,
|
|
3975
|
+
onSelectSell: setSelectedSell,
|
|
3976
|
+
onSelectBuy: setSelectedBuy,
|
|
3977
|
+
onAmountChange: setAmount,
|
|
3978
|
+
onProviderChange: setProvider,
|
|
3979
|
+
onSwap: () => void handleSwap(),
|
|
3980
|
+
onToggleXdr: () => setShowXdr((v) => !v),
|
|
3981
|
+
onCopyHash: handleCopyHash,
|
|
3982
|
+
onRetry: () => void handleRetry(),
|
|
3983
|
+
onDone: onClose
|
|
3984
|
+
}
|
|
3985
|
+
) });
|
|
3986
|
+
}
|
|
3269
3987
|
function describeDevice(s) {
|
|
3270
3988
|
if (s.deviceLabel) return s.deviceLabel;
|
|
3271
3989
|
if (!s.userAgent) return "Unknown device";
|
|
@@ -3960,7 +4678,6 @@ var PollarContext = createContext(null);
|
|
|
3960
4678
|
function PollarProvider({
|
|
3961
4679
|
client,
|
|
3962
4680
|
appConfig: appConfigProp,
|
|
3963
|
-
ui,
|
|
3964
4681
|
adapters,
|
|
3965
4682
|
onStorageDegrade,
|
|
3966
4683
|
children
|
|
@@ -3968,6 +4685,18 @@ function PollarProvider({
|
|
|
3968
4685
|
const [pollarClient] = useState(
|
|
3969
4686
|
() => client instanceof PollarClient ? client : new PollarClient({ passkey: browserPasskeyCeremony, passkeySign: browserPasskeySigner, ...client })
|
|
3970
4687
|
);
|
|
4688
|
+
const ownsClientRef = useRef(!(client instanceof PollarClient));
|
|
4689
|
+
const destroyTimerRef = useRef(null);
|
|
4690
|
+
useEffect(() => {
|
|
4691
|
+
if (!ownsClientRef.current) return;
|
|
4692
|
+
if (destroyTimerRef.current) {
|
|
4693
|
+
clearTimeout(destroyTimerRef.current);
|
|
4694
|
+
destroyTimerRef.current = null;
|
|
4695
|
+
}
|
|
4696
|
+
return () => {
|
|
4697
|
+
destroyTimerRef.current = setTimeout(() => pollarClient.destroy(), 0);
|
|
4698
|
+
};
|
|
4699
|
+
}, [pollarClient]);
|
|
3971
4700
|
const [networkState, setNetworkState] = useState(() => pollarClient.getNetworkState());
|
|
3972
4701
|
const [sessionState, setSessionState] = useState(null);
|
|
3973
4702
|
const [verified, setVerified] = useState(false);
|
|
@@ -4012,6 +4741,30 @@ function PollarProvider({
|
|
|
4012
4741
|
}
|
|
4013
4742
|
});
|
|
4014
4743
|
}, [pollarClient]);
|
|
4744
|
+
const sessionRef = useRef(sessionState);
|
|
4745
|
+
sessionRef.current = sessionState;
|
|
4746
|
+
useEffect(() => {
|
|
4747
|
+
const unsubscribes = [];
|
|
4748
|
+
for (const { id } of pollarClient.listWalletAdapters()) {
|
|
4749
|
+
const adapter = pollarClient.getWalletAdapter(id);
|
|
4750
|
+
if (!isInteractiveAuthAdapter(adapter) || !adapter.onProviderAuthChange) continue;
|
|
4751
|
+
let triggered = false;
|
|
4752
|
+
unsubscribes.push(
|
|
4753
|
+
adapter.onProviderAuthChange((state) => {
|
|
4754
|
+
if (!state.authenticated || !state.address) {
|
|
4755
|
+
triggered = false;
|
|
4756
|
+
return;
|
|
4757
|
+
}
|
|
4758
|
+
if (triggered || sessionRef.current?.wallet?.address) return;
|
|
4759
|
+
triggered = true;
|
|
4760
|
+
pollarClient.login({ provider: id });
|
|
4761
|
+
})
|
|
4762
|
+
);
|
|
4763
|
+
}
|
|
4764
|
+
return () => {
|
|
4765
|
+
for (const unsubscribe of unsubscribes) unsubscribe();
|
|
4766
|
+
};
|
|
4767
|
+
}, [pollarClient]);
|
|
4015
4768
|
useEffect(() => {
|
|
4016
4769
|
setModalErrorLogger(pollarClient.getLogger());
|
|
4017
4770
|
}, [pollarClient]);
|
|
@@ -4037,6 +4790,7 @@ function PollarProvider({
|
|
|
4037
4790
|
const [walletBalanceModalOpen, setWalletBalanceModalOpen] = useState(false);
|
|
4038
4791
|
const [enabledAssetsModalOpen, setEnabledAssetsModalOpen] = useState(false);
|
|
4039
4792
|
const [sendModalOpen, setSendModalOpen] = useState(false);
|
|
4793
|
+
const [swapModalOpen, setSwapModalOpen] = useState(false);
|
|
4040
4794
|
const [receiveModalOpen, setReceiveModalOpen] = useState(false);
|
|
4041
4795
|
const [sessionsModalOpen, setSessionsModalOpen] = useState(false);
|
|
4042
4796
|
const [distributionRulesModalOpen, setDistributionRulesModalOpen] = useState(false);
|
|
@@ -4044,7 +4798,6 @@ function PollarProvider({
|
|
|
4044
4798
|
const getClient = useCallback(() => pollarClient, [pollarClient]);
|
|
4045
4799
|
const refreshWalletBalance = useCallback(() => pollarClient.refreshBalance(), [pollarClient, walletAddress]);
|
|
4046
4800
|
const refreshAssets = useCallback(() => pollarClient.refreshAssets(), [pollarClient, walletAddress]);
|
|
4047
|
-
const renderWallets = ui?.renderWallets;
|
|
4048
4801
|
const contextValue = useMemo(() => {
|
|
4049
4802
|
const styles = resolvedConfig.styles ?? {};
|
|
4050
4803
|
return {
|
|
@@ -4082,6 +4835,12 @@ function PollarProvider({
|
|
|
4082
4835
|
// send / receive
|
|
4083
4836
|
openSendModal: () => setSendModalOpen(true),
|
|
4084
4837
|
openReceiveModal: () => setReceiveModalOpen(true),
|
|
4838
|
+
// swap
|
|
4839
|
+
getSwapConfig: () => pollarClient.getSwapConfig(),
|
|
4840
|
+
getSwapTokens: () => pollarClient.getSwapTokens(),
|
|
4841
|
+
getSwapQuote: (params) => pollarClient.getSwapQuote(params),
|
|
4842
|
+
swap: (quote, opts) => pollarClient.swap(quote, opts),
|
|
4843
|
+
openSwapModal: () => setSwapModalOpen(true),
|
|
4085
4844
|
// sessions
|
|
4086
4845
|
sessions,
|
|
4087
4846
|
openSessionsModal: () => setSessionsModalOpen(true),
|
|
@@ -4100,7 +4859,6 @@ function PollarProvider({
|
|
|
4100
4859
|
// config
|
|
4101
4860
|
appConfig: resolvedConfig,
|
|
4102
4861
|
styles,
|
|
4103
|
-
renderWallets,
|
|
4104
4862
|
adapters
|
|
4105
4863
|
};
|
|
4106
4864
|
}, [
|
|
@@ -4117,8 +4875,7 @@ function PollarProvider({
|
|
|
4117
4875
|
refreshAssets,
|
|
4118
4876
|
networkState,
|
|
4119
4877
|
resolvedConfig,
|
|
4120
|
-
adapters
|
|
4121
|
-
renderWallets
|
|
4878
|
+
adapters
|
|
4122
4879
|
]);
|
|
4123
4880
|
return /* @__PURE__ */ jsxs(PollarContext.Provider, { value: contextValue, children: [
|
|
4124
4881
|
children,
|
|
@@ -4138,6 +4895,7 @@ function PollarProvider({
|
|
|
4138
4895
|
walletBalanceModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setWalletBalanceModalOpen(false), children: /* @__PURE__ */ jsx(WalletBalanceModal, { onClose: () => setWalletBalanceModalOpen(false) }) }),
|
|
4139
4896
|
enabledAssetsModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setEnabledAssetsModalOpen(false), children: /* @__PURE__ */ jsx(EnabledAssetsModal, { onClose: () => setEnabledAssetsModalOpen(false) }) }),
|
|
4140
4897
|
sendModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setSendModalOpen(false), children: /* @__PURE__ */ jsx(SendModal, { onClose: () => setSendModalOpen(false) }) }),
|
|
4898
|
+
swapModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setSwapModalOpen(false), children: /* @__PURE__ */ jsx(SwapModal, { onClose: () => setSwapModalOpen(false) }) }),
|
|
4141
4899
|
receiveModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setReceiveModalOpen(false), children: /* @__PURE__ */ jsx(ReceiveModal, { onClose: () => setReceiveModalOpen(false) }) }),
|
|
4142
4900
|
sessionsModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setSessionsModalOpen(false), children: /* @__PURE__ */ jsx(SessionsModal, { onClose: () => setSessionsModalOpen(false) }) }),
|
|
4143
4901
|
distributionRulesModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setDistributionRulesModalOpen(false), children: /* @__PURE__ */ jsx(DistributionRulesModal, { onClose: () => setDistributionRulesModalOpen(false) }) })
|
|
@@ -4586,6 +5344,6 @@ function WalletButton() {
|
|
|
4586
5344
|
);
|
|
4587
5345
|
}
|
|
4588
5346
|
|
|
4589
|
-
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 };
|
|
5347
|
+
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 };
|
|
4590
5348
|
//# sourceMappingURL=index.mjs.map
|
|
4591
5349
|
//# sourceMappingURL=index.mjs.map
|