@pollar/react 0.10.0-rc.0 → 0.10.0-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -47
- package/dist/index.css +40 -11
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +92 -64
- package/dist/index.d.ts +92 -64
- package/dist/index.js +869 -243
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +869 -245
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1035,7 +1035,7 @@ var PollarModalFooter = () => {
|
|
|
1035
1035
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
|
|
1036
1036
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-footer-version", children: [
|
|
1037
1037
|
"v",
|
|
1038
|
-
"0.10.0-rc.
|
|
1038
|
+
"0.10.0-rc.10"
|
|
1039
1039
|
] })
|
|
1040
1040
|
] })
|
|
1041
1041
|
] });
|
|
@@ -1852,35 +1852,42 @@ var GoogleButton = ({ disabled, onClick }) => {
|
|
|
1852
1852
|
] })
|
|
1853
1853
|
] });
|
|
1854
1854
|
};
|
|
1855
|
-
function
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
onClick: () => onConnect(core.WalletType.FREIGHTER),
|
|
1864
|
-
children: [
|
|
1865
|
-
/* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_FREIGHTER, alt: "Freighter", className: "pollar-wallet-list-icon" }),
|
|
1866
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-wallet-list-name", children: "Freighter" })
|
|
1867
|
-
]
|
|
1868
|
-
}
|
|
1869
|
-
),
|
|
1870
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1855
|
+
function WalletAdapterButtons({
|
|
1856
|
+
walletAdapters,
|
|
1857
|
+
onConnect,
|
|
1858
|
+
isLoading,
|
|
1859
|
+
variant = "list"
|
|
1860
|
+
}) {
|
|
1861
|
+
if (variant === "entry") {
|
|
1862
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: walletAdapters.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1871
1863
|
"button",
|
|
1872
1864
|
{
|
|
1873
1865
|
type: "button",
|
|
1874
1866
|
disabled: isLoading,
|
|
1875
|
-
className: "pollar-wallet-
|
|
1876
|
-
onClick: () => onConnect(
|
|
1867
|
+
className: "pollar-wallet-entry-btn",
|
|
1868
|
+
onClick: () => onConnect(a.id),
|
|
1877
1869
|
children: [
|
|
1878
|
-
/* @__PURE__ */ jsxRuntime.jsx("img", { src:
|
|
1879
|
-
|
|
1870
|
+
a.meta.iconUrl && /* @__PURE__ */ jsxRuntime.jsx("img", { src: a.meta.iconUrl, alt: a.meta.label, className: "pollar-wallet-icon" }),
|
|
1871
|
+
a.meta.label
|
|
1880
1872
|
]
|
|
1881
|
-
}
|
|
1882
|
-
|
|
1883
|
-
|
|
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
|
+
)) });
|
|
1884
1891
|
}
|
|
1885
1892
|
var AUTH_STATE_MESSAGES = {
|
|
1886
1893
|
idle: "",
|
|
@@ -1928,17 +1935,15 @@ function LoginModalTemplate({
|
|
|
1928
1935
|
embeddedWallets,
|
|
1929
1936
|
smartWallet = false,
|
|
1930
1937
|
providers,
|
|
1931
|
-
|
|
1938
|
+
walletAdapters,
|
|
1932
1939
|
appName,
|
|
1933
1940
|
email = "",
|
|
1934
1941
|
onEmailChange,
|
|
1935
1942
|
onEmailSubmit,
|
|
1936
1943
|
onSocialLogin,
|
|
1937
|
-
onCustomLogin,
|
|
1938
1944
|
onWalletConnect,
|
|
1939
1945
|
onLoginSmartWallet,
|
|
1940
1946
|
onCreateSmartWallet,
|
|
1941
|
-
renderWallets,
|
|
1942
1947
|
authState,
|
|
1943
1948
|
codeInputKey,
|
|
1944
1949
|
onCodeSubmit,
|
|
@@ -1946,10 +1951,19 @@ function LoginModalTemplate({
|
|
|
1946
1951
|
onCancel,
|
|
1947
1952
|
onRetry
|
|
1948
1953
|
}) {
|
|
1949
|
-
const [showWalletPicker, setShowWalletPicker] = react.useState(false);
|
|
1950
1954
|
const [showPasskeyChooser, setShowPasskeyChooser] = react.useState(false);
|
|
1955
|
+
const [activeGroup, setActiveGroup] = react.useState(null);
|
|
1951
1956
|
const isDark = theme === "dark";
|
|
1952
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 ?? [];
|
|
1953
1967
|
const cssVars = {
|
|
1954
1968
|
"--pollar-accent": accentColor,
|
|
1955
1969
|
"--pollar-bg": isDark ? "#1a1a1a" : "#ffffff",
|
|
@@ -2013,11 +2027,17 @@ function LoginModalTemplate({
|
|
|
2013
2027
|
/* @__PURE__ */ jsxRuntime.jsx(BackButton, { onClick: onBack }),
|
|
2014
2028
|
/* @__PURE__ */ jsxRuntime.jsx(EmailCodeInput, { email, onSubmit: onCodeSubmit ?? (() => {
|
|
2015
2029
|
}) }, codeInputKey)
|
|
2016
|
-
] }) :
|
|
2017
|
-
/* @__PURE__ */ jsxRuntime.jsx(BackButton, { onClick: () =>
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
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
|
+
)
|
|
2021
2041
|
] }) : showPasskeyChooser ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2022
2042
|
/* @__PURE__ */ jsxRuntime.jsx(BackButton, { onClick: () => setShowPasskeyChooser(false) }),
|
|
2023
2043
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-section", children: [
|
|
@@ -2050,7 +2070,7 @@ function LoginModalTemplate({
|
|
|
2050
2070
|
}
|
|
2051
2071
|
)
|
|
2052
2072
|
] }),
|
|
2053
|
-
emailEnabled &&
|
|
2073
|
+
emailEnabled && enabledSocial.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-divider", children: [
|
|
2054
2074
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-divider-line" }),
|
|
2055
2075
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-divider-label", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-divider-text", children: "or continue with" }) })
|
|
2056
2076
|
] }),
|
|
@@ -2058,47 +2078,46 @@ function LoginModalTemplate({
|
|
|
2058
2078
|
enabledSocial.some(([key]) => key === "google") && /* @__PURE__ */ jsxRuntime.jsx(GoogleButton, { disabled: isLoading, onClick: () => onSocialLogin?.("google") }),
|
|
2059
2079
|
enabledSocial.some(([key]) => key === "github") && /* @__PURE__ */ jsxRuntime.jsx(GithubButton, { disabled: isLoading, onClick: () => onSocialLogin?.("github") })
|
|
2060
2080
|
] }),
|
|
2061
|
-
customProviders.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-social-list", children: customProviders.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2062
|
-
"button",
|
|
2063
|
-
{
|
|
2064
|
-
type: "button",
|
|
2065
|
-
disabled: isLoading,
|
|
2066
|
-
className: "pollar-wallet-entry-btn",
|
|
2067
|
-
onClick: () => onCustomLogin?.(p.id),
|
|
2068
|
-
children: [
|
|
2069
|
-
p.iconUrl && /* @__PURE__ */ jsxRuntime.jsx("img", { src: p.iconUrl, alt: "", className: "pollar-wallet-list-icon" }),
|
|
2070
|
-
p.label
|
|
2071
|
-
]
|
|
2072
|
-
},
|
|
2073
|
-
p.id
|
|
2074
|
-
)) }),
|
|
2075
2081
|
(embeddedWallets || smartWallet) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-section", children: [
|
|
2076
|
-
embeddedWallets && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
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
|
+
] }),
|
|
2102
2121
|
smartWallet && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2103
2122
|
"button",
|
|
2104
2123
|
{
|
|
@@ -2139,12 +2158,142 @@ function LoginModalTemplate({
|
|
|
2139
2158
|
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
2140
2159
|
] });
|
|
2141
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
|
+
}
|
|
2142
2289
|
function LoginModal({ onClose }) {
|
|
2143
2290
|
const [email, setEmail] = react.useState("");
|
|
2144
|
-
const { getClient, styles, appConfig: config
|
|
2291
|
+
const { getClient, styles, appConfig: config } = usePollar();
|
|
2145
2292
|
const [authState, setAuthState] = react.useState(() => getClient().getAuthState());
|
|
2293
|
+
const walletAdapters = react.useMemo(() => getClient().listWalletAdapters(), [getClient]);
|
|
2146
2294
|
const [codeInputKey, setCodeInputKey] = react.useState(0);
|
|
2147
2295
|
const pendingEmail = react.useRef(null);
|
|
2296
|
+
const [interactiveAdapter, setInteractiveAdapter] = react.useState(null);
|
|
2148
2297
|
const onCloseRef = react.useRef(onClose);
|
|
2149
2298
|
onCloseRef.current = onClose;
|
|
2150
2299
|
const autoCloseTimer = react.useRef(null);
|
|
@@ -2191,11 +2340,13 @@ function LoginModal({ onClose }) {
|
|
|
2191
2340
|
function handleSocialLogin(provider) {
|
|
2192
2341
|
getClient().login({ provider });
|
|
2193
2342
|
}
|
|
2194
|
-
function handleCustomLogin(id) {
|
|
2195
|
-
getClient().login({ provider: id });
|
|
2196
|
-
}
|
|
2197
2343
|
function handleWalletConnect(type) {
|
|
2198
|
-
getClient().
|
|
2344
|
+
const adapter = getClient().getWalletAdapter(type);
|
|
2345
|
+
if (core.isInteractiveAuthAdapter(adapter)) {
|
|
2346
|
+
setInteractiveAdapter(adapter);
|
|
2347
|
+
return;
|
|
2348
|
+
}
|
|
2349
|
+
getClient().login({ provider: type });
|
|
2199
2350
|
}
|
|
2200
2351
|
function handleLoginSmartWallet() {
|
|
2201
2352
|
getClient().loginSmartWallet();
|
|
@@ -2216,7 +2367,26 @@ function LoginModal({ onClose }) {
|
|
|
2216
2367
|
getClient().beginEmailLogin();
|
|
2217
2368
|
}
|
|
2218
2369
|
}
|
|
2219
|
-
|
|
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(
|
|
2220
2390
|
LoginModalTemplate,
|
|
2221
2391
|
{
|
|
2222
2392
|
theme,
|
|
@@ -2232,17 +2402,15 @@ function LoginModal({ onClose }) {
|
|
|
2232
2402
|
github: !!providers?.github,
|
|
2233
2403
|
apple: !!providers?.apple
|
|
2234
2404
|
},
|
|
2235
|
-
|
|
2405
|
+
walletAdapters,
|
|
2236
2406
|
appName: config.application?.name ?? "Pollar",
|
|
2237
2407
|
email,
|
|
2238
2408
|
onEmailChange: setEmail,
|
|
2239
2409
|
onEmailSubmit: handleEmailSubmit,
|
|
2240
2410
|
onSocialLogin: handleSocialLogin,
|
|
2241
|
-
onCustomLogin: handleCustomLogin,
|
|
2242
2411
|
onWalletConnect: handleWalletConnect,
|
|
2243
2412
|
onLoginSmartWallet: handleLoginSmartWallet,
|
|
2244
2413
|
onCreateSmartWallet: handleCreateSmartWallet,
|
|
2245
|
-
...renderWallets !== void 0 && { renderWallets },
|
|
2246
2414
|
authState,
|
|
2247
2415
|
codeInputKey,
|
|
2248
2416
|
onCodeSubmit: handleVerifyCode,
|
|
@@ -2299,6 +2467,12 @@ var COUNTRY_CURRENCIES = {
|
|
|
2299
2467
|
PE: "PEN",
|
|
2300
2468
|
AR: "ARS"
|
|
2301
2469
|
};
|
|
2470
|
+
var STATUS_LABEL = {
|
|
2471
|
+
pending: "Pending",
|
|
2472
|
+
processing: "Processing",
|
|
2473
|
+
completed: "Completed",
|
|
2474
|
+
failed: "Failed"
|
|
2475
|
+
};
|
|
2302
2476
|
function RampWidgetTemplate({
|
|
2303
2477
|
theme,
|
|
2304
2478
|
accentColor,
|
|
@@ -2308,15 +2482,23 @@ function RampWidgetTemplate({
|
|
|
2308
2482
|
currency,
|
|
2309
2483
|
country,
|
|
2310
2484
|
quotes,
|
|
2311
|
-
paymentInstructions,
|
|
2312
2485
|
isLoading,
|
|
2486
|
+
provider,
|
|
2487
|
+
txStatus,
|
|
2488
|
+
kycUrl,
|
|
2489
|
+
stellarTxHash,
|
|
2490
|
+
canComplete,
|
|
2491
|
+
completing,
|
|
2492
|
+
errorMsg,
|
|
2313
2493
|
onDirectionChange,
|
|
2314
2494
|
onAmountChange,
|
|
2315
2495
|
onCurrencyChange,
|
|
2316
2496
|
onCountryChange,
|
|
2317
2497
|
onFindRoute,
|
|
2318
2498
|
onSelectQuote,
|
|
2319
|
-
|
|
2499
|
+
onOpenKyc,
|
|
2500
|
+
onCompleteWithdraw,
|
|
2501
|
+
onRetry,
|
|
2320
2502
|
onClose
|
|
2321
2503
|
}) {
|
|
2322
2504
|
const isDark = theme === "dark";
|
|
@@ -2344,13 +2526,15 @@ function RampWidgetTemplate({
|
|
|
2344
2526
|
input: direction === "onramp" ? "Buy crypto" : "Sell crypto",
|
|
2345
2527
|
loading_quote: "Finding best route",
|
|
2346
2528
|
select_route: "Select provider",
|
|
2347
|
-
|
|
2529
|
+
status: direction === "onramp" ? "Complete your deposit" : "Complete your withdrawal",
|
|
2530
|
+
error: "Something went wrong"
|
|
2348
2531
|
};
|
|
2349
2532
|
const stepSubtitle = {
|
|
2350
2533
|
input: direction === "onramp" ? "Enter the amount you want to deposit" : "Enter the amount you want to withdraw",
|
|
2351
2534
|
loading_quote: "Comparing providers in real time\u2026",
|
|
2352
2535
|
select_route: "All prices include fees",
|
|
2353
|
-
|
|
2536
|
+
status: `Finish the flow at ${provider || "the provider"} to continue`,
|
|
2537
|
+
error: "Please try again"
|
|
2354
2538
|
};
|
|
2355
2539
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-card pollar-ramp-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
|
|
2356
2540
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-header", children: [
|
|
@@ -2446,183 +2630,183 @@ function RampWidgetTemplate({
|
|
|
2446
2630
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-route-list", children: quotes.map((q, i) => /* @__PURE__ */ jsxRuntime.jsx(RouteDisplay, { quote: q, onSelect: onSelectQuote }, i)) }),
|
|
2447
2631
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Cancel" })
|
|
2448
2632
|
] }),
|
|
2449
|
-
step === "
|
|
2450
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-title", children: paymentInstructions.type }),
|
|
2633
|
+
step === "status" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment", children: [
|
|
2451
2634
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
2452
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children:
|
|
2453
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2454
|
-
/* @__PURE__ */ jsxRuntime.jsx("code", { children: paymentInstructions.value }),
|
|
2455
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-ramp-copy-btn", onClick: () => onCopy(paymentInstructions.value), children: "Copy" })
|
|
2456
|
-
] })
|
|
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 }) })
|
|
2457
2637
|
] }),
|
|
2458
2638
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
2459
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "
|
|
2460
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
" ",
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
"button",
|
|
2468
|
-
{
|
|
2469
|
-
type: "button",
|
|
2470
|
-
className: "pollar-ramp-copy-btn",
|
|
2471
|
-
onClick: () => onCopy(`${paymentInstructions.amount} ${paymentInstructions.currency}`),
|
|
2472
|
-
children: "Copy"
|
|
2473
|
-
}
|
|
2474
|
-
)
|
|
2475
|
-
] })
|
|
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
|
+
) })
|
|
2476
2647
|
] }),
|
|
2477
|
-
|
|
2478
|
-
"
|
|
2479
|
-
|
|
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
|
+
] }) })
|
|
2480
2655
|
] }),
|
|
2481
|
-
/* @__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
|
+
] })
|
|
2482
2670
|
] })
|
|
2483
2671
|
] });
|
|
2484
2672
|
}
|
|
2485
|
-
var
|
|
2486
|
-
{
|
|
2487
|
-
quoteId: "meld-default",
|
|
2488
|
-
provider: "Meld",
|
|
2489
|
-
fee: 1.2,
|
|
2490
|
-
feeCurrency: "USD",
|
|
2491
|
-
rate: 1,
|
|
2492
|
-
rail: "ACH",
|
|
2493
|
-
protocol: "REST",
|
|
2494
|
-
estimatedTime: "~20 min",
|
|
2495
|
-
recommended: true
|
|
2496
|
-
}
|
|
2497
|
-
];
|
|
2498
|
-
var MOCK_QUOTES = {
|
|
2499
|
-
MX: [
|
|
2500
|
-
{
|
|
2501
|
-
quoteId: "etherfuse-mx",
|
|
2502
|
-
provider: "Etherfuse",
|
|
2503
|
-
fee: 0.5,
|
|
2504
|
-
feeCurrency: "MXN",
|
|
2505
|
-
rate: 17.2,
|
|
2506
|
-
rail: "SPEI",
|
|
2507
|
-
protocol: "SEP-24",
|
|
2508
|
-
estimatedTime: "~10 min",
|
|
2509
|
-
recommended: true
|
|
2510
|
-
},
|
|
2511
|
-
{
|
|
2512
|
-
quoteId: "alfredpay-mx",
|
|
2513
|
-
provider: "AlfredPay",
|
|
2514
|
-
fee: 0.8,
|
|
2515
|
-
feeCurrency: "MXN",
|
|
2516
|
-
rate: 17.1,
|
|
2517
|
-
rail: "SPEI",
|
|
2518
|
-
protocol: "REST",
|
|
2519
|
-
estimatedTime: "~15 min",
|
|
2520
|
-
recommended: false
|
|
2521
|
-
}
|
|
2522
|
-
],
|
|
2523
|
-
BR: [
|
|
2524
|
-
{
|
|
2525
|
-
quoteId: "abroad-br",
|
|
2526
|
-
provider: "Abroad",
|
|
2527
|
-
fee: 0.6,
|
|
2528
|
-
feeCurrency: "BRL",
|
|
2529
|
-
rate: 5.1,
|
|
2530
|
-
rail: "PIX",
|
|
2531
|
-
protocol: "REST",
|
|
2532
|
-
estimatedTime: "~5 min",
|
|
2533
|
-
recommended: true
|
|
2534
|
-
}
|
|
2535
|
-
],
|
|
2536
|
-
CO: [
|
|
2537
|
-
{
|
|
2538
|
-
quoteId: "abroad-co",
|
|
2539
|
-
provider: "Abroad",
|
|
2540
|
-
fee: 0.7,
|
|
2541
|
-
feeCurrency: "COP",
|
|
2542
|
-
rate: 4100,
|
|
2543
|
-
rail: "PSE",
|
|
2544
|
-
protocol: "REST",
|
|
2545
|
-
estimatedTime: "~10 min",
|
|
2546
|
-
recommended: true
|
|
2547
|
-
},
|
|
2548
|
-
{
|
|
2549
|
-
quoteId: "koywe-co",
|
|
2550
|
-
provider: "Koywe",
|
|
2551
|
-
fee: 0.9,
|
|
2552
|
-
feeCurrency: "COP",
|
|
2553
|
-
rate: 4095,
|
|
2554
|
-
rail: "PSE",
|
|
2555
|
-
protocol: "REST",
|
|
2556
|
-
estimatedTime: "~15 min",
|
|
2557
|
-
recommended: false
|
|
2558
|
-
}
|
|
2559
|
-
],
|
|
2560
|
-
DEFAULT: MOCK_DEFAULT_QUOTES
|
|
2561
|
-
};
|
|
2562
|
-
var MOCK_PAYMENT = {
|
|
2563
|
-
type: "CLABE",
|
|
2564
|
-
value: "646180157088723456",
|
|
2565
|
-
amount: 1e3,
|
|
2566
|
-
currency: "MXN",
|
|
2567
|
-
expiresAt: new Date(Date.now() + 30 * 60 * 1e3).toISOString()
|
|
2568
|
-
};
|
|
2673
|
+
var TERMINAL = ["completed", "failed"];
|
|
2569
2674
|
function RampWidget({ onClose }) {
|
|
2570
|
-
const { getClient, wallet, styles } = usePollar();
|
|
2675
|
+
const { getClient, signTx, wallet, styles } = usePollar();
|
|
2571
2676
|
const walletAddress = wallet?.address ?? "";
|
|
2677
|
+
const client = getClient();
|
|
2678
|
+
const { theme = "light", accentColor = "#005DB4" } = styles;
|
|
2572
2679
|
const [step, setStep] = react.useState("input");
|
|
2573
2680
|
const [direction, setDirection] = react.useState("onramp");
|
|
2574
2681
|
const [amount, setAmount] = react.useState("");
|
|
2575
|
-
const [currency, setCurrency] = react.useState("
|
|
2576
|
-
const [country, setCountry] = react.useState("
|
|
2682
|
+
const [currency, setCurrency] = react.useState("ARS");
|
|
2683
|
+
const [country, setCountry] = react.useState("AR");
|
|
2577
2684
|
const [quotes, setQuotes] = react.useState([]);
|
|
2578
|
-
const [paymentInstructions, setPaymentInstructions] = react.useState(null);
|
|
2579
2685
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
2580
|
-
const
|
|
2581
|
-
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
|
+
}
|
|
2582
2750
|
async function handleFindRoute() {
|
|
2583
2751
|
setStep("loading_quote");
|
|
2584
2752
|
setIsLoading(true);
|
|
2753
|
+
setErrorMsg(null);
|
|
2585
2754
|
try {
|
|
2586
|
-
const result = await client.getRampsQuote({
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
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");
|
|
2596
2767
|
} finally {
|
|
2597
2768
|
setIsLoading(false);
|
|
2598
|
-
setStep("select_route");
|
|
2599
2769
|
}
|
|
2600
2770
|
}
|
|
2601
2771
|
async function handleSelectQuote(quote) {
|
|
2602
|
-
if (!walletAddress) return;
|
|
2603
2772
|
setIsLoading(true);
|
|
2604
|
-
|
|
2605
|
-
quoteId: `${quote.provider}-${Date.now()}`,
|
|
2606
|
-
amount: Number(amount),
|
|
2607
|
-
currency,
|
|
2608
|
-
country,
|
|
2609
|
-
walletAddress
|
|
2610
|
-
};
|
|
2773
|
+
setErrorMsg(null);
|
|
2611
2774
|
try {
|
|
2612
|
-
const
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
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");
|
|
2617
2781
|
} finally {
|
|
2618
2782
|
setIsLoading(false);
|
|
2619
|
-
setStep("payment_instructions");
|
|
2620
2783
|
}
|
|
2621
2784
|
}
|
|
2622
|
-
function
|
|
2623
|
-
|
|
2624
|
-
|
|
2785
|
+
function handleOpenKyc() {
|
|
2786
|
+
if (kycUrl) window.open(kycUrl, "_blank", "noopener,noreferrer");
|
|
2787
|
+
}
|
|
2788
|
+
async function handleCompleteWithdraw() {
|
|
2789
|
+
if (!txId) return;
|
|
2790
|
+
setCompleting(true);
|
|
2791
|
+
setErrorMsg(null);
|
|
2792
|
+
try {
|
|
2793
|
+
const result = await client.completeWithdraw(txId);
|
|
2794
|
+
if (result.pendingSignature) {
|
|
2795
|
+
await resumeWithSignature(txId, result.pendingSignature);
|
|
2796
|
+
return;
|
|
2797
|
+
}
|
|
2798
|
+
setTxStatus(result.status);
|
|
2799
|
+
setStellarTxHash(result.stellarTxHash ?? null);
|
|
2800
|
+
} catch (e) {
|
|
2801
|
+
const msg = e instanceof Error ? e.message : "";
|
|
2802
|
+
setErrorMsg(
|
|
2803
|
+
msg.includes("KYC") ? "Finish KYC at the provider first, then try again." : msg || "Failed to complete the withdrawal."
|
|
2804
|
+
);
|
|
2805
|
+
} finally {
|
|
2806
|
+
setCompleting(false);
|
|
2807
|
+
}
|
|
2625
2808
|
}
|
|
2809
|
+
const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash;
|
|
2626
2810
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2627
2811
|
RampWidgetTemplate,
|
|
2628
2812
|
{
|
|
@@ -2634,15 +2818,23 @@ function RampWidget({ onClose }) {
|
|
|
2634
2818
|
currency,
|
|
2635
2819
|
country,
|
|
2636
2820
|
quotes,
|
|
2637
|
-
paymentInstructions,
|
|
2638
2821
|
isLoading,
|
|
2822
|
+
provider,
|
|
2823
|
+
txStatus,
|
|
2824
|
+
kycUrl,
|
|
2825
|
+
stellarTxHash,
|
|
2826
|
+
canComplete,
|
|
2827
|
+
completing,
|
|
2828
|
+
errorMsg,
|
|
2639
2829
|
onDirectionChange: setDirection,
|
|
2640
2830
|
onAmountChange: setAmount,
|
|
2641
2831
|
onCurrencyChange: setCurrency,
|
|
2642
2832
|
onCountryChange: setCountry,
|
|
2643
2833
|
onFindRoute: handleFindRoute,
|
|
2644
2834
|
onSelectQuote: handleSelectQuote,
|
|
2645
|
-
|
|
2835
|
+
onOpenKyc: handleOpenKyc,
|
|
2836
|
+
onCompleteWithdraw: handleCompleteWithdraw,
|
|
2837
|
+
onRetry: resetToInput,
|
|
2646
2838
|
onClose
|
|
2647
2839
|
}
|
|
2648
2840
|
) });
|
|
@@ -3306,6 +3498,415 @@ function SendModal({ onClose }) {
|
|
|
3306
3498
|
}
|
|
3307
3499
|
) });
|
|
3308
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
|
+
}
|
|
3309
3910
|
function describeDevice(s) {
|
|
3310
3911
|
if (s.deviceLabel) return s.deviceLabel;
|
|
3311
3912
|
if (!s.userAgent) return "Unknown device";
|
|
@@ -4000,7 +4601,6 @@ var PollarContext = react.createContext(null);
|
|
|
4000
4601
|
function PollarProvider({
|
|
4001
4602
|
client,
|
|
4002
4603
|
appConfig: appConfigProp,
|
|
4003
|
-
ui,
|
|
4004
4604
|
adapters,
|
|
4005
4605
|
onStorageDegrade,
|
|
4006
4606
|
children
|
|
@@ -4052,6 +4652,30 @@ function PollarProvider({
|
|
|
4052
4652
|
}
|
|
4053
4653
|
});
|
|
4054
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]);
|
|
4055
4679
|
react.useEffect(() => {
|
|
4056
4680
|
setModalErrorLogger(pollarClient.getLogger());
|
|
4057
4681
|
}, [pollarClient]);
|
|
@@ -4077,6 +4701,7 @@ function PollarProvider({
|
|
|
4077
4701
|
const [walletBalanceModalOpen, setWalletBalanceModalOpen] = react.useState(false);
|
|
4078
4702
|
const [enabledAssetsModalOpen, setEnabledAssetsModalOpen] = react.useState(false);
|
|
4079
4703
|
const [sendModalOpen, setSendModalOpen] = react.useState(false);
|
|
4704
|
+
const [swapModalOpen, setSwapModalOpen] = react.useState(false);
|
|
4080
4705
|
const [receiveModalOpen, setReceiveModalOpen] = react.useState(false);
|
|
4081
4706
|
const [sessionsModalOpen, setSessionsModalOpen] = react.useState(false);
|
|
4082
4707
|
const [distributionRulesModalOpen, setDistributionRulesModalOpen] = react.useState(false);
|
|
@@ -4084,8 +4709,6 @@ function PollarProvider({
|
|
|
4084
4709
|
const getClient = react.useCallback(() => pollarClient, [pollarClient]);
|
|
4085
4710
|
const refreshWalletBalance = react.useCallback(() => pollarClient.refreshBalance(), [pollarClient, walletAddress]);
|
|
4086
4711
|
const refreshAssets = react.useCallback(() => pollarClient.refreshAssets(), [pollarClient, walletAddress]);
|
|
4087
|
-
const renderWallets = ui?.renderWallets;
|
|
4088
|
-
const customProviders = ui?.customProviders;
|
|
4089
4712
|
const contextValue = react.useMemo(() => {
|
|
4090
4713
|
const styles = resolvedConfig.styles ?? {};
|
|
4091
4714
|
return {
|
|
@@ -4123,6 +4746,10 @@ function PollarProvider({
|
|
|
4123
4746
|
// send / receive
|
|
4124
4747
|
openSendModal: () => setSendModalOpen(true),
|
|
4125
4748
|
openReceiveModal: () => setReceiveModalOpen(true),
|
|
4749
|
+
// swap
|
|
4750
|
+
getSwapQuote: (params) => pollarClient.getSwapQuote(params),
|
|
4751
|
+
swap: (quote, opts) => pollarClient.swap(quote, opts),
|
|
4752
|
+
openSwapModal: () => setSwapModalOpen(true),
|
|
4126
4753
|
// sessions
|
|
4127
4754
|
sessions,
|
|
4128
4755
|
openSessionsModal: () => setSessionsModalOpen(true),
|
|
@@ -4141,8 +4768,6 @@ function PollarProvider({
|
|
|
4141
4768
|
// config
|
|
4142
4769
|
appConfig: resolvedConfig,
|
|
4143
4770
|
styles,
|
|
4144
|
-
renderWallets,
|
|
4145
|
-
customProviders,
|
|
4146
4771
|
adapters
|
|
4147
4772
|
};
|
|
4148
4773
|
}, [
|
|
@@ -4159,9 +4784,7 @@ function PollarProvider({
|
|
|
4159
4784
|
refreshAssets,
|
|
4160
4785
|
networkState,
|
|
4161
4786
|
resolvedConfig,
|
|
4162
|
-
adapters
|
|
4163
|
-
renderWallets,
|
|
4164
|
-
customProviders
|
|
4787
|
+
adapters
|
|
4165
4788
|
]);
|
|
4166
4789
|
return /* @__PURE__ */ jsxRuntime.jsxs(PollarContext.Provider, { value: contextValue, children: [
|
|
4167
4790
|
children,
|
|
@@ -4181,6 +4804,7 @@ function PollarProvider({
|
|
|
4181
4804
|
walletBalanceModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setWalletBalanceModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(WalletBalanceModal, { onClose: () => setWalletBalanceModalOpen(false) }) }),
|
|
4182
4805
|
enabledAssetsModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setEnabledAssetsModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(EnabledAssetsModal, { onClose: () => setEnabledAssetsModalOpen(false) }) }),
|
|
4183
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) }) }),
|
|
4184
4808
|
receiveModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setReceiveModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(ReceiveModal, { onClose: () => setReceiveModalOpen(false) }) }),
|
|
4185
4809
|
sessionsModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSessionsModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SessionsModal, { onClose: () => setSessionsModalOpen(false) }) }),
|
|
4186
4810
|
distributionRulesModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setDistributionRulesModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(DistributionRulesModal, { onClose: () => setDistributionRulesModalOpen(false) }) })
|
|
@@ -4647,6 +5271,8 @@ exports.SendModal = SendModal;
|
|
|
4647
5271
|
exports.SendModalTemplate = SendModalTemplate;
|
|
4648
5272
|
exports.SessionsModal = SessionsModal;
|
|
4649
5273
|
exports.SessionsModalTemplate = SessionsModalTemplate;
|
|
5274
|
+
exports.SwapModal = SwapModal;
|
|
5275
|
+
exports.SwapModalTemplate = SwapModalTemplate;
|
|
4650
5276
|
exports.TransactionModalTemplate = TransactionModalTemplate;
|
|
4651
5277
|
exports.TxHistoryModalTemplate = TxHistoryModalTemplate;
|
|
4652
5278
|
exports.TxStatusView = TxStatusView;
|