@pollar/react 0.10.0-rc.8 → 0.10.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 +40 -11
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +83 -34
- package/dist/index.d.ts +83 -34
- package/dist/index.js +866 -199
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +866 -201
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
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
|
|
1038
|
+
"0.10.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
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
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
|
-
] }) :
|
|
1996
|
-
/* @__PURE__ */ jsxRuntime.jsx(BackButton, { onClick: () =>
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
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
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 === "
|
|
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:
|
|
2415
|
-
/* @__PURE__ */ jsxRuntime.
|
|
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: "
|
|
2422
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
" ",
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
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
|
-
|
|
2440
|
-
"
|
|
2441
|
-
|
|
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.
|
|
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
|
|
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("
|
|
2538
|
-
const [country, setCountry] = react.useState("
|
|
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
|
|
2543
|
-
const
|
|
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
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
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
|
-
|
|
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
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
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
|
|
2585
|
-
|
|
2586
|
-
});
|
|
2785
|
+
function handleOpenKyc() {
|
|
2786
|
+
if (kycUrl) window.open(kycUrl, "_blank", "noopener,noreferrer");
|
|
2587
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
|
+
}
|
|
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
|
-
|
|
2835
|
+
onOpenKyc: handleOpenKyc,
|
|
2836
|
+
onCompleteWithdraw: handleCompleteWithdraw,
|
|
2837
|
+
onRetry: resetToInput,
|
|
2608
2838
|
onClose
|
|
2609
2839
|
}
|
|
2610
2840
|
) });
|
|
@@ -3268,6 +3498,415 @@ 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
|
+
var IMPLEMENTED_PROVIDERS = ["auto", "aquarius"];
|
|
3511
|
+
function formatAmount2(value) {
|
|
3512
|
+
const n = parseFloat(value);
|
|
3513
|
+
return isNaN(n) ? value : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
|
|
3514
|
+
}
|
|
3515
|
+
function SwapModalTemplate({
|
|
3516
|
+
theme,
|
|
3517
|
+
accentColor,
|
|
3518
|
+
step,
|
|
3519
|
+
txTitle,
|
|
3520
|
+
sellOptions,
|
|
3521
|
+
buyOptions,
|
|
3522
|
+
selectedSell,
|
|
3523
|
+
selectedBuy,
|
|
3524
|
+
amount,
|
|
3525
|
+
provider,
|
|
3526
|
+
providers,
|
|
3527
|
+
quote,
|
|
3528
|
+
quoteLoading,
|
|
3529
|
+
quoteError,
|
|
3530
|
+
formError,
|
|
3531
|
+
isLoadingData,
|
|
3532
|
+
smartUnsupported,
|
|
3533
|
+
transaction,
|
|
3534
|
+
showXdr,
|
|
3535
|
+
copied,
|
|
3536
|
+
explorerUrl,
|
|
3537
|
+
walletType,
|
|
3538
|
+
showBack,
|
|
3539
|
+
isInProgress,
|
|
3540
|
+
onClose,
|
|
3541
|
+
onBack,
|
|
3542
|
+
onSelectSell,
|
|
3543
|
+
onSelectBuy,
|
|
3544
|
+
onAmountChange,
|
|
3545
|
+
onProviderChange,
|
|
3546
|
+
onSwap,
|
|
3547
|
+
onToggleXdr,
|
|
3548
|
+
onCopyHash,
|
|
3549
|
+
onRetry,
|
|
3550
|
+
onDone
|
|
3551
|
+
}) {
|
|
3552
|
+
const isDark = theme === "dark";
|
|
3553
|
+
const cssVars = {
|
|
3554
|
+
"--pollar-accent": accentColor,
|
|
3555
|
+
"--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
|
|
3556
|
+
"--pollar-border": isDark ? "#374151" : "#e5e7eb",
|
|
3557
|
+
"--pollar-text": isDark ? "#ffffff" : "#111827",
|
|
3558
|
+
"--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
|
|
3559
|
+
"--pollar-input-bg": isDark ? "#374151" : "#f9fafb",
|
|
3560
|
+
"--pollar-error-bg": isDark ? "#2a1515" : "#fef2f2",
|
|
3561
|
+
"--pollar-error-border": isDark ? "#7f1d1d" : "#fecaca",
|
|
3562
|
+
"--pollar-error-text": isDark ? "#f87171" : "#dc2626",
|
|
3563
|
+
"--pollar-success-text": isDark ? "#4ade80" : "#16a34a",
|
|
3564
|
+
"--pollar-buttons-border-radius": "6px",
|
|
3565
|
+
"--pollar-buttons-height": "44px",
|
|
3566
|
+
"--pollar-input-height": "44px",
|
|
3567
|
+
"--pollar-input-border-radius": "0.5rem",
|
|
3568
|
+
"--pollar-card-border-radius": "10px"
|
|
3569
|
+
};
|
|
3570
|
+
const sellKey = selectedSell ? assetOptionKey(selectedSell) : "";
|
|
3571
|
+
const buyKey = selectedBuy ? assetOptionKey(selectedBuy) : "";
|
|
3572
|
+
const canSwap = !smartUnsupported && !!selectedSell && !!selectedBuy && !!amount && !!quote && !quoteLoading && !isLoadingData;
|
|
3573
|
+
const title = step === "form" ? "Swap" : txTitle;
|
|
3574
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-card pollar-send-modal", "data-theme": theme, style: cssVars, onClick: (e) => e.stopPropagation(), children: [
|
|
3575
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
3576
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-header-left", children: [
|
|
3577
|
+
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" }) }) }),
|
|
3578
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: title })
|
|
3579
|
+
] }),
|
|
3580
|
+
!isInProgress && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) }) })
|
|
3581
|
+
] }),
|
|
3582
|
+
step === "form" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3583
|
+
smartUnsupported && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: "Swaps are not yet available for smart (passkey) wallets." }),
|
|
3584
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
3585
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "You pay" }),
|
|
3586
|
+
isLoadingData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-skeleton" }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3587
|
+
"select",
|
|
3588
|
+
{
|
|
3589
|
+
className: "pollar-input pollar-send-select",
|
|
3590
|
+
value: sellKey,
|
|
3591
|
+
onChange: (e) => {
|
|
3592
|
+
const found = sellOptions.find((o) => assetOptionKey(o) === e.target.value);
|
|
3593
|
+
if (found) onSelectSell(found);
|
|
3594
|
+
},
|
|
3595
|
+
children: [
|
|
3596
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: "Select asset to sell" }),
|
|
3597
|
+
sellOptions.map((o) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: assetOptionKey(o), children: [
|
|
3598
|
+
o.code,
|
|
3599
|
+
o.available !== void 0 ? ` \u2014 ${formatAmount2(o.available)} available` : ""
|
|
3600
|
+
] }, assetOptionKey(o)))
|
|
3601
|
+
]
|
|
3602
|
+
}
|
|
3603
|
+
)
|
|
3604
|
+
] }),
|
|
3605
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
3606
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-label-row", children: [
|
|
3607
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "Amount" }),
|
|
3608
|
+
selectedSell?.available !== void 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-send-hint", children: [
|
|
3609
|
+
"Available: ",
|
|
3610
|
+
formatAmount2(selectedSell.available),
|
|
3611
|
+
" ",
|
|
3612
|
+
selectedSell.code
|
|
3613
|
+
] })
|
|
3614
|
+
] }),
|
|
3615
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3616
|
+
"input",
|
|
3617
|
+
{
|
|
3618
|
+
className: "pollar-input",
|
|
3619
|
+
type: "text",
|
|
3620
|
+
inputMode: "decimal",
|
|
3621
|
+
placeholder: "0.00",
|
|
3622
|
+
value: amount,
|
|
3623
|
+
onChange: (e) => onAmountChange(e.target.value)
|
|
3624
|
+
}
|
|
3625
|
+
)
|
|
3626
|
+
] }),
|
|
3627
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
3628
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "You receive" }),
|
|
3629
|
+
isLoadingData ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-skeleton" }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3630
|
+
"select",
|
|
3631
|
+
{
|
|
3632
|
+
className: "pollar-input pollar-send-select",
|
|
3633
|
+
value: buyKey,
|
|
3634
|
+
onChange: (e) => {
|
|
3635
|
+
const found = buyOptions.find((o) => assetOptionKey(o) === e.target.value);
|
|
3636
|
+
if (found) onSelectBuy(found);
|
|
3637
|
+
},
|
|
3638
|
+
children: [
|
|
3639
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: true, children: "Select asset to buy" }),
|
|
3640
|
+
buyOptions.map((o) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: assetOptionKey(o), children: [
|
|
3641
|
+
o.code,
|
|
3642
|
+
o.enabledInApp ? "" : " (external)"
|
|
3643
|
+
] }, assetOptionKey(o)))
|
|
3644
|
+
]
|
|
3645
|
+
}
|
|
3646
|
+
)
|
|
3647
|
+
] }),
|
|
3648
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
3649
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "Route" }),
|
|
3650
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3651
|
+
"select",
|
|
3652
|
+
{
|
|
3653
|
+
className: "pollar-input pollar-send-select",
|
|
3654
|
+
value: provider,
|
|
3655
|
+
onChange: (e) => onProviderChange(e.target.value),
|
|
3656
|
+
children: providers.map((p) => {
|
|
3657
|
+
const implemented = IMPLEMENTED_PROVIDERS.includes(p);
|
|
3658
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("option", { value: p, disabled: !implemented, children: [
|
|
3659
|
+
PROVIDER_LABELS[p],
|
|
3660
|
+
implemented ? "" : " (coming soon)"
|
|
3661
|
+
] }, p);
|
|
3662
|
+
})
|
|
3663
|
+
}
|
|
3664
|
+
)
|
|
3665
|
+
] }),
|
|
3666
|
+
quoteLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-hint", children: "Fetching best price\u2026" }),
|
|
3667
|
+
!quoteLoading && quoteError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: quoteError }),
|
|
3668
|
+
!quoteLoading && !quoteError && quote && selectedBuy && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote", children: [
|
|
3669
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
3670
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-hint", children: "You receive" }),
|
|
3671
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
3672
|
+
"~ ",
|
|
3673
|
+
formatAmount2(quote.amountOut),
|
|
3674
|
+
" ",
|
|
3675
|
+
selectedBuy.code
|
|
3676
|
+
] })
|
|
3677
|
+
] }),
|
|
3678
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
3679
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-hint", children: "Minimum received" }),
|
|
3680
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
3681
|
+
formatAmount2(quote.minReceived),
|
|
3682
|
+
" ",
|
|
3683
|
+
selectedBuy.code
|
|
3684
|
+
] })
|
|
3685
|
+
] }),
|
|
3686
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
3687
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-hint", children: "Price impact" }),
|
|
3688
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
3689
|
+
quote.priceImpactPct,
|
|
3690
|
+
"%"
|
|
3691
|
+
] })
|
|
3692
|
+
] }),
|
|
3693
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-quote-row", children: [
|
|
3694
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-hint", children: "Route" }),
|
|
3695
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: PROVIDER_LABELS[quote.provider] })
|
|
3696
|
+
] })
|
|
3697
|
+
] }),
|
|
3698
|
+
!quoteLoading && !quoteError && !quote && selectedSell && selectedBuy && !!amount && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-hint", children: "No route found for this pair." }),
|
|
3699
|
+
formError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: formError }),
|
|
3700
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-primary", onClick: onSwap, disabled: !canSwap, children: "Swap" }) })
|
|
3701
|
+
] }),
|
|
3702
|
+
step === "tx" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3703
|
+
TxStatusView,
|
|
3704
|
+
{
|
|
3705
|
+
transaction,
|
|
3706
|
+
showXdr,
|
|
3707
|
+
copied,
|
|
3708
|
+
explorerUrl,
|
|
3709
|
+
walletType,
|
|
3710
|
+
onSignAndSend: () => {
|
|
3711
|
+
},
|
|
3712
|
+
onToggleXdr,
|
|
3713
|
+
onCopyHash,
|
|
3714
|
+
onRetry,
|
|
3715
|
+
onDone
|
|
3716
|
+
}
|
|
3717
|
+
),
|
|
3718
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
3719
|
+
] });
|
|
3720
|
+
}
|
|
3721
|
+
var QUOTE_DEBOUNCE_MS = 400;
|
|
3722
|
+
var ALL_PROVIDERS = ["auto", "aquarius", "soroswap", "sdex"];
|
|
3723
|
+
function toRef(a) {
|
|
3724
|
+
if (a.type === "native") return { type: "native" };
|
|
3725
|
+
if (a.type === "credit_alphanum4") return { type: "credit_alphanum4", code: a.code, issuer: a.issuer };
|
|
3726
|
+
return { type: "credit_alphanum12", code: a.code, issuer: a.issuer };
|
|
3727
|
+
}
|
|
3728
|
+
function SwapModal({ onClose }) {
|
|
3729
|
+
const {
|
|
3730
|
+
getSwapQuote,
|
|
3731
|
+
swap,
|
|
3732
|
+
walletBalance,
|
|
3733
|
+
refreshWalletBalance,
|
|
3734
|
+
enabledAssets,
|
|
3735
|
+
refreshAssets,
|
|
3736
|
+
tx: transaction,
|
|
3737
|
+
wallet,
|
|
3738
|
+
network,
|
|
3739
|
+
styles
|
|
3740
|
+
} = usePollar();
|
|
3741
|
+
const walletType = wallet?.custody === "external" ? wallet.provider : null;
|
|
3742
|
+
const smartUnsupported = wallet?.custody === "smart";
|
|
3743
|
+
const { theme = "light", accentColor = "#005DB4" } = styles;
|
|
3744
|
+
const [step, setStep] = react.useState("form");
|
|
3745
|
+
const [selectedSell, setSelectedSell] = react.useState(null);
|
|
3746
|
+
const [selectedBuy, setSelectedBuy] = react.useState(null);
|
|
3747
|
+
const [amount, setAmount] = react.useState("");
|
|
3748
|
+
const [provider, setProvider] = react.useState("auto");
|
|
3749
|
+
const [quotes, setQuotes] = react.useState([]);
|
|
3750
|
+
const [quoteLoading, setQuoteLoading] = react.useState(false);
|
|
3751
|
+
const [quoteError, setQuoteError] = react.useState("");
|
|
3752
|
+
const [formError, setFormError] = react.useState("");
|
|
3753
|
+
const [showXdr, setShowXdr] = react.useState(false);
|
|
3754
|
+
const [copied, setCopied] = react.useState(false);
|
|
3755
|
+
const copyTimerRef = react.useRef(null);
|
|
3756
|
+
const slippageBps = 50;
|
|
3757
|
+
react.useEffect(() => {
|
|
3758
|
+
void refreshWalletBalance();
|
|
3759
|
+
void refreshAssets();
|
|
3760
|
+
}, [refreshWalletBalance, refreshAssets]);
|
|
3761
|
+
react.useEffect(
|
|
3762
|
+
() => () => {
|
|
3763
|
+
if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
|
|
3764
|
+
},
|
|
3765
|
+
[]
|
|
3766
|
+
);
|
|
3767
|
+
const balances = walletBalance.step === "loaded" ? walletBalance.data.balances : [];
|
|
3768
|
+
const assetRecords = enabledAssets.step === "loaded" ? enabledAssets.data.assets : [];
|
|
3769
|
+
const isLoadingData = walletBalance.step === "loading" || enabledAssets.step === "loading";
|
|
3770
|
+
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 }));
|
|
3771
|
+
const buyKeyOfSell = selectedSell ? `${selectedSell.code}:${selectedSell.issuer ?? "native"}` : "";
|
|
3772
|
+
const buyOptions = assetRecords.map((a) => ({ ref: toRef(a), code: a.code, issuer: a.issuer, enabledInApp: a.enabledInApp })).filter((o) => `${o.code}:${o.issuer ?? "native"}` !== buyKeyOfSell);
|
|
3773
|
+
const providers = smartUnsupported ? ALL_PROVIDERS.filter((p) => p !== "sdex") : ALL_PROVIDERS;
|
|
3774
|
+
const quote = quotes[0] ?? null;
|
|
3775
|
+
react.useEffect(() => {
|
|
3776
|
+
if (step !== "form" || !selectedSell || !selectedBuy || !amount || parseFloat(amount) <= 0) {
|
|
3777
|
+
setQuotes([]);
|
|
3778
|
+
setQuoteError("");
|
|
3779
|
+
setQuoteLoading(false);
|
|
3780
|
+
return;
|
|
3781
|
+
}
|
|
3782
|
+
let cancelled = false;
|
|
3783
|
+
setQuoteLoading(true);
|
|
3784
|
+
setQuoteError("");
|
|
3785
|
+
const t = setTimeout(async () => {
|
|
3786
|
+
try {
|
|
3787
|
+
const qs = await getSwapQuote({
|
|
3788
|
+
sellAsset: selectedSell.ref,
|
|
3789
|
+
buyAsset: selectedBuy.ref,
|
|
3790
|
+
amount,
|
|
3791
|
+
provider,
|
|
3792
|
+
slippageBps
|
|
3793
|
+
});
|
|
3794
|
+
if (!cancelled) setQuotes(qs);
|
|
3795
|
+
} catch (e) {
|
|
3796
|
+
if (!cancelled) {
|
|
3797
|
+
setQuotes([]);
|
|
3798
|
+
setQuoteError(e instanceof Error ? e.message : "Failed to fetch quote");
|
|
3799
|
+
}
|
|
3800
|
+
} finally {
|
|
3801
|
+
if (!cancelled) setQuoteLoading(false);
|
|
3802
|
+
}
|
|
3803
|
+
}, QUOTE_DEBOUNCE_MS);
|
|
3804
|
+
return () => {
|
|
3805
|
+
cancelled = true;
|
|
3806
|
+
clearTimeout(t);
|
|
3807
|
+
};
|
|
3808
|
+
}, [step, selectedSell, selectedBuy, amount, provider, getSwapQuote]);
|
|
3809
|
+
const hash = transaction.step === "success" ? transaction.hash : null;
|
|
3810
|
+
const buildData = "buildData" in transaction ? transaction.buildData : null;
|
|
3811
|
+
const explorerNetwork = buildData?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : buildData ? "public" : network === "testnet" ? "testnet" : "public";
|
|
3812
|
+
const explorerUrl = hash ? `https://stellar.expert/explorer/${explorerNetwork}/tx/${hash}` : null;
|
|
3813
|
+
const IN_FLIGHT_STEPS2 = [
|
|
3814
|
+
"building",
|
|
3815
|
+
"signing",
|
|
3816
|
+
"submitting",
|
|
3817
|
+
"submitted",
|
|
3818
|
+
"signing-submitting",
|
|
3819
|
+
"building-signing-submitting"
|
|
3820
|
+
];
|
|
3821
|
+
const isInProgress = IN_FLIGHT_STEPS2.includes(transaction.step);
|
|
3822
|
+
const showBack = step === "tx" && (transaction.step === "error" || transaction.step === "success") && !isInProgress;
|
|
3823
|
+
const txTitle = isInProgress ? "Swapping\u2026" : transaction.step === "success" ? "Swapped!" : transaction.step === "error" ? "Swap failed" : "Confirm Swap";
|
|
3824
|
+
async function handleSwap() {
|
|
3825
|
+
setFormError("");
|
|
3826
|
+
if (smartUnsupported) {
|
|
3827
|
+
setFormError("Swaps are not yet supported for smart (passkey) wallets");
|
|
3828
|
+
return;
|
|
3829
|
+
}
|
|
3830
|
+
if (!selectedSell || !selectedBuy) {
|
|
3831
|
+
setFormError("Select both assets");
|
|
3832
|
+
return;
|
|
3833
|
+
}
|
|
3834
|
+
const parsed = parseFloat(amount);
|
|
3835
|
+
if (!amount || isNaN(parsed) || parsed <= 0) {
|
|
3836
|
+
setFormError("Enter a valid amount");
|
|
3837
|
+
return;
|
|
3838
|
+
}
|
|
3839
|
+
if (selectedSell.available !== void 0 && parsed > parseFloat(selectedSell.available)) {
|
|
3840
|
+
setFormError("Insufficient balance");
|
|
3841
|
+
return;
|
|
3842
|
+
}
|
|
3843
|
+
if (!quote) {
|
|
3844
|
+
setFormError("No route available for this pair");
|
|
3845
|
+
return;
|
|
3846
|
+
}
|
|
3847
|
+
setStep("tx");
|
|
3848
|
+
await swap(quote);
|
|
3849
|
+
}
|
|
3850
|
+
async function handleRetry() {
|
|
3851
|
+
if (transaction.step === "error" && quote) await swap(quote);
|
|
3852
|
+
}
|
|
3853
|
+
function handleCopyHash() {
|
|
3854
|
+
if (!hash) return;
|
|
3855
|
+
navigator.clipboard.writeText(hash).then(() => {
|
|
3856
|
+
setCopied(true);
|
|
3857
|
+
if (copyTimerRef.current !== null) clearTimeout(copyTimerRef.current);
|
|
3858
|
+
copyTimerRef.current = setTimeout(() => {
|
|
3859
|
+
copyTimerRef.current = null;
|
|
3860
|
+
setCopied(false);
|
|
3861
|
+
}, 2e3);
|
|
3862
|
+
});
|
|
3863
|
+
}
|
|
3864
|
+
function handleBack() {
|
|
3865
|
+
setStep("form");
|
|
3866
|
+
setShowXdr(false);
|
|
3867
|
+
setCopied(false);
|
|
3868
|
+
}
|
|
3869
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", onClick: !isInProgress ? onClose : void 0, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3870
|
+
SwapModalTemplate,
|
|
3871
|
+
{
|
|
3872
|
+
theme,
|
|
3873
|
+
accentColor,
|
|
3874
|
+
step,
|
|
3875
|
+
txTitle,
|
|
3876
|
+
sellOptions,
|
|
3877
|
+
buyOptions,
|
|
3878
|
+
selectedSell,
|
|
3879
|
+
selectedBuy,
|
|
3880
|
+
amount,
|
|
3881
|
+
provider,
|
|
3882
|
+
providers,
|
|
3883
|
+
quote,
|
|
3884
|
+
quoteLoading,
|
|
3885
|
+
quoteError,
|
|
3886
|
+
formError,
|
|
3887
|
+
isLoadingData,
|
|
3888
|
+
smartUnsupported,
|
|
3889
|
+
transaction,
|
|
3890
|
+
showXdr,
|
|
3891
|
+
copied,
|
|
3892
|
+
explorerUrl,
|
|
3893
|
+
walletType,
|
|
3894
|
+
showBack,
|
|
3895
|
+
isInProgress,
|
|
3896
|
+
onClose,
|
|
3897
|
+
onBack: handleBack,
|
|
3898
|
+
onSelectSell: setSelectedSell,
|
|
3899
|
+
onSelectBuy: setSelectedBuy,
|
|
3900
|
+
onAmountChange: setAmount,
|
|
3901
|
+
onProviderChange: setProvider,
|
|
3902
|
+
onSwap: () => void handleSwap(),
|
|
3903
|
+
onToggleXdr: () => setShowXdr((v) => !v),
|
|
3904
|
+
onCopyHash: handleCopyHash,
|
|
3905
|
+
onRetry: () => void handleRetry(),
|
|
3906
|
+
onDone: onClose
|
|
3907
|
+
}
|
|
3908
|
+
) });
|
|
3909
|
+
}
|
|
3271
3910
|
function describeDevice(s) {
|
|
3272
3911
|
if (s.deviceLabel) return s.deviceLabel;
|
|
3273
3912
|
if (!s.userAgent) return "Unknown device";
|
|
@@ -3962,7 +4601,6 @@ var PollarContext = react.createContext(null);
|
|
|
3962
4601
|
function PollarProvider({
|
|
3963
4602
|
client,
|
|
3964
4603
|
appConfig: appConfigProp,
|
|
3965
|
-
ui,
|
|
3966
4604
|
adapters,
|
|
3967
4605
|
onStorageDegrade,
|
|
3968
4606
|
children
|
|
@@ -4014,6 +4652,30 @@ function PollarProvider({
|
|
|
4014
4652
|
}
|
|
4015
4653
|
});
|
|
4016
4654
|
}, [pollarClient]);
|
|
4655
|
+
const sessionRef = react.useRef(sessionState);
|
|
4656
|
+
sessionRef.current = sessionState;
|
|
4657
|
+
react.useEffect(() => {
|
|
4658
|
+
const unsubscribes = [];
|
|
4659
|
+
for (const { id } of pollarClient.listWalletAdapters()) {
|
|
4660
|
+
const adapter = pollarClient.getWalletAdapter(id);
|
|
4661
|
+
if (!core.isInteractiveAuthAdapter(adapter) || !adapter.onProviderAuthChange) continue;
|
|
4662
|
+
let triggered = false;
|
|
4663
|
+
unsubscribes.push(
|
|
4664
|
+
adapter.onProviderAuthChange((state) => {
|
|
4665
|
+
if (!state.authenticated || !state.address) {
|
|
4666
|
+
triggered = false;
|
|
4667
|
+
return;
|
|
4668
|
+
}
|
|
4669
|
+
if (triggered || sessionRef.current?.wallet?.address) return;
|
|
4670
|
+
triggered = true;
|
|
4671
|
+
pollarClient.login({ provider: id });
|
|
4672
|
+
})
|
|
4673
|
+
);
|
|
4674
|
+
}
|
|
4675
|
+
return () => {
|
|
4676
|
+
for (const unsubscribe of unsubscribes) unsubscribe();
|
|
4677
|
+
};
|
|
4678
|
+
}, [pollarClient]);
|
|
4017
4679
|
react.useEffect(() => {
|
|
4018
4680
|
setModalErrorLogger(pollarClient.getLogger());
|
|
4019
4681
|
}, [pollarClient]);
|
|
@@ -4039,6 +4701,7 @@ function PollarProvider({
|
|
|
4039
4701
|
const [walletBalanceModalOpen, setWalletBalanceModalOpen] = react.useState(false);
|
|
4040
4702
|
const [enabledAssetsModalOpen, setEnabledAssetsModalOpen] = react.useState(false);
|
|
4041
4703
|
const [sendModalOpen, setSendModalOpen] = react.useState(false);
|
|
4704
|
+
const [swapModalOpen, setSwapModalOpen] = react.useState(false);
|
|
4042
4705
|
const [receiveModalOpen, setReceiveModalOpen] = react.useState(false);
|
|
4043
4706
|
const [sessionsModalOpen, setSessionsModalOpen] = react.useState(false);
|
|
4044
4707
|
const [distributionRulesModalOpen, setDistributionRulesModalOpen] = react.useState(false);
|
|
@@ -4046,7 +4709,6 @@ function PollarProvider({
|
|
|
4046
4709
|
const getClient = react.useCallback(() => pollarClient, [pollarClient]);
|
|
4047
4710
|
const refreshWalletBalance = react.useCallback(() => pollarClient.refreshBalance(), [pollarClient, walletAddress]);
|
|
4048
4711
|
const refreshAssets = react.useCallback(() => pollarClient.refreshAssets(), [pollarClient, walletAddress]);
|
|
4049
|
-
const renderWallets = ui?.renderWallets;
|
|
4050
4712
|
const contextValue = react.useMemo(() => {
|
|
4051
4713
|
const styles = resolvedConfig.styles ?? {};
|
|
4052
4714
|
return {
|
|
@@ -4084,6 +4746,10 @@ function PollarProvider({
|
|
|
4084
4746
|
// send / receive
|
|
4085
4747
|
openSendModal: () => setSendModalOpen(true),
|
|
4086
4748
|
openReceiveModal: () => setReceiveModalOpen(true),
|
|
4749
|
+
// swap
|
|
4750
|
+
getSwapQuote: (params) => pollarClient.getSwapQuote(params),
|
|
4751
|
+
swap: (quote, opts) => pollarClient.swap(quote, opts),
|
|
4752
|
+
openSwapModal: () => setSwapModalOpen(true),
|
|
4087
4753
|
// sessions
|
|
4088
4754
|
sessions,
|
|
4089
4755
|
openSessionsModal: () => setSessionsModalOpen(true),
|
|
@@ -4102,7 +4768,6 @@ function PollarProvider({
|
|
|
4102
4768
|
// config
|
|
4103
4769
|
appConfig: resolvedConfig,
|
|
4104
4770
|
styles,
|
|
4105
|
-
renderWallets,
|
|
4106
4771
|
adapters
|
|
4107
4772
|
};
|
|
4108
4773
|
}, [
|
|
@@ -4119,8 +4784,7 @@ function PollarProvider({
|
|
|
4119
4784
|
refreshAssets,
|
|
4120
4785
|
networkState,
|
|
4121
4786
|
resolvedConfig,
|
|
4122
|
-
adapters
|
|
4123
|
-
renderWallets
|
|
4787
|
+
adapters
|
|
4124
4788
|
]);
|
|
4125
4789
|
return /* @__PURE__ */ jsxRuntime.jsxs(PollarContext.Provider, { value: contextValue, children: [
|
|
4126
4790
|
children,
|
|
@@ -4140,6 +4804,7 @@ function PollarProvider({
|
|
|
4140
4804
|
walletBalanceModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setWalletBalanceModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(WalletBalanceModal, { onClose: () => setWalletBalanceModalOpen(false) }) }),
|
|
4141
4805
|
enabledAssetsModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setEnabledAssetsModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(EnabledAssetsModal, { onClose: () => setEnabledAssetsModalOpen(false) }) }),
|
|
4142
4806
|
sendModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSendModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SendModal, { onClose: () => setSendModalOpen(false) }) }),
|
|
4807
|
+
swapModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSwapModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SwapModal, { onClose: () => setSwapModalOpen(false) }) }),
|
|
4143
4808
|
receiveModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setReceiveModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(ReceiveModal, { onClose: () => setReceiveModalOpen(false) }) }),
|
|
4144
4809
|
sessionsModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSessionsModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SessionsModal, { onClose: () => setSessionsModalOpen(false) }) }),
|
|
4145
4810
|
distributionRulesModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setDistributionRulesModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(DistributionRulesModal, { onClose: () => setDistributionRulesModalOpen(false) }) })
|
|
@@ -4606,6 +5271,8 @@ exports.SendModal = SendModal;
|
|
|
4606
5271
|
exports.SendModalTemplate = SendModalTemplate;
|
|
4607
5272
|
exports.SessionsModal = SessionsModal;
|
|
4608
5273
|
exports.SessionsModalTemplate = SessionsModalTemplate;
|
|
5274
|
+
exports.SwapModal = SwapModal;
|
|
5275
|
+
exports.SwapModalTemplate = SwapModalTemplate;
|
|
4609
5276
|
exports.TransactionModalTemplate = TransactionModalTemplate;
|
|
4610
5277
|
exports.TxHistoryModalTemplate = TxHistoryModalTemplate;
|
|
4611
5278
|
exports.TxStatusView = TxStatusView;
|