@pollar/react 0.11.5 → 0.12.0-rc.5
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 +14 -4
- package/dist/index.css +561 -178
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +344 -150
- package/dist/index.d.ts +344 -150
- package/dist/index.js +2275 -1148
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2271 -1150
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1001,7 +1001,6 @@ var require_QRCode = __commonJS({
|
|
|
1001
1001
|
});
|
|
1002
1002
|
|
|
1003
1003
|
// src/constants.ts
|
|
1004
|
-
var LOGO_POLLAR = "https://pollar.xyz/assets/logo_pollar.png";
|
|
1005
1004
|
var LOGO_POLLAR_WORDMARK_ON_LIGHT = "https://www.pollar.xyz/brandkit/pollar-logo-horizontal-on-light.png";
|
|
1006
1005
|
var LOGO_POLLAR_WORDMARK_ON_DARK = "https://www.pollar.xyz/brandkit/pollar-logo-horizontal-on-dark.png";
|
|
1007
1006
|
var LOGO_POLLAR_MARK_ON_LIGHT = "https://www.pollar.xyz/brandkit/pollar-mark-on-light.png";
|
|
@@ -1031,6 +1030,13 @@ var ModalErrorBoundary = class extends react.Component {
|
|
|
1031
1030
|
return this.props.children;
|
|
1032
1031
|
}
|
|
1033
1032
|
};
|
|
1033
|
+
function ModalLogo({ logoUrl }) {
|
|
1034
|
+
if (logoUrl) return /* @__PURE__ */ jsxRuntime.jsx("img", { src: logoUrl, alt: "Logo", className: "pollar-logo" });
|
|
1035
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1036
|
+
/* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR_MARK_ON_LIGHT, alt: "Pollar", className: "pollar-logo pollar-logo-on-light" }),
|
|
1037
|
+
/* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR_MARK_ON_DARK, alt: "Pollar", className: "pollar-logo pollar-logo-on-dark" })
|
|
1038
|
+
] });
|
|
1039
|
+
}
|
|
1034
1040
|
var PollarModalFooter = () => {
|
|
1035
1041
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-footer", children: [
|
|
1036
1042
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-protected", children: "Protected by" }),
|
|
@@ -1038,7 +1044,7 @@ var PollarModalFooter = () => {
|
|
|
1038
1044
|
/* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR_WORDMARK_ON_DARK, alt: "Pollar", className: "pollar-footer-logo pollar-logo-on-dark" }),
|
|
1039
1045
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-footer-version", children: [
|
|
1040
1046
|
"v",
|
|
1041
|
-
"0.
|
|
1047
|
+
"0.12.0-rc.5"
|
|
1042
1048
|
] })
|
|
1043
1049
|
] });
|
|
1044
1050
|
};
|
|
@@ -1220,42 +1226,75 @@ function readableTextOn(background) {
|
|
|
1220
1226
|
const [r, g, b] = rgb;
|
|
1221
1227
|
return (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255 > 0.6 ? "#111827" : "#ffffff";
|
|
1222
1228
|
}
|
|
1229
|
+
var PALETTES = {
|
|
1230
|
+
light: {
|
|
1231
|
+
bg: "#ffffff",
|
|
1232
|
+
border: "#e5e7eb",
|
|
1233
|
+
text: "#111827",
|
|
1234
|
+
muted: "#6b7280",
|
|
1235
|
+
"input-bg": "#f9fafb",
|
|
1236
|
+
"error-bg": "#fef2f2",
|
|
1237
|
+
"error-border": "#fecaca",
|
|
1238
|
+
"error-text": "#dc2626",
|
|
1239
|
+
"success-text": "#16a34a"
|
|
1240
|
+
},
|
|
1241
|
+
dark: {
|
|
1242
|
+
bg: "#1a1a1a",
|
|
1243
|
+
border: "#374151",
|
|
1244
|
+
text: "#ffffff",
|
|
1245
|
+
muted: "#9ca3af",
|
|
1246
|
+
"input-bg": "#374151",
|
|
1247
|
+
"error-bg": "#2a1515",
|
|
1248
|
+
"error-border": "#7f1d1d",
|
|
1249
|
+
"error-text": "#f87171",
|
|
1250
|
+
"success-text": "#4ade80"
|
|
1251
|
+
}
|
|
1252
|
+
};
|
|
1253
|
+
function mix(fg, percent, bg) {
|
|
1254
|
+
return `color-mix(in srgb, ${fg} ${percent}%, ${bg})`;
|
|
1255
|
+
}
|
|
1223
1256
|
function buildModalCssVars(theme, accentColor, overrides = {}, variant = "compact") {
|
|
1224
1257
|
const isDark = theme === "dark";
|
|
1225
|
-
const
|
|
1258
|
+
const palette = isDark ? PALETTES.dark : PALETTES.light;
|
|
1259
|
+
const bg = color(overrides.backgroundColor, "");
|
|
1260
|
+
const text = color(overrides.textColor, "");
|
|
1261
|
+
const pinned = isDark || bg !== "" || text !== "";
|
|
1226
1262
|
const secondaryBg = color(overrides.buttonColor, "");
|
|
1227
|
-
|
|
1228
|
-
"--pollar-accent": accentColor,
|
|
1229
|
-
"--pollar-bg": color(overrides.backgroundColor, isDark ? "#1a1a1a" : "#ffffff"),
|
|
1230
|
-
"--pollar-border": isDark ? "#374151" : "#e5e7eb",
|
|
1231
|
-
"--pollar-text": textColor,
|
|
1232
|
-
"--pollar-muted": isDark ? "#9ca3af" : "#6b7280",
|
|
1263
|
+
const vars = {
|
|
1264
|
+
"--pollar-brand-accent": accentColor,
|
|
1233
1265
|
// The primary button is the accent's, straight up; its label follows the
|
|
1234
1266
|
// accent's luminance so a pale accent doesn't render white-on-white.
|
|
1235
|
-
"--pollar-btn-primary-fg": readableTextOn(accentColor),
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
"--pollar-btn-secondary-fg": readableTextOn(secondaryBg)
|
|
1239
|
-
} : {},
|
|
1240
|
-
"--pollar-input-bg": isDark ? "#374151" : "#f9fafb",
|
|
1241
|
-
"--pollar-error-bg": isDark ? "#2a1515" : "#fef2f2",
|
|
1242
|
-
"--pollar-error-border": isDark ? "#7f1d1d" : "#fecaca",
|
|
1243
|
-
"--pollar-error-text": isDark ? "#f87171" : "#dc2626",
|
|
1244
|
-
"--pollar-success-text": isDark ? "#4ade80" : "#16a34a",
|
|
1245
|
-
"--pollar-logo-on-light-display": isDark ? "none" : "block",
|
|
1246
|
-
"--pollar-logo-on-dark-display": isDark ? "block" : "none",
|
|
1247
|
-
"--pollar-modal-border-radius": px(overrides.modalBorderRadius, DEFAULT_MODAL_BORDER_RADIUS),
|
|
1248
|
-
"--pollar-buttons-border-radius": px(overrides.buttonBorderRadius, DEFAULT_BUTTON_BORDER_RADIUS),
|
|
1249
|
-
"--pollar-buttons-height": "44px",
|
|
1250
|
-
"--pollar-input-height": "44px",
|
|
1251
|
-
"--pollar-input-border-radius": "0.5rem",
|
|
1252
|
-
"--pollar-card-border-radius": "10px",
|
|
1253
|
-
...variant === "hero" ? {
|
|
1254
|
-
"--pollar-modal-padding": "2rem",
|
|
1255
|
-
"--pollar-modal-heading-size": "1.375rem",
|
|
1256
|
-
"--pollar-modal-subtitle-size": "0.9rem"
|
|
1257
|
-
} : {}
|
|
1267
|
+
"--pollar-brand-btn-primary-fg": readableTextOn(accentColor),
|
|
1268
|
+
"--pollar-brand-modal-border-radius": px(overrides.modalBorderRadius, DEFAULT_MODAL_BORDER_RADIUS),
|
|
1269
|
+
"--pollar-brand-buttons-border-radius": px(overrides.buttonBorderRadius, DEFAULT_BUTTON_BORDER_RADIUS)
|
|
1258
1270
|
};
|
|
1271
|
+
if (secondaryBg) {
|
|
1272
|
+
vars["--pollar-brand-btn-secondary-bg"] = secondaryBg;
|
|
1273
|
+
vars["--pollar-brand-btn-secondary-fg"] = readableTextOn(secondaryBg);
|
|
1274
|
+
}
|
|
1275
|
+
if (pinned) {
|
|
1276
|
+
for (const [name, value] of Object.entries(palette)) vars[`--pollar-brand-${name}`] = value;
|
|
1277
|
+
vars["--pollar-brand-logo-on-light-display"] = isDark ? "none" : "block";
|
|
1278
|
+
vars["--pollar-brand-logo-on-dark-display"] = isDark ? "block" : "none";
|
|
1279
|
+
}
|
|
1280
|
+
if (bg || text) {
|
|
1281
|
+
const surface = bg || palette.bg;
|
|
1282
|
+
const ink = text || palette.text;
|
|
1283
|
+
vars["--pollar-brand-bg"] = surface;
|
|
1284
|
+
vars["--pollar-brand-text"] = ink;
|
|
1285
|
+
vars["--pollar-brand-border"] = mix(ink, 14, surface);
|
|
1286
|
+
vars["--pollar-brand-muted"] = mix(ink, 62, surface);
|
|
1287
|
+
vars["--pollar-brand-input-bg"] = mix(ink, 4, surface);
|
|
1288
|
+
const darkSurface = readableTextOn(surface) === "#ffffff";
|
|
1289
|
+
vars["--pollar-brand-logo-on-light-display"] = darkSurface ? "none" : "block";
|
|
1290
|
+
vars["--pollar-brand-logo-on-dark-display"] = darkSurface ? "block" : "none";
|
|
1291
|
+
}
|
|
1292
|
+
if (variant === "hero") {
|
|
1293
|
+
vars["--pollar-brand-modal-padding"] = "2rem";
|
|
1294
|
+
vars["--pollar-brand-modal-heading-size"] = "1.375rem";
|
|
1295
|
+
vars["--pollar-brand-modal-subtitle-size"] = "0.9rem";
|
|
1296
|
+
}
|
|
1297
|
+
return vars;
|
|
1259
1298
|
}
|
|
1260
1299
|
function modalChrome(styles) {
|
|
1261
1300
|
const zIndex = styles.modalZIndex;
|
|
@@ -1270,7 +1309,7 @@ function modalChrome(styles) {
|
|
|
1270
1309
|
buttonBorderRadius: styles.buttonBorderRadius
|
|
1271
1310
|
},
|
|
1272
1311
|
overlayStyle: {
|
|
1273
|
-
"--pollar-overlay-z-index": typeof zIndex === "number" && Number.isFinite(zIndex) ? zIndex : DEFAULT_OVERLAY_Z_INDEX
|
|
1312
|
+
"--pollar-brand-overlay-z-index": typeof zIndex === "number" && Number.isFinite(zIndex) ? zIndex : DEFAULT_OVERLAY_Z_INDEX
|
|
1274
1313
|
}
|
|
1275
1314
|
};
|
|
1276
1315
|
}
|
|
@@ -1915,7 +1954,7 @@ function KycStatus({ status, label, className }) {
|
|
|
1915
1954
|
|
|
1916
1955
|
// src/components/kyc-modal/kyc-messages.ts
|
|
1917
1956
|
function kycErrorMessage(error, phase) {
|
|
1918
|
-
const code = error
|
|
1957
|
+
const code = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
1919
1958
|
switch (code) {
|
|
1920
1959
|
case "SDK_KYC_NOT_CONFIGURED":
|
|
1921
1960
|
return "Identity verification is not available for this app yet.";
|
|
@@ -1955,6 +1994,8 @@ function KycModalTemplate({
|
|
|
1955
1994
|
reviewReason,
|
|
1956
1995
|
processing = false,
|
|
1957
1996
|
isLoading,
|
|
1997
|
+
startingProviderId = null,
|
|
1998
|
+
directOpen = false,
|
|
1958
1999
|
error,
|
|
1959
2000
|
onSelectProvider,
|
|
1960
2001
|
onDoneVerifying,
|
|
@@ -1963,6 +2004,7 @@ function KycModalTemplate({
|
|
|
1963
2004
|
onClose
|
|
1964
2005
|
}) {
|
|
1965
2006
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides, "hero");
|
|
2007
|
+
const busy = isLoading || startingProviderId !== null;
|
|
1966
2008
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1967
2009
|
"div",
|
|
1968
2010
|
{
|
|
@@ -1990,7 +2032,7 @@ function KycModalTemplate({
|
|
|
1990
2032
|
type: "button",
|
|
1991
2033
|
className: "pollar-modal-close",
|
|
1992
2034
|
onClick: onRefresh,
|
|
1993
|
-
disabled:
|
|
2035
|
+
disabled: busy,
|
|
1994
2036
|
"aria-label": "Refresh",
|
|
1995
2037
|
title: "Refresh providers",
|
|
1996
2038
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2020,7 +2062,14 @@ function KycModalTemplate({
|
|
|
2020
2062
|
] })
|
|
2021
2063
|
] }),
|
|
2022
2064
|
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-kyc-error", role: "alert", children: error }),
|
|
2023
|
-
step === "select_provider" && (
|
|
2065
|
+
step === "select_provider" && (startingProviderId !== null && directOpen ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-loading-block", "aria-live": "polite", children: [
|
|
2066
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner" }),
|
|
2067
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2068
|
+
"Opening ",
|
|
2069
|
+
selectedProvider?.name ?? "verification",
|
|
2070
|
+
"\u2026"
|
|
2071
|
+
] })
|
|
2072
|
+
] }) : isLoading && providers.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-loading-block", children: [
|
|
2024
2073
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner" }),
|
|
2025
2074
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading providers\u2026" })
|
|
2026
2075
|
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-kyc-providers", children: [
|
|
@@ -2030,11 +2079,15 @@ function KycModalTemplate({
|
|
|
2030
2079
|
{
|
|
2031
2080
|
type: "button",
|
|
2032
2081
|
className: "pollar-kyc-provider-btn",
|
|
2033
|
-
disabled:
|
|
2082
|
+
disabled: busy,
|
|
2083
|
+
"aria-busy": startingProviderId === p.id,
|
|
2034
2084
|
onClick: () => onSelectProvider(p),
|
|
2035
2085
|
children: [
|
|
2036
2086
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-kyc-provider-name", children: p.name }),
|
|
2037
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-kyc-provider-flow", children:
|
|
2087
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-kyc-provider-flow", children: startingProviderId === p.id ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2088
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
2089
|
+
"Opening\u2026"
|
|
2090
|
+
] }) : p.flow === "redirect" ? "Continue in a new tab" : "Continue here" })
|
|
2038
2091
|
]
|
|
2039
2092
|
},
|
|
2040
2093
|
p.id
|
|
@@ -2085,7 +2138,7 @@ function KycModalTemplate({
|
|
|
2085
2138
|
/* @__PURE__ */ jsxRuntime.jsx(KycStatus, { status: kycStatus, ...processing ? { label: "Approved" } : {} }),
|
|
2086
2139
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-kyc-result-text", children: kycStatus === "approved" ? "Your identity has been verified successfully." : kycStatus === "rejected" ? "Your verification was not approved. Contact support for the next steps." : kycStatus === "expired" ? "Your verification expired. Start again to verify your identity." : processing ? kycProcessingMessage() : kycReviewMessage(reviewReason) }),
|
|
2087
2140
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-actions", children: [
|
|
2088
|
-
kycStatus === "expired" && onStartAgain && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onStartAgain, disabled:
|
|
2141
|
+
kycStatus === "expired" && onStartAgain && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onStartAgain, disabled: busy, children: "Start again" }),
|
|
2089
2142
|
kycStatus !== "approved" && kycStatus !== "rejected" && kycStatus !== "expired" && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onDoneVerifying, children: "Check again" }),
|
|
2090
2143
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onClose, children: "Close" })
|
|
2091
2144
|
] })
|
|
@@ -2118,6 +2171,8 @@ function KycModal({
|
|
|
2118
2171
|
const [reviewReason, setReviewReason] = react.useState(null);
|
|
2119
2172
|
const [processing, setProcessing] = react.useState(false);
|
|
2120
2173
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
2174
|
+
const [startingProviderId, setStartingProviderId] = react.useState(null);
|
|
2175
|
+
const [directOpen, setDirectOpen] = react.useState(false);
|
|
2121
2176
|
const [error, setError] = react.useState(null);
|
|
2122
2177
|
const idempotencyKeys = react.useRef({});
|
|
2123
2178
|
const autoOpened = react.useRef(false);
|
|
@@ -2145,7 +2200,7 @@ function KycModal({
|
|
|
2145
2200
|
starting.current = true;
|
|
2146
2201
|
setSelectedProvider(provider);
|
|
2147
2202
|
setError(null);
|
|
2148
|
-
|
|
2203
|
+
setStartingProviderId(provider.id);
|
|
2149
2204
|
const key = (_a = idempotencyKeys.current)[_b = provider.id] ?? (_a[_b] = newIdempotencyKey());
|
|
2150
2205
|
try {
|
|
2151
2206
|
const result = await client.resolveKyc(
|
|
@@ -2160,7 +2215,13 @@ function KycModal({
|
|
|
2160
2215
|
finish("approved");
|
|
2161
2216
|
return;
|
|
2162
2217
|
}
|
|
2163
|
-
|
|
2218
|
+
const { sessionId } = result;
|
|
2219
|
+
if (sessionId === void 0) throw new Error("The KYC provider answered without a session.");
|
|
2220
|
+
setSession({
|
|
2221
|
+
sessionId,
|
|
2222
|
+
...result.kycUrl !== void 0 ? { kycUrl: result.kycUrl } : {},
|
|
2223
|
+
...result.fields !== void 0 ? { fields: result.fields } : {}
|
|
2224
|
+
});
|
|
2164
2225
|
setStep("verifying");
|
|
2165
2226
|
} catch (e) {
|
|
2166
2227
|
const code = core.isPollarApiError(e) ? e.code : void 0;
|
|
@@ -2177,7 +2238,7 @@ function KycModal({
|
|
|
2177
2238
|
setStep("select_provider");
|
|
2178
2239
|
} finally {
|
|
2179
2240
|
starting.current = false;
|
|
2180
|
-
|
|
2241
|
+
setStartingProviderId(null);
|
|
2181
2242
|
}
|
|
2182
2243
|
}
|
|
2183
2244
|
const loadProviders = react.useCallback(() => {
|
|
@@ -2196,6 +2257,7 @@ function KycModal({
|
|
|
2196
2257
|
void loadProviders().then((list) => {
|
|
2197
2258
|
if (!providerId || autoOpened.current) return;
|
|
2198
2259
|
autoOpened.current = true;
|
|
2260
|
+
setDirectOpen(true);
|
|
2199
2261
|
const target = list.find((p) => p.id === providerId);
|
|
2200
2262
|
if (target) void handleSelectProvider(target);
|
|
2201
2263
|
else
|
|
@@ -2245,6 +2307,8 @@ function KycModal({
|
|
|
2245
2307
|
reviewReason,
|
|
2246
2308
|
processing,
|
|
2247
2309
|
isLoading,
|
|
2310
|
+
startingProviderId,
|
|
2311
|
+
directOpen,
|
|
2248
2312
|
error,
|
|
2249
2313
|
onSelectProvider: handleSelectProvider,
|
|
2250
2314
|
onDoneVerifying: handleDoneVerifying,
|
|
@@ -2347,10 +2411,14 @@ function fieldErrorMessage(code, language) {
|
|
|
2347
2411
|
}
|
|
2348
2412
|
function fieldErrorsOf(error) {
|
|
2349
2413
|
if (!error || typeof error !== "object") return null;
|
|
2350
|
-
|
|
2351
|
-
|
|
2414
|
+
if (!("code" in error) || error.code !== "KYC_FORM_INVALID_ANSWERS") return null;
|
|
2415
|
+
const body = "body" in error ? error.body : void 0;
|
|
2416
|
+
const list = typeof body === "object" && body !== null && "errors" in body ? body.errors : void 0;
|
|
2417
|
+
if (!Array.isArray(list)) return null;
|
|
2418
|
+
const items = list;
|
|
2352
2419
|
const errors = {};
|
|
2353
|
-
for (const item of
|
|
2420
|
+
for (const item of items) {
|
|
2421
|
+
if (typeof item !== "object" || item === null || !("key" in item) || !("code" in item)) continue;
|
|
2354
2422
|
if (typeof item.key === "string" && typeof item.code === "string") errors[item.key] = item.code;
|
|
2355
2423
|
}
|
|
2356
2424
|
return Object.keys(errors).length ? errors : null;
|
|
@@ -2930,7 +2998,7 @@ function LoginModalTemplate({
|
|
|
2930
2998
|
}
|
|
2931
2999
|
) }),
|
|
2932
3000
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-header", children: [
|
|
2933
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-logo-wrap", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3001
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-logo-wrap", children: /* @__PURE__ */ jsxRuntime.jsx(ModalLogo, { logoUrl }) }),
|
|
2934
3002
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-title", children: appName }),
|
|
2935
3003
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-subtitle", children: "Log in or sign up" })
|
|
2936
3004
|
] }),
|
|
@@ -3096,7 +3164,7 @@ function LoginModalStatus({
|
|
|
3096
3164
|
}
|
|
3097
3165
|
) }),
|
|
3098
3166
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-header", children: [
|
|
3099
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-logo-wrap", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3167
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-logo-wrap", children: /* @__PURE__ */ jsxRuntime.jsx(ModalLogo, { logoUrl }) }),
|
|
3100
3168
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-title", children: appName }),
|
|
3101
3169
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-subtitle", children: "Log in or sign up" })
|
|
3102
3170
|
] }),
|
|
@@ -3198,7 +3266,7 @@ function PrivyLoginSubmodal({
|
|
|
3198
3266
|
}
|
|
3199
3267
|
) }),
|
|
3200
3268
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-header", children: [
|
|
3201
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-logo-wrap", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3269
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-logo-wrap", children: /* @__PURE__ */ jsxRuntime.jsx(ModalLogo, { logoUrl }) }),
|
|
3202
3270
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-title", children: appName }),
|
|
3203
3271
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-subtitle", children: adapter.meta.label })
|
|
3204
3272
|
] }),
|
|
@@ -3399,69 +3467,45 @@ function LoginModal({ onClose }) {
|
|
|
3399
3467
|
}
|
|
3400
3468
|
) });
|
|
3401
3469
|
}
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
if (!nonEmpty(rampProviderId) || !nonEmpty(corridorId)) return null;
|
|
3411
|
-
if ((requirementType === "FORM" || requirementType === "REGISTRY_CHECK" || requirementType === "PROVIDER_REGISTRATION") && nonEmpty(optionId)) {
|
|
3412
|
-
return { rampProviderId, corridorId, type: requirementType, optionId };
|
|
3413
|
-
}
|
|
3414
|
-
const kyc = nonEmpty(optionId) && requirementType === "KYC" ? optionId : kycProviderId;
|
|
3415
|
-
return nonEmpty(kyc) ? { rampProviderId, corridorId, type: "KYC", optionId: kyc } : null;
|
|
3416
|
-
}
|
|
3417
|
-
function pendingFromQuote(requirement) {
|
|
3418
|
-
return {
|
|
3419
|
-
rampProviderId: requirement.rampProviderId,
|
|
3420
|
-
corridorId: requirement.corridorId,
|
|
3421
|
-
type: requirement.type,
|
|
3422
|
-
optionId: requirement.optionId,
|
|
3423
|
-
progress: { position: requirement.completed + 1, total: requirement.total }
|
|
3424
|
-
};
|
|
3425
|
-
}
|
|
3426
|
-
function lockedRouteCopy(requirement) {
|
|
3427
|
-
if (requirement.type === "FORM") return { message: "Answer a few questions to see this route", action: "Continue" };
|
|
3428
|
-
if (requirement.type === "PROVIDER_REGISTRATION") {
|
|
3429
|
-
return { message: "Register with the provider to see this route", action: "Continue" };
|
|
3430
|
-
}
|
|
3431
|
-
if (requirement.type === "REGISTRY_CHECK") {
|
|
3432
|
-
return requirement.status === "pending" ? { message: "Your details are under review", action: null } : { message: "Confirm your details to see this route", action: "Confirm" };
|
|
3433
|
-
}
|
|
3434
|
-
switch (requirement.status) {
|
|
3435
|
-
case "expired":
|
|
3436
|
-
return { message: "Your verification expired", action: "Verify again" };
|
|
3437
|
-
case "pending":
|
|
3438
|
-
if (!requirement.reviewReason) return { message: "Verification in progress", action: "Continue" };
|
|
3439
|
-
return {
|
|
3440
|
-
message: requirement.reviewReason === "DUPLICATE_DOCUMENT" ? kycReviewMessage(requirement.reviewReason) : "Your verification is under review",
|
|
3441
|
-
action: null
|
|
3442
|
-
};
|
|
3443
|
-
case "rejected":
|
|
3444
|
-
return { message: "Verification was not approved", action: null };
|
|
3445
|
-
default:
|
|
3446
|
-
return { message: "Verify your identity to see this route", action: "Verify" };
|
|
3447
|
-
}
|
|
3470
|
+
function findWalletBalance(balances, asset) {
|
|
3471
|
+
const { issuer } = asset;
|
|
3472
|
+
return balances.find((b) => {
|
|
3473
|
+
if (resolveChain(b.chain) !== asset.chain) return false;
|
|
3474
|
+
if (issuer === null) return b.type === "native" || !b.issuer && b.code === asset.code;
|
|
3475
|
+
if (b.code !== asset.code) return false;
|
|
3476
|
+
return issuer === void 0 || !b.issuer || b.issuer.toLowerCase() === issuer.toLowerCase();
|
|
3477
|
+
});
|
|
3448
3478
|
}
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
};
|
|
3455
|
-
|
|
3479
|
+
function useWalletAvailable(asset) {
|
|
3480
|
+
const { walletBalance, refreshWalletBalance } = usePollar();
|
|
3481
|
+
const wanted = !!asset;
|
|
3482
|
+
react.useEffect(() => {
|
|
3483
|
+
if (wanted && walletBalance.step === "idle") void refreshWalletBalance();
|
|
3484
|
+
}, [wanted, walletBalance.step, refreshWalletBalance]);
|
|
3485
|
+
if (!asset || walletBalance.step !== "loaded") return void 0;
|
|
3486
|
+
const record = findWalletBalance(walletBalance.data.balances, asset);
|
|
3487
|
+
return record ? record.available : "0";
|
|
3488
|
+
}
|
|
3489
|
+
var CUSTODY_LABEL = { COSIGNED: "co-signed", SELF_CUSTODY: "self-custody" };
|
|
3490
|
+
var assetOf = (node) => node.kind === "fiat" ? node.currency : node.code;
|
|
3491
|
+
function etaText(seconds) {
|
|
3492
|
+
if (seconds === null) return null;
|
|
3493
|
+
if (seconds < 90) return `~${Math.max(1, Math.round(seconds))} s`;
|
|
3494
|
+
if (seconds < 5400) return `~${Math.round(seconds / 60)} min`;
|
|
3495
|
+
return `~${Math.round(seconds / 3600)} h`;
|
|
3496
|
+
}
|
|
3497
|
+
function RouteDisplay({ quote, best = false, busy = false, disabled = false, onSelect }) {
|
|
3456
3498
|
const inert = busy || disabled;
|
|
3457
3499
|
const select = () => {
|
|
3458
3500
|
if (!inert) onSelect(quote);
|
|
3459
3501
|
};
|
|
3502
|
+
const first = quote.legs[0];
|
|
3503
|
+
const last = quote.legs[quote.legs.length - 1];
|
|
3460
3504
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3461
3505
|
"div",
|
|
3462
3506
|
{
|
|
3463
3507
|
className: "pollar-ramp-route-card",
|
|
3464
|
-
"data-recommended":
|
|
3508
|
+
"data-recommended": best,
|
|
3465
3509
|
"data-busy": busy || void 0,
|
|
3466
3510
|
"data-disabled": disabled || void 0,
|
|
3467
3511
|
role: "button",
|
|
@@ -3472,54 +3516,152 @@ function RouteDisplay({ quote, busy = false, disabled = false, onSelect }) {
|
|
|
3472
3516
|
onKeyDown: (e) => e.key === "Enter" && select(),
|
|
3473
3517
|
children: [
|
|
3474
3518
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-route-left", children: [
|
|
3475
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-provider", children: quote.
|
|
3476
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-meta", children: busy ? "Starting\u2026" :
|
|
3519
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-provider", children: first && last ? `${quote.amountIn} ${assetOf(first.from)} \u2192 ~${quote.amountOut} ${assetOf(last.to)}` : `~${quote.amountOut}` }),
|
|
3520
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-meta", children: busy ? "Starting\u2026" : [quote.legs.map((leg) => core.rampLegTitle(leg)).join(" \xB7 "), etaText(quote.etaSeconds)].filter(Boolean).join(" \xB7 ") })
|
|
3477
3521
|
] }),
|
|
3478
3522
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-route-right", children: busy ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3479
3523
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-ramp-route-fee", children: [
|
|
3480
|
-
quote.
|
|
3481
|
-
"
|
|
3524
|
+
quote.legs.length === 1 ? "1 step" : `${quote.legs.length} steps`,
|
|
3525
|
+
" \xB7 fees included"
|
|
3482
3526
|
] }),
|
|
3483
|
-
|
|
3527
|
+
best && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-badge", children: "Best rate" })
|
|
3484
3528
|
] }) })
|
|
3485
3529
|
]
|
|
3486
3530
|
}
|
|
3487
3531
|
);
|
|
3488
3532
|
}
|
|
3489
|
-
function
|
|
3490
|
-
|
|
3533
|
+
function RejectedRouteDisplay({
|
|
3534
|
+
rejection,
|
|
3535
|
+
disabled = false,
|
|
3536
|
+
trusting = false,
|
|
3537
|
+
walletBusy = false,
|
|
3538
|
+
custodyChoice = false,
|
|
3539
|
+
onVerify,
|
|
3540
|
+
onTrust,
|
|
3541
|
+
onWalletStep
|
|
3542
|
+
}) {
|
|
3543
|
+
const requirement = rejection.requirement;
|
|
3544
|
+
const copy = requirement ? core.rampRequirementCopy(requirement) : null;
|
|
3545
|
+
const trustAsset = !requirement && onTrust ? core.rampTrustlineAsset(rejection) : null;
|
|
3546
|
+
const step = !requirement ? core.rampWalletStep(rejection) : null;
|
|
3547
|
+
const fromMenu = step?.action === "create_wallet" && custodyChoice;
|
|
3548
|
+
const walletStep = onWalletStep && !fromMenu ? step : null;
|
|
3549
|
+
const picks = custodyChoice && step?.action !== "set_up_recovery" ? ["COSIGNED", "SELF_CUSTODY"] : [void 0];
|
|
3550
|
+
const meta = copy ? copy.message : fromMenu ? "You need a wallet to receive this. Create it from the wallet menu, then find the route again." : core.rampResolutionText(rejection.failure);
|
|
3551
|
+
const busy = trusting || !!walletStep && walletBusy;
|
|
3491
3552
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3492
3553
|
"div",
|
|
3493
3554
|
{
|
|
3494
3555
|
className: "pollar-ramp-route-card",
|
|
3495
3556
|
"data-locked": true,
|
|
3496
|
-
"data-kyc-status": requirement
|
|
3497
|
-
"data-disabled": disabled || void 0,
|
|
3557
|
+
"data-kyc-status": requirement?.status,
|
|
3558
|
+
"data-disabled": !(copy?.action && onVerify) && !trustAsset && !walletStep || disabled && !busy || void 0,
|
|
3498
3559
|
children: [
|
|
3499
3560
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-route-left", children: [
|
|
3500
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-provider", children:
|
|
3501
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-meta", children:
|
|
3561
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-provider", children: rejection.legs.map((leg) => core.rampLegTitle(leg)).join(" \xB7 ") }),
|
|
3562
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-meta", children: meta })
|
|
3502
3563
|
] }),
|
|
3503
|
-
|
|
3564
|
+
trustAsset && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-route-right", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3565
|
+
"button",
|
|
3566
|
+
{
|
|
3567
|
+
type: "button",
|
|
3568
|
+
className: "pollar-btn-secondary pollar-ramp-route-verify",
|
|
3569
|
+
disabled,
|
|
3570
|
+
"aria-busy": trusting,
|
|
3571
|
+
onClick: () => onTrust(trustAsset),
|
|
3572
|
+
children: trusting ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3573
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
3574
|
+
" Adding\u2026"
|
|
3575
|
+
] }) : `Add ${trustAsset.code} trustline`
|
|
3576
|
+
}
|
|
3577
|
+
) }),
|
|
3578
|
+
walletStep && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-route-right", children: walletBusy ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "pollar-btn-secondary pollar-ramp-route-verify", disabled: true, "aria-busy": true, children: [
|
|
3579
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
3580
|
+
" ",
|
|
3581
|
+
walletStep.busyLabel
|
|
3582
|
+
] }) : picks.map((custody) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3583
|
+
"button",
|
|
3584
|
+
{
|
|
3585
|
+
type: "button",
|
|
3586
|
+
className: "pollar-btn-secondary pollar-ramp-route-verify",
|
|
3587
|
+
disabled,
|
|
3588
|
+
onClick: () => onWalletStep(walletStep, custody),
|
|
3589
|
+
children: custody ? `${walletStep.label} (${CUSTODY_LABEL[custody]})` : walletStep.label
|
|
3590
|
+
},
|
|
3591
|
+
custody ?? "app"
|
|
3592
|
+
)) }),
|
|
3593
|
+
requirement && copy?.action && onVerify && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-route-right", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3504
3594
|
"button",
|
|
3505
3595
|
{
|
|
3506
3596
|
type: "button",
|
|
3507
3597
|
className: "pollar-btn-secondary pollar-ramp-route-verify",
|
|
3508
3598
|
disabled,
|
|
3509
3599
|
onClick: () => onVerify(requirement),
|
|
3510
|
-
children: action
|
|
3600
|
+
children: copy.action
|
|
3511
3601
|
}
|
|
3512
3602
|
) })
|
|
3513
3603
|
]
|
|
3514
3604
|
}
|
|
3515
3605
|
);
|
|
3516
3606
|
}
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
const
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3607
|
+
function formatAvailable(available) {
|
|
3608
|
+
if (available === null) return "\u2014";
|
|
3609
|
+
const n = parseFloat(available);
|
|
3610
|
+
return isNaN(n) ? available : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
|
|
3611
|
+
}
|
|
3612
|
+
function AmountField({
|
|
3613
|
+
id,
|
|
3614
|
+
label,
|
|
3615
|
+
value,
|
|
3616
|
+
onChange,
|
|
3617
|
+
unit,
|
|
3618
|
+
available,
|
|
3619
|
+
onMax,
|
|
3620
|
+
placeholder = "0.00",
|
|
3621
|
+
disabled = false
|
|
3622
|
+
}) {
|
|
3623
|
+
const showBalance = available !== void 0;
|
|
3624
|
+
const canMax = showBalance && available !== null && parseFloat(available) > 0 && !disabled;
|
|
3625
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
3626
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-label-row", children: [
|
|
3627
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", htmlFor: id, children: label }),
|
|
3628
|
+
showBalance && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-send-hint", children: [
|
|
3629
|
+
"Available: ",
|
|
3630
|
+
formatAvailable(available),
|
|
3631
|
+
" ",
|
|
3632
|
+
unit ?? ""
|
|
3633
|
+
] })
|
|
3634
|
+
] }),
|
|
3635
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-input-shell", children: [
|
|
3636
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3637
|
+
"input",
|
|
3638
|
+
{
|
|
3639
|
+
id,
|
|
3640
|
+
className: "pollar-input pollar-send-amount-input",
|
|
3641
|
+
type: "text",
|
|
3642
|
+
inputMode: "decimal",
|
|
3643
|
+
placeholder,
|
|
3644
|
+
value,
|
|
3645
|
+
disabled,
|
|
3646
|
+
onChange: (e) => onChange(e.target.value),
|
|
3647
|
+
"aria-label": id ? void 0 : label
|
|
3648
|
+
}
|
|
3649
|
+
),
|
|
3650
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-input-suffix", children: [
|
|
3651
|
+
showBalance && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3652
|
+
"button",
|
|
3653
|
+
{
|
|
3654
|
+
type: "button",
|
|
3655
|
+
className: "pollar-send-inline-action",
|
|
3656
|
+
disabled: !canMax,
|
|
3657
|
+
onClick: () => onMax ? onMax() : available && onChange(available),
|
|
3658
|
+
children: "Max"
|
|
3659
|
+
}
|
|
3660
|
+
),
|
|
3661
|
+
unit && /* @__PURE__ */ jsxRuntime.jsx("span", { children: unit })
|
|
3662
|
+
] })
|
|
3663
|
+
] })
|
|
3664
|
+
] });
|
|
3523
3665
|
}
|
|
3524
3666
|
function scannableImageSrc(image) {
|
|
3525
3667
|
return image.encoding === "base64" ? `data:${image.mediaType};base64,${image.data}` : `data:${image.mediaType};charset=utf-8,${encodeURIComponent(image.data)}`;
|
|
@@ -3538,102 +3680,143 @@ function placeholderFor(field, fields, values) {
|
|
|
3538
3680
|
}
|
|
3539
3681
|
return field.placeholder;
|
|
3540
3682
|
}
|
|
3541
|
-
var CHAIN_NAME = { STELLAR: "Stellar", POLYGON: "Polygon", SOLANA: "Solana" };
|
|
3542
|
-
var EXPLORER_NAME = { STELLAR: "Stellar Expert", POLYGON: "Polygonscan", SOLANA: "Solana Explorer" };
|
|
3543
|
-
var LOADING_STEPS = ["Detecting your country\u2026", "Consulting providers\u2026", "Route found!"];
|
|
3544
3683
|
function flagEmoji(code) {
|
|
3545
3684
|
const cc = code.trim().toUpperCase();
|
|
3546
3685
|
if (!/^[A-Z]{2}$/.test(cc)) return "";
|
|
3547
3686
|
const base = 127462;
|
|
3548
3687
|
return String.fromCodePoint(base + (cc.charCodeAt(0) - 65), base + (cc.charCodeAt(1) - 65));
|
|
3549
3688
|
}
|
|
3550
|
-
var
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
}
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
return
|
|
3689
|
+
var CHAIN_NAME = { STELLAR: "Stellar", POLYGON: "Polygon", SOLANA: "Solana" };
|
|
3690
|
+
function explorerTxUrl2(chain, hash, network) {
|
|
3691
|
+
const testnet = network === "testnet";
|
|
3692
|
+
if (chain === "SOLANA") return `https://explorer.solana.com/tx/${hash}${testnet ? "?cluster=devnet" : ""}`;
|
|
3693
|
+
if (chain === "POLYGON") return `https://${testnet ? "amoy." : ""}polygonscan.com/tx/${hash}`;
|
|
3694
|
+
return `https://stellar.expert/explorer/${testnet ? "testnet" : "public"}/tx/${hash}`;
|
|
3695
|
+
}
|
|
3696
|
+
function legChain(leg) {
|
|
3697
|
+
if (leg.from.kind === "asset") return leg.from.chain;
|
|
3698
|
+
return leg.to.kind === "asset" ? leg.to.chain : "STELLAR";
|
|
3699
|
+
}
|
|
3700
|
+
function stepChain(kind, leg) {
|
|
3701
|
+
if (kind === "mint" && leg.to.kind === "asset") return leg.to.chain;
|
|
3702
|
+
return legChain(leg);
|
|
3703
|
+
}
|
|
3704
|
+
var timeLeftText = (seconds) => seconds <= 0 ? "Taking a little longer than usual" : seconds < 60 ? `About ${seconds}s left` : `About ${Math.ceil(seconds / 60)} min left`;
|
|
3705
|
+
function useNowEverySecond(running) {
|
|
3706
|
+
const [now, setNow] = react.useState(() => Date.now());
|
|
3707
|
+
react.useEffect(() => {
|
|
3708
|
+
if (!running) return;
|
|
3709
|
+
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
3710
|
+
return () => clearInterval(timer);
|
|
3711
|
+
}, [running]);
|
|
3712
|
+
return now;
|
|
3713
|
+
}
|
|
3714
|
+
var fiatKey = (fiat) => `${fiat.currency}:${fiat.rail}`;
|
|
3715
|
+
var assetKey3 = (asset) => `${asset.code}:${asset.chain}:${asset.identifier ?? ""}`;
|
|
3716
|
+
function trustKey(rejection) {
|
|
3717
|
+
const asset = core.rampTrustlineAsset(rejection);
|
|
3718
|
+
return asset ? `${asset.code}:${asset.issuer}` : null;
|
|
3719
|
+
}
|
|
3720
|
+
var LOADING_STEPS = ["Checking routes\u2026", "Quoting each step\u2026", "Route found!"];
|
|
3721
|
+
function useRenderAt(at) {
|
|
3722
|
+
const [, setTick] = react.useState(0);
|
|
3723
|
+
react.useEffect(() => {
|
|
3724
|
+
if (at === null) return;
|
|
3725
|
+
const timer = setTimeout(() => setTick((n) => n + 1), Math.max(0, at - Date.now()) + 50);
|
|
3726
|
+
return () => clearTimeout(timer);
|
|
3727
|
+
}, [at]);
|
|
3560
3728
|
}
|
|
3561
3729
|
function RampWidgetTemplate({
|
|
3562
3730
|
theme,
|
|
3563
3731
|
accentColor,
|
|
3564
3732
|
styleOverrides,
|
|
3733
|
+
network,
|
|
3565
3734
|
step,
|
|
3566
3735
|
flowSteps,
|
|
3567
3736
|
flowStepIndex,
|
|
3568
|
-
startingQuoteId,
|
|
3569
3737
|
direction,
|
|
3570
|
-
|
|
3571
|
-
currency,
|
|
3572
|
-
country,
|
|
3573
|
-
requiredFields,
|
|
3574
|
-
fieldValues,
|
|
3738
|
+
routesLoading,
|
|
3575
3739
|
countries,
|
|
3576
|
-
|
|
3577
|
-
|
|
3740
|
+
country,
|
|
3741
|
+
fiats,
|
|
3742
|
+
fiat,
|
|
3743
|
+
assets,
|
|
3744
|
+
asset,
|
|
3745
|
+
amount,
|
|
3746
|
+
sellAvailable,
|
|
3578
3747
|
quotes,
|
|
3579
|
-
|
|
3748
|
+
rejected,
|
|
3749
|
+
startingQuoteId,
|
|
3750
|
+
fields,
|
|
3751
|
+
fieldValues,
|
|
3752
|
+
order,
|
|
3753
|
+
pendingOrders,
|
|
3580
3754
|
isLoading,
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
kycUrl,
|
|
3584
|
-
tosUrl,
|
|
3585
|
-
kycBlocking,
|
|
3586
|
-
onboardingStatus,
|
|
3587
|
-
kycJustApproved,
|
|
3588
|
-
stellarTxHash,
|
|
3589
|
-
txHash,
|
|
3590
|
-
txChain,
|
|
3591
|
-
explorerUrl,
|
|
3592
|
-
fundsInTransit = false,
|
|
3593
|
-
retrying = false,
|
|
3594
|
-
onRetryTransit,
|
|
3595
|
-
depositInstructions,
|
|
3596
|
-
canComplete,
|
|
3597
|
-
completing,
|
|
3755
|
+
refreshing,
|
|
3756
|
+
signing,
|
|
3598
3757
|
errorMsg,
|
|
3599
|
-
|
|
3758
|
+
notice = null,
|
|
3600
3759
|
onDirectionChange,
|
|
3601
|
-
onAmountChange,
|
|
3602
|
-
onFieldChange,
|
|
3603
3760
|
onCountryChange,
|
|
3761
|
+
onFiatChange,
|
|
3762
|
+
onAssetChange,
|
|
3763
|
+
onAmountChange,
|
|
3604
3764
|
onFindRoute,
|
|
3605
3765
|
onSelectQuote,
|
|
3606
3766
|
onVerifyRoute,
|
|
3767
|
+
trustingAsset = null,
|
|
3768
|
+
onTrustAsset,
|
|
3769
|
+
walletBusy = null,
|
|
3770
|
+
custodyChoice = false,
|
|
3771
|
+
onWalletStep,
|
|
3772
|
+
noChains = false,
|
|
3773
|
+
retrying = false,
|
|
3774
|
+
onRetryOrder,
|
|
3775
|
+
onSetUpRecovery,
|
|
3776
|
+
recoveryMissing = null,
|
|
3777
|
+
checkingPayment = false,
|
|
3778
|
+
onCheckPayment,
|
|
3779
|
+
pollTrouble = false,
|
|
3780
|
+
onFieldChange,
|
|
3607
3781
|
onContactContinue,
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3782
|
+
onSign,
|
|
3783
|
+
onApprove,
|
|
3784
|
+
onResumeOrder,
|
|
3785
|
+
onNewOrder,
|
|
3611
3786
|
onBack,
|
|
3787
|
+
onStepSelect,
|
|
3612
3788
|
onRetry,
|
|
3613
3789
|
onRefresh,
|
|
3614
3790
|
onClose
|
|
3615
3791
|
}) {
|
|
3616
|
-
const settledHash = txHash ?? stellarTxHash;
|
|
3617
|
-
const chainName = CHAIN_NAME[txChain ?? "STELLAR"];
|
|
3618
3792
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides, "hero");
|
|
3793
|
+
const onramp = direction === "ONRAMP";
|
|
3794
|
+
const sendUnit = onramp ? fiat?.currency : asset?.code;
|
|
3795
|
+
const view = order ? core.describeRampAction(order) : null;
|
|
3796
|
+
const settled = order ? ["completed", "failed", "refunded"].includes(order.state) : false;
|
|
3797
|
+
const running = order?.legs.find((leg) => core.rampLegStatus(leg) === "active" && order.pendingAction?.legIndex !== leg.index);
|
|
3798
|
+
const now = useNowEverySecond(step === "status" && !settled && !!running && running.etaSeconds !== null);
|
|
3799
|
+
const nextApproval = order && !settled ? core.rampNextApproval(order) : null;
|
|
3800
|
+
const stopped = order ? core.rampOrderStopped(order) : false;
|
|
3801
|
+
const receive = order ? core.rampOrderReceive(order) : null;
|
|
3802
|
+
const waitsOnRecovery = order?.failure?.resolutionAction === "set_up_recovery";
|
|
3803
|
+
const payBy = view?.action?.kind === "FIAT_PAYMENT" && view.expiresAt ? Date.parse(view.expiresAt) : null;
|
|
3804
|
+
useRenderAt(view?.canSign && view.expiresAt ? Date.parse(view.expiresAt) : null);
|
|
3805
|
+
const stepsOpen = !!onStepSelect && step !== "status" && !isLoading && startingQuoteId === null && trustingAsset === null && walletBusy === null;
|
|
3619
3806
|
const stepTitle = {
|
|
3620
|
-
input:
|
|
3621
|
-
loading_quote: "Finding best route",
|
|
3622
|
-
select_route: "
|
|
3807
|
+
input: onramp ? "Buy crypto" : "Sell crypto",
|
|
3808
|
+
loading_quote: "Finding the best route",
|
|
3809
|
+
select_route: "Choose a route",
|
|
3623
3810
|
contact: "Your details",
|
|
3624
|
-
status:
|
|
3811
|
+
status: order?.state === "completed" ? "Transfer completed" : onramp ? "Your purchase" : "Your sale",
|
|
3625
3812
|
error: "Something went wrong"
|
|
3626
3813
|
};
|
|
3627
3814
|
const stepSubtitle = {
|
|
3628
|
-
input:
|
|
3629
|
-
loading_quote: "Comparing
|
|
3630
|
-
select_route: "All
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
// money, not who you are. Say which, rather than asserting the Bridge case
|
|
3634
|
-
// over every provider.
|
|
3635
|
-
contact: `${provider || "This provider"} needs ${listOf(requiredFields.filter((f) => !f.optional).map((f) => f.label.toLowerCase()))} to continue`,
|
|
3636
|
-
status: `Finish the flow at ${provider || "the provider"} to continue`,
|
|
3815
|
+
input: onramp ? "Pick what you receive and how much you pay" : "Pick what you sell and how much",
|
|
3816
|
+
loading_quote: "Comparing routes in real time\u2026",
|
|
3817
|
+
select_route: "All amounts include fees",
|
|
3818
|
+
contact: `This route needs ${listOf(fields.filter((f) => !f.optional).map((f) => f.label.toLowerCase()))} to continue`,
|
|
3819
|
+
status: view?.title ?? "Processing",
|
|
3637
3820
|
error: "Please try again"
|
|
3638
3821
|
};
|
|
3639
3822
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-card pollar-ramp-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
|
|
@@ -3674,85 +3857,124 @@ function RampWidgetTemplate({
|
|
|
3674
3857
|
" of ",
|
|
3675
3858
|
flowSteps.length
|
|
3676
3859
|
] }),
|
|
3677
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3678
|
-
"
|
|
3860
|
+
/* @__PURE__ */ jsxRuntime.jsx("ol", { className: "pollar-ramp-steps-track", children: flowSteps.map((label, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "pollar-ramp-steps-item", "aria-current": i === flowStepIndex ? "step" : void 0, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3861
|
+
"button",
|
|
3679
3862
|
{
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
"
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3863
|
+
type: "button",
|
|
3864
|
+
className: "pollar-ramp-steps-step",
|
|
3865
|
+
"data-done": i <= flowStepIndex || void 0,
|
|
3866
|
+
disabled: !stepsOpen || i >= flowStepIndex,
|
|
3867
|
+
onClick: () => onStepSelect?.(label),
|
|
3868
|
+
children: [
|
|
3869
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-steps-segment" }),
|
|
3870
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-steps-name", children: label })
|
|
3871
|
+
]
|
|
3687
3872
|
}
|
|
3688
|
-
)
|
|
3873
|
+
) }, label)) })
|
|
3874
|
+
] }),
|
|
3875
|
+
step === "input" && pendingOrders.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-ramp-payment pollar-ramp-saved", "aria-label": "Pending operations", children: [
|
|
3876
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: "These operations are waiting for you. Starting another does not cancel them." }),
|
|
3877
|
+
pendingOrders.map((pending) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-saved-row", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3878
|
+
"button",
|
|
3879
|
+
{
|
|
3880
|
+
type: "button",
|
|
3881
|
+
className: "pollar-btn-secondary",
|
|
3882
|
+
disabled: isLoading,
|
|
3883
|
+
onClick: () => onResumeOrder(pending.id),
|
|
3884
|
+
children: [
|
|
3885
|
+
"Resume ",
|
|
3886
|
+
pending.direction === "ONRAMP" ? "purchase" : "sale",
|
|
3887
|
+
" \xB7 ",
|
|
3888
|
+
pending.id.slice(-8)
|
|
3889
|
+
]
|
|
3890
|
+
}
|
|
3891
|
+
) }, pending.id))
|
|
3689
3892
|
] }),
|
|
3690
3893
|
step === "input" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3691
3894
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tabs", children: [
|
|
3692
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3693
|
-
|
|
3694
|
-
{
|
|
3695
|
-
type: "button",
|
|
3696
|
-
className: "pollar-tab",
|
|
3697
|
-
"data-active": direction === "onramp",
|
|
3698
|
-
onClick: () => onDirectionChange("onramp"),
|
|
3699
|
-
children: "Buy"
|
|
3700
|
-
}
|
|
3701
|
-
),
|
|
3702
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3703
|
-
"button",
|
|
3704
|
-
{
|
|
3705
|
-
type: "button",
|
|
3706
|
-
className: "pollar-tab",
|
|
3707
|
-
"data-active": direction === "offramp",
|
|
3708
|
-
onClick: () => onDirectionChange("offramp"),
|
|
3709
|
-
children: "Sell"
|
|
3710
|
-
}
|
|
3711
|
-
)
|
|
3895
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-tab", "data-active": onramp, onClick: () => onDirectionChange("ONRAMP"), children: "Buy" }),
|
|
3896
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-tab", "data-active": !onramp, onClick: () => onDirectionChange("OFFRAMP"), children: "Sell" })
|
|
3712
3897
|
] }),
|
|
3713
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-
|
|
3714
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3898
|
+
routesLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-input pollar-select-loading", children: [
|
|
3899
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
3900
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading routes\u2026" })
|
|
3901
|
+
] }) : countries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: noChains ? "This app has no chains enabled, so there is nothing to buy or sell yet." : "No ramp routes are available for this app yet." }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3902
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-field", children: [
|
|
3903
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-ramp-label", htmlFor: "pollar-ramp-country", children: "Country" }),
|
|
3904
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3905
|
+
"select",
|
|
3906
|
+
{
|
|
3907
|
+
id: "pollar-ramp-country",
|
|
3908
|
+
className: "pollar-ramp-input",
|
|
3909
|
+
value: country,
|
|
3910
|
+
onChange: (e) => onCountryChange(e.target.value),
|
|
3911
|
+
children: countries.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: c.country, children: [
|
|
3912
|
+
flagEmoji(c.country),
|
|
3913
|
+
" ",
|
|
3914
|
+
c.country
|
|
3915
|
+
] }, c.country))
|
|
3916
|
+
}
|
|
3917
|
+
)
|
|
3729
3918
|
] }),
|
|
3730
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3731
|
-
"
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3919
|
+
fiats.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-field", children: [
|
|
3920
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-ramp-label", htmlFor: "pollar-ramp-fiat", children: onramp ? "Pay with" : "Receive in" }),
|
|
3921
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3922
|
+
"select",
|
|
3923
|
+
{
|
|
3924
|
+
id: "pollar-ramp-fiat",
|
|
3925
|
+
className: "pollar-ramp-input",
|
|
3926
|
+
value: fiat ? fiatKey(fiat) : "",
|
|
3927
|
+
onChange: (e) => onFiatChange(e.target.value),
|
|
3928
|
+
children: fiats.map((f) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: fiatKey(f), children: [
|
|
3929
|
+
f.currency,
|
|
3930
|
+
" \xB7 ",
|
|
3931
|
+
core.rampRailLabel(f.rail, { language: formLanguage() })
|
|
3932
|
+
] }, fiatKey(f)))
|
|
3933
|
+
}
|
|
3934
|
+
)
|
|
3935
|
+
] }),
|
|
3936
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-field", children: [
|
|
3937
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-ramp-label", htmlFor: "pollar-ramp-asset", children: onramp ? "Receive" : "Sell" }),
|
|
3938
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3939
|
+
"select",
|
|
3940
|
+
{
|
|
3941
|
+
id: "pollar-ramp-asset",
|
|
3942
|
+
className: "pollar-ramp-input",
|
|
3943
|
+
value: asset ? assetKey3(asset) : "",
|
|
3944
|
+
onChange: (e) => onAssetChange(e.target.value),
|
|
3945
|
+
children: assets.map((a) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: assetKey3(a), children: [
|
|
3946
|
+
a.code,
|
|
3947
|
+
" on ",
|
|
3948
|
+
CHAIN_NAME[a.chain] ?? a.chain
|
|
3949
|
+
] }, assetKey3(a)))
|
|
3950
|
+
}
|
|
3951
|
+
)
|
|
3952
|
+
] }),
|
|
3953
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-field", children: [
|
|
3954
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3955
|
+
AmountField,
|
|
3956
|
+
{
|
|
3957
|
+
id: "pollar-ramp-amount",
|
|
3958
|
+
label: onramp ? "You pay" : "You sell",
|
|
3959
|
+
value: amount,
|
|
3960
|
+
onChange: onAmountChange,
|
|
3961
|
+
unit: sendUnit,
|
|
3962
|
+
available: onramp ? void 0 : sellAvailable
|
|
3963
|
+
}
|
|
3964
|
+
),
|
|
3965
|
+
errorMsg && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-field-error", children: errorMsg })
|
|
3966
|
+
] })
|
|
3742
3967
|
] }),
|
|
3743
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
"button",
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
}
|
|
3754
|
-
)
|
|
3755
|
-
] })
|
|
3968
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3969
|
+
"button",
|
|
3970
|
+
{
|
|
3971
|
+
type: "button",
|
|
3972
|
+
className: "pollar-btn-primary",
|
|
3973
|
+
disabled: !amount || !fiat || !asset || isLoading || routesLoading,
|
|
3974
|
+
onClick: onFindRoute,
|
|
3975
|
+
children: "Find best route"
|
|
3976
|
+
}
|
|
3977
|
+
) })
|
|
3756
3978
|
] }),
|
|
3757
3979
|
step === "loading_quote" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-loading", children: [
|
|
3758
3980
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-spinner pollar-ramp-loading-spinner" }),
|
|
@@ -3762,33 +3984,44 @@ function RampWidgetTemplate({
|
|
|
3762
3984
|
] }, i))
|
|
3763
3985
|
] }),
|
|
3764
3986
|
step === "select_route" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3765
|
-
noticeMsg && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: noticeMsg }),
|
|
3766
3987
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-route-list", children: [
|
|
3767
3988
|
quotes.map((q, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
3768
3989
|
RouteDisplay,
|
|
3769
3990
|
{
|
|
3770
3991
|
quote: q,
|
|
3771
|
-
|
|
3992
|
+
best: i === 0,
|
|
3993
|
+
busy: startingQuoteId === q.quoteId,
|
|
3772
3994
|
disabled: startingQuoteId != null && q.quoteId !== startingQuoteId,
|
|
3773
3995
|
onSelect: onSelectQuote
|
|
3774
3996
|
},
|
|
3775
|
-
|
|
3997
|
+
q.quoteId
|
|
3776
3998
|
)),
|
|
3777
|
-
|
|
3778
|
-
|
|
3999
|
+
rejected.map((r, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4000
|
+
RejectedRouteDisplay,
|
|
3779
4001
|
{
|
|
3780
|
-
|
|
3781
|
-
disabled: startingQuoteId != null,
|
|
3782
|
-
|
|
4002
|
+
rejection: r,
|
|
4003
|
+
disabled: startingQuoteId != null || trustingAsset !== null || walletBusy !== null,
|
|
4004
|
+
trusting: trustKey(r) === trustingAsset,
|
|
4005
|
+
walletBusy: walletBusy === i,
|
|
4006
|
+
custodyChoice,
|
|
4007
|
+
onVerify: onVerifyRoute,
|
|
4008
|
+
onTrust: onTrustAsset,
|
|
4009
|
+
onWalletStep: onWalletStep && ((step2, custody) => onWalletStep(step2, i, custody))
|
|
3783
4010
|
},
|
|
3784
|
-
|
|
4011
|
+
i
|
|
3785
4012
|
))
|
|
3786
4013
|
] }),
|
|
4014
|
+
quotes.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: core.rampNoRouteText(rejected) }),
|
|
4015
|
+
notice && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-ramp-payment-note", children: [
|
|
4016
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm", "aria-hidden": true }),
|
|
4017
|
+
" ",
|
|
4018
|
+
notice
|
|
4019
|
+
] }),
|
|
3787
4020
|
errorMsg && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", style: { color: "var(--pollar-error-text)" }, children: errorMsg }),
|
|
3788
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className:
|
|
4021
|
+
(errorMsg || !quotes.length) && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onBack, children: "Back" })
|
|
3789
4022
|
] }),
|
|
3790
4023
|
step === "contact" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3791
|
-
|
|
4024
|
+
fields.map((f) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-field", children: [
|
|
3792
4025
|
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-ramp-label", children: [
|
|
3793
4026
|
f.label,
|
|
3794
4027
|
f.optional && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-field-optional", children: " (optional)" })
|
|
@@ -3810,175 +4043,178 @@ function RampWidgetTemplate({
|
|
|
3810
4043
|
type: f.type,
|
|
3811
4044
|
className: "pollar-ramp-input",
|
|
3812
4045
|
value: fieldValues[f.key] ?? "",
|
|
3813
|
-
placeholder: placeholderFor(f,
|
|
4046
|
+
placeholder: placeholderFor(f, fields, fieldValues),
|
|
3814
4047
|
autoComplete: f.type === "email" ? "email" : "off",
|
|
3815
4048
|
onChange: (e) => onFieldChange(f.key, e.target.value)
|
|
3816
4049
|
}
|
|
3817
4050
|
),
|
|
3818
4051
|
f.hint && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-field-hint", children: f.hint }),
|
|
3819
|
-
|
|
4052
|
+
core.rampFieldError(f, fieldValues[f.key]) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-field-error", children: core.rampFieldError(f, fieldValues[f.key]) })
|
|
3820
4053
|
] }, f.key)),
|
|
3821
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3822
|
-
|
|
3823
|
-
|
|
4054
|
+
errorMsg && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-field-error", children: errorMsg }),
|
|
4055
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4056
|
+
"button",
|
|
4057
|
+
{
|
|
4058
|
+
type: "button",
|
|
4059
|
+
className: "pollar-btn-primary",
|
|
4060
|
+
disabled: fields.some((f) => !core.rampFieldValid(f, fieldValues[f.key])) || isLoading,
|
|
4061
|
+
onClick: onContactContinue,
|
|
4062
|
+
children: isLoading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4063
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
4064
|
+
"Starting\u2026"
|
|
4065
|
+
] }) : "Continue"
|
|
4066
|
+
}
|
|
4067
|
+
) })
|
|
4068
|
+
] }),
|
|
4069
|
+
step === "status" && order && view && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment", children: [
|
|
4070
|
+
/* @__PURE__ */ jsxRuntime.jsx("ol", { className: "pollar-ramp-legs", "aria-label": "Progress", children: order.legs.map((leg) => {
|
|
4071
|
+
const status = core.rampLegStatus(leg);
|
|
4072
|
+
const hash = leg.onchainTxHash;
|
|
4073
|
+
const note = core.rampLegNote(leg);
|
|
4074
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "pollar-ramp-leg", "data-status": status, children: [
|
|
4075
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-leg-dot", "aria-hidden": true }),
|
|
4076
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-leg-title", children: core.rampLegTitle(leg) }),
|
|
4077
|
+
status === "active" && !settled && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm", "aria-label": "In progress" }),
|
|
4078
|
+
hash && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4079
|
+
"a",
|
|
4080
|
+
{
|
|
4081
|
+
className: "pollar-ramp-leg-link",
|
|
4082
|
+
href: explorerTxUrl2(legChain(leg), hash, network),
|
|
4083
|
+
target: "_blank",
|
|
4084
|
+
rel: "noopener noreferrer",
|
|
4085
|
+
children: [
|
|
4086
|
+
hash.slice(0, 6),
|
|
4087
|
+
"\u2026",
|
|
4088
|
+
hash.slice(-4)
|
|
4089
|
+
]
|
|
4090
|
+
}
|
|
4091
|
+
),
|
|
4092
|
+
note && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-leg-note", children: note }),
|
|
4093
|
+
status === "active" && !settled && !!leg.steps?.length && /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "pollar-ramp-steps", children: leg.steps.map((s) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "pollar-ramp-step", "data-status": s.status, children: [
|
|
4094
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-step-title", children: core.rampStepTitle(s, leg) }),
|
|
4095
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-ramp-step-state", children: [
|
|
4096
|
+
s.status === "confirming" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm", "aria-hidden": true }),
|
|
4097
|
+
s.hash ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4098
|
+
"a",
|
|
4099
|
+
{
|
|
4100
|
+
className: "pollar-ramp-leg-link",
|
|
4101
|
+
href: explorerTxUrl2(stepChain(s.kind, leg), s.hash, network),
|
|
4102
|
+
target: "_blank",
|
|
4103
|
+
rel: "noopener noreferrer",
|
|
4104
|
+
children: core.rampStepStatusText(s)
|
|
4105
|
+
}
|
|
4106
|
+
) : core.rampStepStatusText(s)
|
|
4107
|
+
] })
|
|
4108
|
+
] }, s.kind)) }),
|
|
4109
|
+
running === leg && !settled && core.rampLegTimeLeft(leg, now) !== null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-leg-eta", children: timeLeftText(core.rampLegTimeLeft(leg, now)) })
|
|
4110
|
+
] }, leg.index);
|
|
4111
|
+
}) }),
|
|
4112
|
+
nextApproval && !order.pendingAction && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-ramp-next", children: [
|
|
4113
|
+
"Next: ",
|
|
4114
|
+
nextApproval,
|
|
4115
|
+
". You approve it on this device when it comes up."
|
|
4116
|
+
] }),
|
|
4117
|
+
receive && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
4118
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: order.state === "completed" ? "You received" : "You receive" }),
|
|
4119
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-value", children: [
|
|
4120
|
+
receive.estimated && "~",
|
|
4121
|
+
receive.amount,
|
|
4122
|
+
" ",
|
|
4123
|
+
receive.unit
|
|
4124
|
+
] })
|
|
4125
|
+
] }),
|
|
4126
|
+
order.failure && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
4127
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "What to do" }),
|
|
4128
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: core.rampOrderResolutionText(order) }),
|
|
4129
|
+
stopped && !settled && waitsOnRecovery && recoveryMissing !== false && onSetUpRecovery && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onSetUpRecovery, children: "Set up recovery" }),
|
|
4130
|
+
stopped && !settled && waitsOnRecovery && recoveryMissing === true && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: "Once it is set up, the order goes on by itself." }),
|
|
4131
|
+
stopped && !settled && order.failure.resolutionOwner === "END_USER" && onRetryOrder && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3824
4132
|
"button",
|
|
3825
4133
|
{
|
|
3826
4134
|
type: "button",
|
|
3827
4135
|
className: "pollar-btn-primary",
|
|
3828
|
-
disabled:
|
|
3829
|
-
onClick:
|
|
3830
|
-
children:
|
|
4136
|
+
disabled: retrying || waitsOnRecovery && recoveryMissing === true,
|
|
4137
|
+
onClick: onRetryOrder,
|
|
4138
|
+
children: retrying ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3831
4139
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
3832
|
-
"
|
|
3833
|
-
] }) : "
|
|
4140
|
+
" Trying again\u2026"
|
|
4141
|
+
] }) : "Try again"
|
|
3834
4142
|
}
|
|
3835
|
-
)
|
|
3836
|
-
] })
|
|
3837
|
-
] }),
|
|
3838
|
-
step === "status" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment", children: [
|
|
3839
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
3840
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "Provider" }),
|
|
3841
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-payment-value", children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: provider }) })
|
|
3842
|
-
] }),
|
|
3843
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
3844
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "Status" }),
|
|
3845
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-value", children: [
|
|
3846
|
-
/* @__PURE__ */ jsxRuntime.jsx("code", { style: { color: txStatus === "completed" ? "var(--pollar-success-text)" : void 0 }, children: txStatus ? STATUS_LABEL[txStatus] : "Processing" }),
|
|
3847
|
-
txStatus !== "completed" && txStatus !== "failed" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm", "aria-label": "Checking status" })
|
|
3848
|
-
] })
|
|
3849
|
-
] }),
|
|
3850
|
-
fundsInTransit && txStatus !== "completed" && txStatus !== "failed" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
3851
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "Funds in transit" }),
|
|
3852
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: "Your money is safe in your own wallet, waiting for the next step of the transfer." }),
|
|
3853
|
-
onRetryTransit && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onRetryTransit, disabled: retrying, children: retrying ? "Retrying..." : "Retry now" })
|
|
3854
|
-
] }),
|
|
3855
|
-
settledHash && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
3856
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-ramp-payment-label", children: [
|
|
3857
|
-
chainName,
|
|
3858
|
-
" tx"
|
|
3859
|
-
] }),
|
|
4143
|
+
),
|
|
3860
4144
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-value", style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
3861
4145
|
/* @__PURE__ */ jsxRuntime.jsxs("code", { style: { flex: 1, wordBreak: "break-all" }, children: [
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
settledHash.slice(-8)
|
|
4146
|
+
"Order ",
|
|
4147
|
+
order.id
|
|
3865
4148
|
] }),
|
|
3866
|
-
/* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value:
|
|
3867
|
-
explorerUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3868
|
-
"a",
|
|
3869
|
-
{
|
|
3870
|
-
href: explorerUrl,
|
|
3871
|
-
target: "_blank",
|
|
3872
|
-
rel: "noopener noreferrer",
|
|
3873
|
-
className: "pollar-copy-btn",
|
|
3874
|
-
"aria-label": `View on ${EXPLORER_NAME[txChain ?? "STELLAR"]}`,
|
|
3875
|
-
title: `View on ${EXPLORER_NAME[txChain ?? "STELLAR"]}`,
|
|
3876
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
|
|
3877
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3878
|
-
"path",
|
|
3879
|
-
{
|
|
3880
|
-
d: "M6 3H3v8h8V8",
|
|
3881
|
-
stroke: "currentColor",
|
|
3882
|
-
strokeWidth: "1.5",
|
|
3883
|
-
strokeLinecap: "round",
|
|
3884
|
-
strokeLinejoin: "round"
|
|
3885
|
-
}
|
|
3886
|
-
),
|
|
3887
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3888
|
-
"path",
|
|
3889
|
-
{
|
|
3890
|
-
d: "M8.5 2.5h3v3M11 3L6.5 7.5",
|
|
3891
|
-
stroke: "currentColor",
|
|
3892
|
-
strokeWidth: "1.5",
|
|
3893
|
-
strokeLinecap: "round",
|
|
3894
|
-
strokeLinejoin: "round"
|
|
3895
|
-
}
|
|
3896
|
-
)
|
|
3897
|
-
] })
|
|
3898
|
-
}
|
|
3899
|
-
)
|
|
4149
|
+
/* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: order.id, label: "Copy order id" })
|
|
3900
4150
|
] })
|
|
3901
4151
|
] }),
|
|
3902
|
-
|
|
4152
|
+
!settled && payBy !== null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: payBy > Date.now() ? `Pay before ${new Date(payBy).toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" })}.` : "This payment window has closed. If you have not paid, start a new operation." }),
|
|
4153
|
+
!settled && view.scannable && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
3903
4154
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "Payment QR" }),
|
|
3904
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-payment-value", children:
|
|
4155
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-payment-value", children: view.scannable.image.inlineSafe ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3905
4156
|
"div",
|
|
3906
4157
|
{
|
|
3907
4158
|
className: "pollar-ramp-qr",
|
|
3908
4159
|
"aria-label": "Payment QR",
|
|
3909
|
-
dangerouslySetInnerHTML: { __html:
|
|
4160
|
+
dangerouslySetInnerHTML: { __html: view.scannable.image.data }
|
|
3910
4161
|
}
|
|
3911
4162
|
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3912
4163
|
"img",
|
|
3913
4164
|
{
|
|
3914
|
-
src: scannableImageSrc(
|
|
4165
|
+
src: scannableImageSrc(view.scannable.image),
|
|
3915
4166
|
alt: "Payment QR",
|
|
3916
4167
|
style: { width: "100%", maxWidth: 220, height: "auto", display: "block", margin: "0 auto" }
|
|
3917
4168
|
}
|
|
3918
4169
|
) })
|
|
3919
4170
|
] }),
|
|
3920
|
-
|
|
3921
|
-
|
|
4171
|
+
!settled && view.codeMissing && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", style: { color: "var(--pollar-error-text)" }, children: "The payment code could not be shown. Refresh; if it still does not appear, contact this app's support." }),
|
|
4172
|
+
!settled && view.scannable?.payload && view.scannable.payloadLabel && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
4173
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: view.scannable.payloadLabel }),
|
|
3922
4174
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-payment-value", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
3923
|
-
/* @__PURE__ */ jsxRuntime.jsx("code", { style: { flex: 1, wordBreak: "break-all" }, children:
|
|
3924
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3925
|
-
CopyButton,
|
|
3926
|
-
{
|
|
3927
|
-
value: depositInstructions.scannable.payload,
|
|
3928
|
-
label: `Copy ${depositInstructions.scannable.payloadLabel}`
|
|
3929
|
-
}
|
|
3930
|
-
)
|
|
4175
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { style: { flex: 1, wordBreak: "break-all" }, children: view.scannable.payload }),
|
|
4176
|
+
/* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: view.scannable.payload, label: `Copy ${view.scannable.payloadLabel}` })
|
|
3931
4177
|
] }) })
|
|
3932
4178
|
] }),
|
|
3933
|
-
|
|
3934
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children:
|
|
3935
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-payment-value", children:
|
|
3936
|
-
/* @__PURE__ */ jsxRuntime.jsx("code", { style: { flex: 1, wordBreak: "break-all" }, children:
|
|
3937
|
-
/* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value:
|
|
3938
|
-
] })
|
|
3939
|
-
] },
|
|
3940
|
-
|
|
3941
|
-
"Accept terms at ",
|
|
3942
|
-
provider
|
|
3943
|
-
] }),
|
|
3944
|
-
kycUrl && !depositInstructions && txStatus !== "completed" && /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "pollar-btn-primary", onClick: onOpenKyc, children: [
|
|
3945
|
-
"Continue at ",
|
|
3946
|
-
provider
|
|
3947
|
-
] }),
|
|
3948
|
-
kycBlocking && onboardingStatus === "awaiting_provider" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-ramp-payment-note", children: [
|
|
3949
|
-
provider,
|
|
3950
|
-
" is still setting up your account for this payment method. Your verification is complete and there is nothing left for you to do \u2014 nothing has been sent, and this will update on its own once ",
|
|
3951
|
-
provider,
|
|
3952
|
-
" is ready."
|
|
3953
|
-
] }),
|
|
3954
|
-
kycBlocking && onboardingStatus !== "awaiting_provider" && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-ramp-payment-note", children: [
|
|
3955
|
-
provider,
|
|
3956
|
-
" needs to verify your identity before this payout. Nothing has been sent yet \u2014 complete verification with ",
|
|
3957
|
-
provider,
|
|
3958
|
-
", and this will update on its own."
|
|
3959
|
-
] }),
|
|
3960
|
-
kycJustApproved && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3961
|
-
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-ramp-payment-note", children: [
|
|
3962
|
-
provider,
|
|
3963
|
-
" approved your verification. Request a new quote to continue \u2014 the previous one was consumed."
|
|
3964
|
-
] }),
|
|
3965
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onRetry, children: "Request a new quote" })
|
|
3966
|
-
] }),
|
|
3967
|
-
canComplete && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", disabled: completing, onClick: onCompleteWithdraw, children: completing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4179
|
+
!settled && view.details.map((d) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
4180
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: d.label }),
|
|
4181
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-payment-value", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
4182
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { style: { flex: 1, wordBreak: "break-all" }, children: d.value }),
|
|
4183
|
+
/* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: d.value, label: `Copy ${d.label}` })
|
|
4184
|
+
] }) })
|
|
4185
|
+
] }, d.label)),
|
|
4186
|
+
!settled && view.action?.kind === "FIAT_PAYMENT" && onCheckPayment && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", disabled: checkingPayment, onClick: onCheckPayment, children: checkingPayment ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3968
4187
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
3969
|
-
"
|
|
3970
|
-
] }) : "I've
|
|
3971
|
-
|
|
3972
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
4188
|
+
" Checking your payment..."
|
|
4189
|
+
] }) : "I've paid" }),
|
|
4190
|
+
!settled && view.canSign && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", disabled: signing, onClick: onSign, children: signing ? "Waiting for your wallet\u2026" : "Authorize" }),
|
|
4191
|
+
!settled && view.action?.kind === "SIGNATURE" && !view.canSign && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: "Preparing a new signature request\u2026" }),
|
|
4192
|
+
!settled && view.canApprove && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onApprove, children: "Approve on this device" }),
|
|
4193
|
+
!settled && view.link && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4194
|
+
"a",
|
|
4195
|
+
{
|
|
4196
|
+
className: "pollar-btn-primary pollar-ramp-hosted-link",
|
|
4197
|
+
href: view.link,
|
|
4198
|
+
target: "_blank",
|
|
4199
|
+
rel: "noopener noreferrer",
|
|
4200
|
+
children: view.linkLabel
|
|
4201
|
+
}
|
|
4202
|
+
),
|
|
4203
|
+
!settled && order.pendingAction?.kind === "KYC" && !view.link && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: view.note ?? "The provider is reviewing your details. This updates on its own." }),
|
|
4204
|
+
pollTrouble && !settled && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: "Having trouble reaching the server. Retrying\u2026" }),
|
|
4205
|
+
errorMsg && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-field-error", children: errorMsg }),
|
|
4206
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-explore", children: [
|
|
4207
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onNewOrder, children: "Start another operation" }),
|
|
4208
|
+
!stopped && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: "This one keeps going; you can resume it later." })
|
|
4209
|
+
] })
|
|
3973
4210
|
] }),
|
|
3974
|
-
step === "error" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3975
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
4211
|
+
step === "error" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4212
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: errorMsg ?? "Something went wrong." }),
|
|
3976
4213
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-actions", children: [
|
|
3977
4214
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: "Close" }),
|
|
3978
4215
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", onClick: onRetry, children: "Try again" })
|
|
3979
4216
|
] })
|
|
3980
|
-
] })
|
|
3981
|
-
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
4217
|
+
] })
|
|
3982
4218
|
] });
|
|
3983
4219
|
}
|
|
3984
4220
|
|
|
@@ -4133,19 +4369,26 @@ var SHARED_FIELD_LABELS = {
|
|
|
4133
4369
|
country_code: "Pa\xEDs de residencia"
|
|
4134
4370
|
}
|
|
4135
4371
|
};
|
|
4136
|
-
var errorCode = (error) =>
|
|
4372
|
+
var errorCode = (error) => typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : null;
|
|
4373
|
+
var errorBody = (error) => {
|
|
4374
|
+
const body = typeof error === "object" && error !== null && "body" in error ? error.body : void 0;
|
|
4375
|
+
return typeof body === "object" && body !== null ? body : void 0;
|
|
4376
|
+
};
|
|
4137
4377
|
function missingFieldsOf(error) {
|
|
4138
|
-
const body = error
|
|
4139
|
-
|
|
4378
|
+
const body = errorBody(error);
|
|
4379
|
+
const missing = body && "missing" in body ? body.missing : void 0;
|
|
4380
|
+
return Array.isArray(missing) ? missing.filter((item) => typeof item === "string") : [];
|
|
4140
4381
|
}
|
|
4141
4382
|
function registrationFixOf(error) {
|
|
4142
|
-
const body = error
|
|
4383
|
+
const body = errorBody(error);
|
|
4384
|
+
const invalid = body && "invalid" in body ? body.invalid : void 0;
|
|
4385
|
+
const formList = body && "forms" in body ? body.forms : void 0;
|
|
4143
4386
|
const strings = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
4144
|
-
const forms = Array.isArray(
|
|
4145
|
-
|
|
4146
|
-
return
|
|
4387
|
+
const forms = Array.isArray(formList) ? formList.flatMap((item) => {
|
|
4388
|
+
if (typeof item !== "object" || item === null || !("formId" in item) || typeof item.formId !== "string") return [];
|
|
4389
|
+
return [{ formId: item.formId, keys: strings("keys" in item ? item.keys : void 0) }];
|
|
4147
4390
|
}) : [];
|
|
4148
|
-
return { invalid: strings(
|
|
4391
|
+
return { invalid: strings(invalid), forms };
|
|
4149
4392
|
}
|
|
4150
4393
|
function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
4151
4394
|
const { getClient, styles } = usePollar();
|
|
@@ -4465,472 +4708,499 @@ function ProviderRegistrationModal({
|
|
|
4465
4708
|
}
|
|
4466
4709
|
) });
|
|
4467
4710
|
}
|
|
4468
|
-
var
|
|
4469
|
-
|
|
4470
|
-
return quote.requiredFields ?? [];
|
|
4471
|
-
}
|
|
4472
|
-
function flowStepsOf(quotes, selected) {
|
|
4473
|
-
const needsDetails = selected != null ? requiredFieldsOf(selected).length > 0 : quotes.some((q) => requiredFieldsOf(q).length > 0);
|
|
4474
|
-
return needsDetails ? ["Amount", "Provider", "Details", "Complete"] : ["Amount", "Provider", "Complete"];
|
|
4475
|
-
}
|
|
4476
|
-
var STEP_LABEL = {
|
|
4477
|
-
input: "Amount",
|
|
4478
|
-
loading_quote: "Amount",
|
|
4479
|
-
select_route: "Provider",
|
|
4480
|
-
contact: "Details",
|
|
4481
|
-
status: "Complete"
|
|
4482
|
-
};
|
|
4483
|
-
function brokenLimitOf(amount, quote) {
|
|
4484
|
-
const { minAmount, maxAmount } = quote;
|
|
4485
|
-
if (!Number.isFinite(amount)) return null;
|
|
4486
|
-
if (minAmount != null && amount < minAmount) return { limit: "min", value: minAmount };
|
|
4487
|
-
if (maxAmount != null && amount > maxAmount) return { limit: "max", value: maxAmount };
|
|
4488
|
-
return null;
|
|
4489
|
-
}
|
|
4490
|
-
function limitMessage(limit, value, currency) {
|
|
4491
|
-
return `The ${limit === "min" ? "minimum" : "maximum"} amount for this route is ${value} ${currency}.`;
|
|
4492
|
-
}
|
|
4711
|
+
var PAYMENT_CHECK_EVERY_MS = 1e4;
|
|
4712
|
+
var PAYMENT_CHECK_WINDOW_MS = 2 * 6e4;
|
|
4493
4713
|
var RAMP_ERROR_MESSAGES = {
|
|
4494
|
-
SDK_RAMPS_QUOTE_EXPIRED: "This quote expired.
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
SDK_RAMPS_ANCHOR_ERROR: "The provider rejected the request. Please try again in a moment.",
|
|
4500
|
-
SDK_RAMPS_BRIDGE_ERROR: "The provider rejected the request. Please try again in a moment.",
|
|
4501
|
-
SDK_RAMPS_ETHERFUSE_ERROR: "The provider rejected the request. Please try again in a moment.",
|
|
4502
|
-
SDK_RAMPS_INSUFFICIENT_BALANCE: "This wallet does not hold enough to cover that amount. Try a smaller one.",
|
|
4503
|
-
// Nothing moved on-chain, so the balance is untouched. Almost always no XLM
|
|
4504
|
-
// for the network fee on a wallet the app does not sponsor.
|
|
4505
|
-
SDK_RAMPS_ONCHAIN_SUBMIT_FAILED: "The network rejected the transaction, so nothing was sent. The wallet may need XLM for the fee."
|
|
4714
|
+
SDK_RAMPS_QUOTE_EXPIRED: "This quote expired. Find a route again.",
|
|
4715
|
+
SDK_RAMPS_QUOTE_NOT_FOUND: "This quote is no longer available. Find a route again.",
|
|
4716
|
+
SDK_RAMPS_ACTION_STALE: "This step changed. It was refreshed; try again.",
|
|
4717
|
+
SDK_RAMPS_TX_NOT_FOUND: "This operation was not found.",
|
|
4718
|
+
SDK_RAMPS_WALLET_NOT_READY: "Approve the new wallet account on your device, then try again."
|
|
4506
4719
|
};
|
|
4507
|
-
function rampErrorMessage(
|
|
4508
|
-
const
|
|
4509
|
-
|
|
4510
|
-
if (
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
return RAMP_ERROR_MESSAGES[code] ?? (e instanceof Error ? e.message : fallback);
|
|
4720
|
+
function rampErrorMessage(error, fallback) {
|
|
4721
|
+
const unavailable = core.appUnavailableMessage(error);
|
|
4722
|
+
if (unavailable) return unavailable;
|
|
4723
|
+
if (core.isPollarApiError(error)) {
|
|
4724
|
+
const known = RAMP_ERROR_MESSAGES[error.code];
|
|
4725
|
+
if (known) return known;
|
|
4726
|
+
const message = error.body.message;
|
|
4727
|
+
if (typeof message === "string" && message && !/^[A-Z0-9_]+$/.test(message)) return message;
|
|
4728
|
+
}
|
|
4729
|
+
return fallback;
|
|
4518
4730
|
}
|
|
4519
|
-
function
|
|
4520
|
-
|
|
4521
|
-
|
|
4522
|
-
|
|
4523
|
-
|
|
4524
|
-
|
|
4731
|
+
function routeKey(quote) {
|
|
4732
|
+
const node = (n) => n.kind === "asset" ? `${n.code}:${n.chain}` : `${n.currency}:${n.rail}`;
|
|
4733
|
+
return quote.legs.map((leg) => `${leg.kind}:${node(leg.from)}>${node(leg.to)}`).join("|");
|
|
4734
|
+
}
|
|
4735
|
+
var DECIMAL = /^\d+(\.\d+)?$/;
|
|
4736
|
+
async function signLegWithWallet(client, orderId, actionId) {
|
|
4737
|
+
const lent = [];
|
|
4738
|
+
const lend = (chain, encoding, handler) => {
|
|
4739
|
+
try {
|
|
4740
|
+
lent.push(client.registerRampSigningHandler(chain, encoding, handler));
|
|
4741
|
+
} catch {
|
|
4742
|
+
}
|
|
4743
|
+
};
|
|
4744
|
+
lend("STELLAR", "xdr", async (action) => {
|
|
4745
|
+
const wallet = client.getWallet();
|
|
4746
|
+
if (!wallet) throw new Error("Connect the Stellar wallet this step was built for.");
|
|
4747
|
+
core.assertRampStellarSigner(action, wallet.address);
|
|
4748
|
+
const outcome = await client.signTx(action.payload.value);
|
|
4749
|
+
if (client.getWallet()?.address !== wallet.address)
|
|
4750
|
+
throw new Error("The connected wallet changed. Refresh before signing.");
|
|
4751
|
+
if (outcome.status === "signed") return outcome.signedXdr;
|
|
4752
|
+
throw new Error(
|
|
4753
|
+
outcome.status === "error" ? outcome.message ?? outcome.details ?? "Signing was cancelled." : "Signing was cancelled."
|
|
4754
|
+
);
|
|
4755
|
+
});
|
|
4756
|
+
lend("SOLANA", "solana-v0-json", async (action) => {
|
|
4757
|
+
const payload = JSON.parse(action.payload.value);
|
|
4758
|
+
const solanaWallet = () => client.getWallets().find((w) => w.chain === "SOLANA" && w.custody === "external");
|
|
4759
|
+
const wallet = solanaWallet();
|
|
4760
|
+
if (!wallet || payload.from !== wallet.address || !payload.unsignedTransaction)
|
|
4761
|
+
throw new Error("This step must be signed by the Solana wallet it was built for. Reconnect that wallet.");
|
|
4762
|
+
const signed = await client.signSolanaTransaction(payload.unsignedTransaction);
|
|
4763
|
+
if (solanaWallet()?.address !== wallet.address) throw new Error("The connected wallet changed. Refresh before signing.");
|
|
4764
|
+
return signed;
|
|
4765
|
+
});
|
|
4766
|
+
try {
|
|
4767
|
+
return await client.signRampLeg(orderId, actionId);
|
|
4768
|
+
} finally {
|
|
4769
|
+
for (const release of lent) release();
|
|
4770
|
+
}
|
|
4525
4771
|
}
|
|
4526
4772
|
function RampWidget({ onClose }) {
|
|
4527
|
-
const {
|
|
4528
|
-
|
|
4773
|
+
const {
|
|
4774
|
+
getClient,
|
|
4775
|
+
styles,
|
|
4776
|
+
network,
|
|
4777
|
+
openCosignModal,
|
|
4778
|
+
setCosignNextStep,
|
|
4779
|
+
openRecoveryModal,
|
|
4780
|
+
recovery,
|
|
4781
|
+
recoveryLocked,
|
|
4782
|
+
appConfig,
|
|
4783
|
+
cosign,
|
|
4784
|
+
refreshWalletBalance
|
|
4785
|
+
} = usePollar();
|
|
4529
4786
|
const client = getClient();
|
|
4530
4787
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
4531
4788
|
const [step, setStep] = react.useState("input");
|
|
4532
|
-
const [direction, setDirection] = react.useState("
|
|
4533
|
-
const [
|
|
4534
|
-
const [
|
|
4789
|
+
const [direction, setDirection] = react.useState("ONRAMP");
|
|
4790
|
+
const [routes, setRoutes] = react.useState([]);
|
|
4791
|
+
const [routesLoading, setRoutesLoading] = react.useState(true);
|
|
4535
4792
|
const [country, setCountry] = react.useState("");
|
|
4536
|
-
const [
|
|
4537
|
-
const
|
|
4538
|
-
const [
|
|
4539
|
-
const [countriesLoading, setCountriesLoading] = react.useState(true);
|
|
4540
|
-
const [refreshing, setRefreshing] = react.useState(false);
|
|
4793
|
+
const [fiatChoice, setFiatChoice] = react.useState("");
|
|
4794
|
+
const [assetChoice, setAssetChoice] = react.useState("");
|
|
4795
|
+
const [amount, setAmount] = react.useState("");
|
|
4541
4796
|
const [quotes, setQuotes] = react.useState([]);
|
|
4542
|
-
const [
|
|
4543
|
-
const [
|
|
4797
|
+
const [rejected, setRejected] = react.useState([]);
|
|
4798
|
+
const [selected, setSelected] = react.useState(null);
|
|
4799
|
+
const [startingQuoteId, setStartingQuoteId] = react.useState(null);
|
|
4800
|
+
const [fieldValues, setFieldValues] = react.useState({});
|
|
4801
|
+
const [order, setOrder] = react.useState(null);
|
|
4802
|
+
const [pendingOrders, setPendingOrders] = react.useState([]);
|
|
4544
4803
|
const [isLoading, setIsLoading] = react.useState(false);
|
|
4545
|
-
const [
|
|
4546
|
-
const [
|
|
4547
|
-
const kycAttempt = react.useRef(null);
|
|
4548
|
-
react.useEffect(
|
|
4549
|
-
() => () => {
|
|
4550
|
-
kycAttempt.current = null;
|
|
4551
|
-
},
|
|
4552
|
-
[]
|
|
4553
|
-
);
|
|
4554
|
-
const [txId, setTxId] = react.useState(null);
|
|
4555
|
-
const [provider, setProvider] = react.useState("");
|
|
4556
|
-
const [kycUrl, setKycUrl] = react.useState(null);
|
|
4557
|
-
const [tosUrl, setTosUrl] = react.useState(null);
|
|
4558
|
-
const [kycPending, setKycPending] = react.useState(false);
|
|
4559
|
-
const [kycApproved, setKycApproved] = react.useState(false);
|
|
4560
|
-
const [onboardingStatus, setOnboardingStatus] = react.useState(void 0);
|
|
4561
|
-
const [txStatus, setTxStatus] = react.useState(null);
|
|
4562
|
-
const [stellarTxHash, setStellarTxHash] = react.useState(null);
|
|
4563
|
-
const [txHash, setTxHash] = react.useState(null);
|
|
4564
|
-
const [txChain, setTxChain] = react.useState(null);
|
|
4565
|
-
const [fundsInTransit, setFundsInTransit] = react.useState(false);
|
|
4566
|
-
const [retrying, setRetrying] = react.useState(false);
|
|
4567
|
-
const [depositInstructions, setDepositInstructions] = react.useState(null);
|
|
4568
|
-
const [completing, setCompleting] = react.useState(false);
|
|
4804
|
+
const [refreshing, setRefreshing] = react.useState(false);
|
|
4805
|
+
const [signing, setSigning] = react.useState(false);
|
|
4569
4806
|
const [errorMsg, setErrorMsg] = react.useState(null);
|
|
4570
|
-
const
|
|
4571
|
-
const
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
const id = setInterval(async () => {
|
|
4598
|
-
try {
|
|
4599
|
-
const tx = await client.getRampTransaction(txId);
|
|
4600
|
-
if (!active) return;
|
|
4601
|
-
setTxStatus(tx.status);
|
|
4602
|
-
applySettlement(tx);
|
|
4603
|
-
const pending = tx.pendingSignature;
|
|
4604
|
-
if (pending && !signingRef.current) {
|
|
4605
|
-
signingRef.current = true;
|
|
4606
|
-
void resumeRef.current(txId, pending).finally(() => {
|
|
4607
|
-
signingRef.current = false;
|
|
4608
|
-
});
|
|
4609
|
-
}
|
|
4610
|
-
if (tx.kycUrl) setKycUrl(tx.kycUrl);
|
|
4611
|
-
if (tx.depositInstructions) setDepositInstructions(tx.depositInstructions);
|
|
4612
|
-
if (TERMINAL.includes(tx.status)) clearInterval(id);
|
|
4613
|
-
} catch {
|
|
4614
|
-
}
|
|
4615
|
-
}, 5e3);
|
|
4616
|
-
return () => {
|
|
4617
|
-
active = false;
|
|
4618
|
-
clearInterval(id);
|
|
4619
|
-
};
|
|
4620
|
-
}, [step, txId, txStatus, client]);
|
|
4807
|
+
const [verifying, setVerifying] = react.useState(null);
|
|
4808
|
+
const [trustingAsset, setTrustingAsset] = react.useState(null);
|
|
4809
|
+
const [walletBusy, setWalletBusy] = react.useState(null);
|
|
4810
|
+
const [retrying, setRetrying] = react.useState(false);
|
|
4811
|
+
const [awaitingAccount, setAwaitingAccount] = react.useState(null);
|
|
4812
|
+
const [pollTrouble, setPollTrouble] = react.useState(false);
|
|
4813
|
+
const [pollKey, setPollKey] = react.useState(0);
|
|
4814
|
+
const [paymentCheckUntil, setPaymentCheckUntil] = react.useState(null);
|
|
4815
|
+
const promptedApproval = react.useRef(null);
|
|
4816
|
+
const custodyChoice = appConfig.application?.walletCustodyMode === "USER_CHOICE";
|
|
4817
|
+
const appChains = appConfig.application?.chains;
|
|
4818
|
+
const verifyAttempt = react.useRef(null);
|
|
4819
|
+
const countries = react.useMemo(() => core.rampCountries(routes), [routes]);
|
|
4820
|
+
const fiats = countries.find((c) => c.country === country)?.fiats ?? [];
|
|
4821
|
+
const fiat = fiats.find((f) => fiatKey(f) === fiatChoice) ?? fiats[0] ?? null;
|
|
4822
|
+
const assets = react.useMemo(() => {
|
|
4823
|
+
const seen = /* @__PURE__ */ new Map();
|
|
4824
|
+
for (const route of routes)
|
|
4825
|
+
if (fiat && route.fiat.country === country && fiatKey(route.fiat) === fiatKey(fiat))
|
|
4826
|
+
seen.set(assetKey3(route.asset), route.asset);
|
|
4827
|
+
return [...seen.values()];
|
|
4828
|
+
}, [routes, country, fiat]);
|
|
4829
|
+
const asset = assets.find((a) => assetKey3(a) === assetChoice) ?? assets[0] ?? null;
|
|
4830
|
+
const fields = selected ? core.rampQuoteFields(selected) : [];
|
|
4831
|
+
const sellAvailable = useWalletAvailable(
|
|
4832
|
+
direction === "OFFRAMP" && asset ? { chain: asset.chain, code: asset.code, issuer: asset.identifier } : null
|
|
4833
|
+
);
|
|
4621
4834
|
react.useEffect(() => {
|
|
4622
|
-
if (
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
try {
|
|
4627
|
-
const { hasApproved } = await client.getRampKycStatus();
|
|
4628
|
-
if (active && hasApproved) setKycApproved(true);
|
|
4629
|
-
} catch {
|
|
4630
|
-
}
|
|
4631
|
-
};
|
|
4632
|
-
void check();
|
|
4633
|
-
const id = setInterval(check, 1e4);
|
|
4634
|
-
return () => {
|
|
4635
|
-
active = false;
|
|
4636
|
-
clearInterval(id);
|
|
4637
|
-
};
|
|
4638
|
-
}, [step, kycPending, kycApproved, onboardingStatus, client]);
|
|
4639
|
-
async function loadCountries(resetSelection) {
|
|
4640
|
-
setCountriesLoading(true);
|
|
4835
|
+
if (direction === "OFFRAMP") void refreshWalletBalance();
|
|
4836
|
+
}, [direction, refreshWalletBalance]);
|
|
4837
|
+
async function loadRoutes(next) {
|
|
4838
|
+
setRoutesLoading(true);
|
|
4641
4839
|
try {
|
|
4642
|
-
const {
|
|
4643
|
-
|
|
4644
|
-
const first =
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
}
|
|
4650
|
-
} catch {
|
|
4651
|
-
setCountries([]);
|
|
4840
|
+
const { routes: found } = await client.getRampRoutes(next);
|
|
4841
|
+
setRoutes(found);
|
|
4842
|
+
const first = core.rampCountries(found)[0]?.country ?? "";
|
|
4843
|
+
setCountry((current) => found.some((r) => r.fiat.country === current) ? current : first);
|
|
4844
|
+
} catch (error) {
|
|
4845
|
+
setRoutes([]);
|
|
4846
|
+
setErrorMsg(rampErrorMessage(error, "Could not load the ramp routes."));
|
|
4652
4847
|
} finally {
|
|
4653
|
-
|
|
4848
|
+
setRoutesLoading(false);
|
|
4654
4849
|
}
|
|
4655
4850
|
}
|
|
4656
|
-
|
|
4657
|
-
loadCountries(true);
|
|
4658
|
-
}, []);
|
|
4659
|
-
function handleCountryChange(code) {
|
|
4660
|
-
setCountry(code);
|
|
4661
|
-
const match = countries.find((c) => c.code === code);
|
|
4662
|
-
if (match?.currency) setCurrency(match.currency);
|
|
4663
|
-
}
|
|
4664
|
-
async function handleRefresh() {
|
|
4665
|
-
if (refreshing) return;
|
|
4666
|
-
setRefreshing(true);
|
|
4851
|
+
async function loadPendingOrders() {
|
|
4667
4852
|
try {
|
|
4668
|
-
await
|
|
4669
|
-
|
|
4670
|
-
const result = await client.getRampsQuote({ country, amount: Number(amount), currency, direction });
|
|
4671
|
-
setQuotes(result.quotes ?? []);
|
|
4672
|
-
setRequirementsRequired(result.requirementsRequired ?? []);
|
|
4673
|
-
} else if (step === "status" && txId) {
|
|
4674
|
-
const tx = await client.getRampTransaction(txId);
|
|
4675
|
-
setTxStatus(tx.status);
|
|
4676
|
-
applySettlement(tx);
|
|
4677
|
-
if (tx.kycUrl) setKycUrl(tx.kycUrl);
|
|
4678
|
-
if (tx.depositInstructions) setDepositInstructions(tx.depositInstructions);
|
|
4679
|
-
}
|
|
4853
|
+
const page = await client.listRampOrders({ open: "true", limit: 5 });
|
|
4854
|
+
setPendingOrders(page.orders);
|
|
4680
4855
|
} catch {
|
|
4681
|
-
|
|
4682
|
-
setRefreshing(false);
|
|
4856
|
+
setPendingOrders([]);
|
|
4683
4857
|
}
|
|
4684
4858
|
}
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
if (!keepMessage) setErrorMsg(null);
|
|
4705
|
-
}
|
|
4706
|
-
async function resumeWithSignature(id, ps) {
|
|
4707
|
-
const outcome = await signTx(ps.unsignedXdr);
|
|
4708
|
-
if (outcome.status === "cosign_pending") {
|
|
4709
|
-
setErrorMsg("Approve the signature on your device, then resume.");
|
|
4710
|
-
setStep("error");
|
|
4711
|
-
return;
|
|
4712
|
-
}
|
|
4713
|
-
if (outcome.status !== "signed") {
|
|
4714
|
-
setErrorMsg(outcome.message ?? outcome.details ?? "Signing was cancelled.");
|
|
4715
|
-
setStep("error");
|
|
4716
|
-
return;
|
|
4717
|
-
}
|
|
4718
|
-
const result = await client.submitRampSignature(id, {
|
|
4719
|
-
signedXdr: outcome.signedXdr,
|
|
4720
|
-
// The CCTP actions are not in the generated schema until it is regenerated.
|
|
4721
|
-
action: ps.action
|
|
4859
|
+
react.useEffect(() => {
|
|
4860
|
+
void loadRoutes(direction);
|
|
4861
|
+
}, [client, direction]);
|
|
4862
|
+
react.useEffect(() => {
|
|
4863
|
+
void loadPendingOrders();
|
|
4864
|
+
}, [client]);
|
|
4865
|
+
const orderId = order?.id ?? null;
|
|
4866
|
+
react.useEffect(() => {
|
|
4867
|
+
if (step !== "status" || !orderId) return;
|
|
4868
|
+
const controller = new AbortController();
|
|
4869
|
+
client.pollRampOrder(orderId, {
|
|
4870
|
+
signal: controller.signal,
|
|
4871
|
+
onUpdate: (next) => {
|
|
4872
|
+
setOrder(next);
|
|
4873
|
+
setPollTrouble(false);
|
|
4874
|
+
},
|
|
4875
|
+
onError: () => setPollTrouble(true)
|
|
4876
|
+
}).catch((error) => {
|
|
4877
|
+
if (!controller.signal.aborted) setErrorMsg(rampErrorMessage(error, "This operation could not be read."));
|
|
4722
4878
|
});
|
|
4723
|
-
|
|
4724
|
-
}
|
|
4725
|
-
const
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
await resumeWithSignature(result.txId, result.pendingSignature);
|
|
4879
|
+
return () => controller.abort();
|
|
4880
|
+
}, [client, step, orderId, pollKey]);
|
|
4881
|
+
const awaitingPayment = step === "status" && order?.pendingAction?.kind === "FIAT_PAYMENT";
|
|
4882
|
+
react.useEffect(() => {
|
|
4883
|
+
if (paymentCheckUntil === null || !orderId) return;
|
|
4884
|
+
if (!awaitingPayment) {
|
|
4885
|
+
setPaymentCheckUntil(null);
|
|
4886
|
+
setPollKey((key) => key + 1);
|
|
4732
4887
|
return;
|
|
4733
4888
|
}
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4889
|
+
const timer = setInterval(() => {
|
|
4890
|
+
if (Date.now() >= paymentCheckUntil) {
|
|
4891
|
+
setPaymentCheckUntil(null);
|
|
4892
|
+
return;
|
|
4893
|
+
}
|
|
4894
|
+
client.checkRampOrder(orderId).then(setOrder).catch(() => void 0);
|
|
4895
|
+
}, PAYMENT_CHECK_EVERY_MS);
|
|
4896
|
+
return () => clearInterval(timer);
|
|
4897
|
+
}, [client, orderId, awaitingPayment, paymentCheckUntil]);
|
|
4898
|
+
const approval = order?.pendingAction?.kind === "COSIGN_APPROVAL" ? order.pendingAction.actionId : null;
|
|
4899
|
+
react.useEffect(() => {
|
|
4900
|
+
if (!approval || promptedApproval.current === approval) return;
|
|
4901
|
+
promptedApproval.current = approval;
|
|
4902
|
+
void client.cosign.pending().catch(() => void 0).then(() => openCosignModal());
|
|
4903
|
+
}, [approval, client, openCosignModal]);
|
|
4904
|
+
const nextApproval = step === "status" && order ? core.rampNextApproval(order) : null;
|
|
4905
|
+
react.useEffect(() => {
|
|
4906
|
+
setCosignNextStep(nextApproval);
|
|
4907
|
+
}, [nextApproval, setCosignNextStep]);
|
|
4908
|
+
react.useEffect(() => () => setCosignNextStep(null), [setCosignNextStep]);
|
|
4909
|
+
const resolvedRequest = cosign.lastResolved;
|
|
4910
|
+
react.useEffect(() => {
|
|
4911
|
+
if (!awaitingAccount || resolvedRequest?.id !== awaitingAccount.requestId) return;
|
|
4912
|
+
setAwaitingAccount(null);
|
|
4913
|
+
if (resolvedRequest.status !== "APPROVED") {
|
|
4914
|
+
setErrorMsg("The new account was not approved, so this route cannot start.");
|
|
4915
|
+
return;
|
|
4755
4916
|
}
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4917
|
+
void resumeRoute(awaitingAccount.routeKey);
|
|
4918
|
+
}, [awaitingAccount, resolvedRequest]);
|
|
4919
|
+
function handleDirectionChange(next) {
|
|
4920
|
+
setDirection(next);
|
|
4921
|
+
setErrorMsg(null);
|
|
4922
|
+
setAwaitingAccount(null);
|
|
4759
4923
|
}
|
|
4760
4924
|
async function handleFindRoute() {
|
|
4925
|
+
if (!fiat || !asset) return [];
|
|
4926
|
+
if (!DECIMAL.test(amount.trim()) || Number(amount) <= 0) {
|
|
4927
|
+
setErrorMsg("Enter an amount greater than zero.");
|
|
4928
|
+
return [];
|
|
4929
|
+
}
|
|
4761
4930
|
setStep("loading_quote");
|
|
4762
|
-
setIsLoading(true);
|
|
4763
4931
|
setErrorMsg(null);
|
|
4932
|
+
setSelected(null);
|
|
4764
4933
|
try {
|
|
4765
|
-
|
|
4934
|
+
const result = await client.quoteRamp({
|
|
4935
|
+
direction,
|
|
4936
|
+
fiat: { currency: fiat.currency, rail: fiat.rail, country: fiat.country },
|
|
4937
|
+
asset: { code: asset.code, identifier: asset.identifier, chain: asset.chain },
|
|
4938
|
+
amount: { value: amount.trim(), denomination: "in" }
|
|
4939
|
+
});
|
|
4940
|
+
setQuotes(result.quotes);
|
|
4941
|
+
setRejected(result.rejected);
|
|
4766
4942
|
setStep("select_route");
|
|
4767
|
-
|
|
4768
|
-
|
|
4943
|
+
return result.quotes;
|
|
4944
|
+
} catch (error) {
|
|
4945
|
+
if (core.isPollarApiError(error) && error.code === "SDK_RAMPS_NO_ROUTE") {
|
|
4946
|
+
setQuotes([]);
|
|
4947
|
+
setRejected(Array.isArray(error.body.rejected) ? error.body.rejected : []);
|
|
4948
|
+
setStep("select_route");
|
|
4949
|
+
return [];
|
|
4950
|
+
}
|
|
4951
|
+
setErrorMsg(rampErrorMessage(error, "Could not find a route. Please try again."));
|
|
4769
4952
|
setStep("error");
|
|
4953
|
+
return [];
|
|
4954
|
+
}
|
|
4955
|
+
}
|
|
4956
|
+
function handleVerifyRoute(requirement) {
|
|
4957
|
+
setErrorMsg(null);
|
|
4958
|
+
verifyAttempt.current = requirement;
|
|
4959
|
+
setVerifying(requirement);
|
|
4960
|
+
}
|
|
4961
|
+
function closeVerification() {
|
|
4962
|
+
verifyAttempt.current = null;
|
|
4963
|
+
setVerifying(null);
|
|
4964
|
+
}
|
|
4965
|
+
function verificationDone(requirement) {
|
|
4966
|
+
if (verifyAttempt.current !== requirement) return;
|
|
4967
|
+
closeVerification();
|
|
4968
|
+
void handleFindRoute();
|
|
4969
|
+
}
|
|
4970
|
+
async function handleTrustAsset(asset2) {
|
|
4971
|
+
if (trustingAsset) return;
|
|
4972
|
+
setTrustingAsset(`${asset2.code}:${asset2.issuer}`);
|
|
4973
|
+
setErrorMsg(null);
|
|
4974
|
+
try {
|
|
4975
|
+
const outcome = await client.setTrustline(asset2);
|
|
4976
|
+
if (outcome.status === "error") {
|
|
4977
|
+
setErrorMsg(core.rampTrustlineErrorText(outcome, asset2.code));
|
|
4978
|
+
return;
|
|
4979
|
+
}
|
|
4980
|
+
if (outcome.status === "cosign_pending") {
|
|
4981
|
+
setErrorMsg(`Approve the ${asset2.code} trustline, then refresh the routes.`);
|
|
4982
|
+
openCosignModal();
|
|
4983
|
+
return;
|
|
4984
|
+
}
|
|
4985
|
+
await client.refreshAssets().catch(() => {
|
|
4986
|
+
});
|
|
4987
|
+
await handleFindRoute();
|
|
4988
|
+
} catch (error) {
|
|
4989
|
+
setErrorMsg(rampErrorMessage(error, `Could not add the ${asset2.code} trustline. Please try again.`));
|
|
4770
4990
|
} finally {
|
|
4771
|
-
|
|
4991
|
+
setTrustingAsset(null);
|
|
4772
4992
|
}
|
|
4773
4993
|
}
|
|
4774
|
-
function
|
|
4775
|
-
|
|
4994
|
+
async function handleWalletStep(walletStep, index, custody) {
|
|
4995
|
+
if (walletBusy !== null) return;
|
|
4996
|
+
setWalletBusy(index);
|
|
4776
4997
|
setErrorMsg(null);
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4998
|
+
try {
|
|
4999
|
+
const { recoveryRequired } = await client.runRampWalletStep(walletStep, custody);
|
|
5000
|
+
if (recoveryRequired) {
|
|
5001
|
+
setErrorMsg("Add a way to recover your wallet, then find the route again.");
|
|
5002
|
+
openRecoveryModal();
|
|
5003
|
+
return;
|
|
5004
|
+
}
|
|
5005
|
+
await handleFindRoute();
|
|
5006
|
+
} catch (error) {
|
|
5007
|
+
const code = core.isPollarApiError(error) ? error.code : null;
|
|
5008
|
+
if (code === "SDK_RAMPS_WALLET_NOT_READY") {
|
|
5009
|
+
setErrorMsg("Approve the new account, then find the route again.");
|
|
5010
|
+
openCosignModal();
|
|
5011
|
+
return;
|
|
5012
|
+
}
|
|
5013
|
+
setErrorMsg(
|
|
5014
|
+
code === "SDK_WALLET_PROVISIONING_DISABLED" ? "This app does not create wallets." : rampErrorMessage(error, "Could not prepare the wallet. Please try again.")
|
|
5015
|
+
);
|
|
5016
|
+
} finally {
|
|
5017
|
+
setWalletBusy(null);
|
|
4782
5018
|
}
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
5019
|
+
}
|
|
5020
|
+
async function resumeRoute(key) {
|
|
5021
|
+
const same = (await handleFindRoute()).find((q) => routeKey(q) === key);
|
|
5022
|
+
if (same) handleSelectQuote(same, true);
|
|
5023
|
+
else setErrorMsg("That route is no longer available. Pick another one.");
|
|
5024
|
+
}
|
|
5025
|
+
function handleSelectQuote(quote, fresh = false) {
|
|
5026
|
+
if (!fresh && Date.parse(quote.expiresAt) <= Date.now()) {
|
|
5027
|
+
void resumeRoute(routeKey(quote));
|
|
4787
5028
|
return;
|
|
4788
5029
|
}
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
if (
|
|
5030
|
+
setSelected(quote);
|
|
5031
|
+
setErrorMsg(null);
|
|
5032
|
+
const missing = core.rampQuoteFields(quote).some((f) => !f.optional && !(fieldValues[f.key] ?? "").trim());
|
|
5033
|
+
if (missing) setStep("contact");
|
|
5034
|
+
else void startOrder(quote, fresh);
|
|
4793
5035
|
}
|
|
4794
|
-
async function
|
|
5036
|
+
async function startOrder(quote, fresh = false) {
|
|
4795
5037
|
setIsLoading(true);
|
|
5038
|
+
setStartingQuoteId(quote.quoteId);
|
|
4796
5039
|
setErrorMsg(null);
|
|
5040
|
+
setAwaitingAccount(null);
|
|
4797
5041
|
try {
|
|
4798
|
-
const
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
const
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
5042
|
+
const payee = Object.fromEntries(
|
|
5043
|
+
core.rampQuoteFields(quote).map((f) => [f.key, (fieldValues[f.key] ?? "").trim()]).filter(([, value]) => value)
|
|
5044
|
+
);
|
|
5045
|
+
const created = await client.createRampOrder({
|
|
5046
|
+
quoteId: quote.quoteId,
|
|
5047
|
+
...Object.keys(payee).length ? { payee } : {}
|
|
5048
|
+
});
|
|
5049
|
+
setOrder(created);
|
|
5050
|
+
setStep("status");
|
|
5051
|
+
} catch (error) {
|
|
5052
|
+
if (core.isPollarApiError(error) && error.code === "SDK_RAMPS_WALLET_NOT_READY") {
|
|
5053
|
+
const pending = await client.cosign.pending().catch(() => []);
|
|
5054
|
+
const request = pending.find((r) => r.intent === "add_accounts");
|
|
5055
|
+
if (request) setAwaitingAccount({ routeKey: routeKey(quote), requestId: request.id });
|
|
5056
|
+
else setErrorMsg(rampErrorMessage(error, "Could not start the operation. Please try again."));
|
|
5057
|
+
openCosignModal();
|
|
5058
|
+
setStep("select_route");
|
|
5059
|
+
return;
|
|
4808
5060
|
}
|
|
4809
|
-
if (
|
|
4810
|
-
|
|
4811
|
-
await applyResult(result);
|
|
4812
|
-
} catch (e) {
|
|
4813
|
-
const requirement = requiredRampKyc(e);
|
|
4814
|
-
if (requirement) {
|
|
4815
|
-
setStep(requiredFieldsOf(quote).length ? "contact" : "select_route");
|
|
4816
|
-
setErrorMsg(
|
|
4817
|
-
requirement.type === "KYC" ? "Identity verification is required before continuing." : "A few more details are required before continuing."
|
|
4818
|
-
);
|
|
4819
|
-
kycAttempt.current = requirement;
|
|
4820
|
-
setPendingKyc(requirement);
|
|
5061
|
+
if (core.isPollarApiError(error) && error.code === "SDK_RAMPS_QUOTE_EXPIRED" && !fresh) {
|
|
5062
|
+
void resumeRoute(routeKey(quote));
|
|
4821
5063
|
return;
|
|
4822
5064
|
}
|
|
4823
|
-
setErrorMsg(rampErrorMessage(
|
|
4824
|
-
setStep("
|
|
5065
|
+
setErrorMsg(rampErrorMessage(error, "Could not start the operation. Please try again."));
|
|
5066
|
+
if (core.isPollarApiError(error) && error.code === "VALIDATION_ERROR" && core.rampQuoteFields(quote).length) setStep("contact");
|
|
5067
|
+
else setStep("select_route");
|
|
4825
5068
|
} finally {
|
|
4826
5069
|
setIsLoading(false);
|
|
5070
|
+
setStartingQuoteId(null);
|
|
4827
5071
|
}
|
|
4828
5072
|
}
|
|
4829
|
-
async function
|
|
4830
|
-
|
|
5073
|
+
async function handleSign() {
|
|
5074
|
+
const action = order?.pendingAction;
|
|
5075
|
+
if (!order || action?.kind !== "SIGNATURE" || signing) return;
|
|
5076
|
+
setSigning(true);
|
|
5077
|
+
setErrorMsg(null);
|
|
5078
|
+
try {
|
|
5079
|
+
setOrder(await signLegWithWallet(client, order.id, action.actionId));
|
|
5080
|
+
} catch (error) {
|
|
5081
|
+
setErrorMsg(rampErrorMessage(error, error instanceof Error && error.message ? error.message : "Signing was cancelled."));
|
|
5082
|
+
setOrder(await client.getRampOrder(order.id).catch(() => order));
|
|
5083
|
+
} finally {
|
|
5084
|
+
setSigning(false);
|
|
5085
|
+
}
|
|
5086
|
+
}
|
|
5087
|
+
async function handleResumeOrder(id) {
|
|
4831
5088
|
setIsLoading(true);
|
|
4832
5089
|
setErrorMsg(null);
|
|
4833
|
-
setSelectedQuote(null);
|
|
4834
5090
|
try {
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
);
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
setErrorMsg(rampErrorMessage(e, "Failed to fetch quotes."));
|
|
4842
|
-
setStep("error");
|
|
5091
|
+
const found = await client.getRampOrder(id);
|
|
5092
|
+
setDirection(found.direction);
|
|
5093
|
+
setOrder(found);
|
|
5094
|
+
setStep("status");
|
|
5095
|
+
} catch (error) {
|
|
5096
|
+
setErrorMsg(rampErrorMessage(error, "Could not resume the operation."));
|
|
4843
5097
|
} finally {
|
|
4844
5098
|
setIsLoading(false);
|
|
4845
5099
|
}
|
|
4846
5100
|
}
|
|
4847
|
-
function
|
|
4848
|
-
|
|
5101
|
+
function handleNewOrder() {
|
|
5102
|
+
setAwaitingAccount(null);
|
|
5103
|
+
setOrder(null);
|
|
5104
|
+
setSelected(null);
|
|
5105
|
+
setQuotes([]);
|
|
5106
|
+
setRejected([]);
|
|
4849
5107
|
setErrorMsg(null);
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
setPendingKyc(attempt);
|
|
5108
|
+
setStep("input");
|
|
5109
|
+
void loadPendingOrders();
|
|
4853
5110
|
}
|
|
4854
|
-
function
|
|
4855
|
-
|
|
5111
|
+
function handleBack() {
|
|
5112
|
+
setErrorMsg(null);
|
|
5113
|
+
setAwaitingAccount(null);
|
|
5114
|
+
setStep(step === "contact" ? "select_route" : "input");
|
|
4856
5115
|
}
|
|
4857
|
-
function
|
|
4858
|
-
|
|
5116
|
+
function handleStepSelect(target) {
|
|
5117
|
+
setErrorMsg(null);
|
|
5118
|
+
setAwaitingAccount(null);
|
|
5119
|
+
setStep(target === "Route" ? "select_route" : "input");
|
|
4859
5120
|
}
|
|
4860
|
-
async function
|
|
4861
|
-
if (!
|
|
4862
|
-
setCompleting(true);
|
|
5121
|
+
async function handleCheckPayment() {
|
|
5122
|
+
if (!order || paymentCheckUntil !== null) return;
|
|
4863
5123
|
setErrorMsg(null);
|
|
5124
|
+
setPaymentCheckUntil(Date.now() + PAYMENT_CHECK_WINDOW_MS);
|
|
4864
5125
|
try {
|
|
4865
|
-
|
|
4866
|
-
|
|
4867
|
-
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
);
|
|
5126
|
+
setOrder(await client.checkRampOrder(order.id));
|
|
5127
|
+
} catch (error) {
|
|
5128
|
+
setPaymentCheckUntil(null);
|
|
5129
|
+
setErrorMsg(rampErrorMessage(error, "Could not check the payment. Please try again."));
|
|
5130
|
+
}
|
|
5131
|
+
}
|
|
5132
|
+
async function handleRetryOrder() {
|
|
5133
|
+
if (!order || retrying) return;
|
|
5134
|
+
setRetrying(true);
|
|
5135
|
+
setErrorMsg(null);
|
|
5136
|
+
try {
|
|
5137
|
+
setOrder(await client.retryRampOrder(order.id));
|
|
5138
|
+
setPollKey((key) => key + 1);
|
|
5139
|
+
} catch (error) {
|
|
5140
|
+
setErrorMsg(rampErrorMessage(error, "Could not try again. Please try again."));
|
|
4877
5141
|
} finally {
|
|
4878
|
-
|
|
5142
|
+
setRetrying(false);
|
|
4879
5143
|
}
|
|
4880
5144
|
}
|
|
4881
|
-
const
|
|
4882
|
-
const
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
void requoteAfterKyc("FORM");
|
|
4900
|
-
}
|
|
5145
|
+
const heldForRecovery = step === "status" && order?.failure?.resolutionAction === "set_up_recovery";
|
|
5146
|
+
const wasRecoveryLocked = react.useRef(recoveryLocked);
|
|
5147
|
+
react.useEffect(() => {
|
|
5148
|
+
if (heldForRecovery && wasRecoveryLocked.current && !recoveryLocked && recovery) void handleRetryOrder();
|
|
5149
|
+
wasRecoveryLocked.current = recoveryLocked;
|
|
5150
|
+
}, [heldForRecovery, recoveryLocked, recovery]);
|
|
5151
|
+
async function handleRefresh() {
|
|
5152
|
+
if (refreshing) return;
|
|
5153
|
+
setRefreshing(true);
|
|
5154
|
+
try {
|
|
5155
|
+
if (step === "status" && order) {
|
|
5156
|
+
setOrder(await client.getRampOrder(order.id));
|
|
5157
|
+
setPollKey((key) => key + 1);
|
|
5158
|
+
} else if (step === "select_route") await handleFindRoute();
|
|
5159
|
+
else {
|
|
5160
|
+
await loadRoutes(direction);
|
|
5161
|
+
await loadPendingOrders();
|
|
5162
|
+
if (direction === "OFFRAMP") await refreshWalletBalance();
|
|
4901
5163
|
}
|
|
4902
|
-
)
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
setPendingKyc(null);
|
|
4908
|
-
};
|
|
4909
|
-
const done = () => {
|
|
4910
|
-
if (kycAttempt.current !== pendingKyc) return;
|
|
4911
|
-
close();
|
|
4912
|
-
void requoteAfterKyc(pendingKyc.type);
|
|
4913
|
-
};
|
|
4914
|
-
const progress = pendingKyc.progress ? { progress: pendingKyc.progress } : {};
|
|
4915
|
-
return pendingKyc.type === "REGISTRY_CHECK" ? /* @__PURE__ */ jsxRuntime.jsx(RegistryCheckModal, { optionId: pendingKyc.optionId, ...progress, onClose: close, onApproved: done }) : /* @__PURE__ */ jsxRuntime.jsx(ProviderRegistrationModal, { corridorId: pendingKyc.corridorId, ...progress, onClose: close, onRegistered: done });
|
|
5164
|
+
} catch (error) {
|
|
5165
|
+
setErrorMsg(rampErrorMessage(error, "Could not refresh."));
|
|
5166
|
+
} finally {
|
|
5167
|
+
setRefreshing(false);
|
|
5168
|
+
}
|
|
4916
5169
|
}
|
|
4917
|
-
|
|
5170
|
+
const flowSteps = fields.length || quotes.some((q) => core.rampQuoteFields(q).length) ? ["Amount", "Route", "Details", "Complete"] : ["Amount", "Route", "Complete"];
|
|
5171
|
+
const stepLabel = {
|
|
5172
|
+
input: "Amount",
|
|
5173
|
+
loading_quote: "Amount",
|
|
5174
|
+
select_route: "Route",
|
|
5175
|
+
contact: "Details",
|
|
5176
|
+
status: "Complete"
|
|
5177
|
+
};
|
|
5178
|
+
const label = stepLabel[step];
|
|
5179
|
+
if (verifying) {
|
|
5180
|
+
const progress = { progress: { position: verifying.completed + 1, total: verifying.total } };
|
|
5181
|
+
const done = () => verificationDone(verifying);
|
|
5182
|
+
if (verifying.type === "FORM")
|
|
5183
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RequirementFormModal, { formId: verifying.optionId, ...progress, onClose: closeVerification, onSubmitted: done });
|
|
5184
|
+
if (verifying.type === "REGISTRY_CHECK")
|
|
5185
|
+
return /* @__PURE__ */ jsxRuntime.jsx(RegistryCheckModal, { optionId: verifying.optionId, ...progress, onClose: closeVerification, onApproved: done });
|
|
5186
|
+
if (verifying.type === "PROVIDER_REGISTRATION")
|
|
5187
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
5188
|
+
ProviderRegistrationModal,
|
|
5189
|
+
{
|
|
5190
|
+
corridorId: verifying.corridorId,
|
|
5191
|
+
...progress,
|
|
5192
|
+
onClose: closeVerification,
|
|
5193
|
+
onRegistered: done
|
|
5194
|
+
}
|
|
5195
|
+
);
|
|
4918
5196
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4919
5197
|
KycModal,
|
|
4920
5198
|
{
|
|
4921
5199
|
country,
|
|
4922
|
-
corridorId:
|
|
4923
|
-
providerId:
|
|
4924
|
-
onClose:
|
|
4925
|
-
|
|
4926
|
-
setPendingKyc(null);
|
|
4927
|
-
},
|
|
4928
|
-
onApproved: () => {
|
|
4929
|
-
if (kycAttempt.current !== pendingKyc) return;
|
|
4930
|
-
kycAttempt.current = null;
|
|
4931
|
-
setPendingKyc(null);
|
|
4932
|
-
void requoteAfterKyc();
|
|
4933
|
-
}
|
|
5200
|
+
corridorId: verifying.corridorId,
|
|
5201
|
+
providerId: verifying.optionId,
|
|
5202
|
+
onClose: closeVerification,
|
|
5203
|
+
onApproved: done
|
|
4934
5204
|
}
|
|
4935
5205
|
);
|
|
4936
5206
|
}
|
|
@@ -4939,59 +5209,79 @@ function RampWidget({ onClose }) {
|
|
|
4939
5209
|
{
|
|
4940
5210
|
theme,
|
|
4941
5211
|
accentColor,
|
|
4942
|
-
styleOverrides,
|
|
5212
|
+
...styleOverrides ? { styleOverrides } : {},
|
|
5213
|
+
network,
|
|
4943
5214
|
step,
|
|
4944
5215
|
flowSteps,
|
|
4945
|
-
flowStepIndex,
|
|
4946
|
-
startingQuoteId: isLoading && selectedQuote ? selectedQuote.quoteId : null,
|
|
5216
|
+
flowStepIndex: label ? flowSteps.indexOf(label) : -1,
|
|
4947
5217
|
direction,
|
|
4948
|
-
|
|
4949
|
-
currency,
|
|
4950
|
-
country,
|
|
4951
|
-
requiredFields: selectedQuote ? requiredFieldsOf(selectedQuote) : [],
|
|
4952
|
-
fieldValues,
|
|
5218
|
+
routesLoading,
|
|
4953
5219
|
countries,
|
|
4954
|
-
|
|
4955
|
-
|
|
5220
|
+
country,
|
|
5221
|
+
fiats,
|
|
5222
|
+
fiat,
|
|
5223
|
+
assets,
|
|
5224
|
+
asset,
|
|
5225
|
+
amount,
|
|
5226
|
+
sellAvailable,
|
|
4956
5227
|
quotes,
|
|
4957
|
-
|
|
5228
|
+
rejected,
|
|
5229
|
+
startingQuoteId,
|
|
5230
|
+
fields,
|
|
5231
|
+
fieldValues,
|
|
5232
|
+
order,
|
|
5233
|
+
pendingOrders,
|
|
4958
5234
|
isLoading,
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
kycUrl,
|
|
4962
|
-
tosUrl,
|
|
4963
|
-
kycBlocking,
|
|
4964
|
-
onboardingStatus: onboardingStatus ?? null,
|
|
4965
|
-
kycJustApproved: kycPending && kycApproved,
|
|
4966
|
-
stellarTxHash,
|
|
4967
|
-
txHash,
|
|
4968
|
-
txChain,
|
|
4969
|
-
explorerUrl: explorerTxUrl2(txChain ?? "STELLAR", txHash ?? stellarTxHash, network),
|
|
4970
|
-
fundsInTransit,
|
|
4971
|
-
retrying,
|
|
4972
|
-
onRetryTransit: handleRetryTransit,
|
|
4973
|
-
depositInstructions,
|
|
4974
|
-
canComplete,
|
|
4975
|
-
completing,
|
|
5235
|
+
refreshing,
|
|
5236
|
+
signing,
|
|
4976
5237
|
errorMsg,
|
|
4977
|
-
|
|
4978
|
-
onDirectionChange:
|
|
4979
|
-
|
|
4980
|
-
|
|
5238
|
+
notice: awaitingAccount ? "Approve the new account on your device. The order starts once it is approved." : null,
|
|
5239
|
+
onDirectionChange: handleDirectionChange,
|
|
5240
|
+
onCountryChange: (next) => {
|
|
5241
|
+
setCountry(next);
|
|
5242
|
+
setFiatChoice("");
|
|
5243
|
+
setAssetChoice("");
|
|
5244
|
+
},
|
|
5245
|
+
onFiatChange: (key) => {
|
|
5246
|
+
setFiatChoice(key);
|
|
5247
|
+
setAssetChoice("");
|
|
5248
|
+
},
|
|
5249
|
+
onAssetChange: setAssetChoice,
|
|
5250
|
+
onAmountChange: (value) => {
|
|
5251
|
+
setAmount(value);
|
|
4981
5252
|
setErrorMsg(null);
|
|
4982
5253
|
},
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
onFindRoute: handleFindRoute,
|
|
4986
|
-
onSelectQuote: handleSelectQuote,
|
|
5254
|
+
onFindRoute: () => void handleFindRoute(),
|
|
5255
|
+
onSelectQuote: (quote) => handleSelectQuote(quote),
|
|
4987
5256
|
onVerifyRoute: handleVerifyRoute,
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
|
|
4992
|
-
|
|
4993
|
-
|
|
4994
|
-
|
|
5257
|
+
trustingAsset,
|
|
5258
|
+
onTrustAsset: (asset2) => void handleTrustAsset(asset2),
|
|
5259
|
+
walletBusy,
|
|
5260
|
+
custodyChoice,
|
|
5261
|
+
onWalletStep: (walletStep, index, custody) => void handleWalletStep(walletStep, index, custody),
|
|
5262
|
+
noChains: Array.isArray(appChains) && appChains.length === 0,
|
|
5263
|
+
onFieldChange: (key, value) => setFieldValues((current) => ({ ...current, [key]: value })),
|
|
5264
|
+
onContactContinue: () => {
|
|
5265
|
+
if (selected) void startOrder(selected);
|
|
5266
|
+
},
|
|
5267
|
+
onSign: () => void handleSign(),
|
|
5268
|
+
onApprove: openCosignModal,
|
|
5269
|
+
retrying,
|
|
5270
|
+
onRetryOrder: () => void handleRetryOrder(),
|
|
5271
|
+
onSetUpRecovery: openRecoveryModal,
|
|
5272
|
+
recoveryMissing: recovery === null ? null : recoveryLocked,
|
|
5273
|
+
pollTrouble,
|
|
5274
|
+
checkingPayment: paymentCheckUntil !== null,
|
|
5275
|
+
onCheckPayment: () => void handleCheckPayment(),
|
|
5276
|
+
onResumeOrder: (id) => void handleResumeOrder(id),
|
|
5277
|
+
onNewOrder: handleNewOrder,
|
|
5278
|
+
onBack: handleBack,
|
|
5279
|
+
onStepSelect: handleStepSelect,
|
|
5280
|
+
onRetry: () => {
|
|
5281
|
+
setErrorMsg(null);
|
|
5282
|
+
setStep("input");
|
|
5283
|
+
},
|
|
5284
|
+
onRefresh: () => void handleRefresh(),
|
|
4995
5285
|
onClose
|
|
4996
5286
|
}
|
|
4997
5287
|
) });
|
|
@@ -5091,6 +5381,8 @@ function ReceiveModalTemplate({
|
|
|
5091
5381
|
onSelectChain,
|
|
5092
5382
|
copied,
|
|
5093
5383
|
notReadyReason,
|
|
5384
|
+
recoveryLocked,
|
|
5385
|
+
onSetupRecovery,
|
|
5094
5386
|
onCopy,
|
|
5095
5387
|
onClose
|
|
5096
5388
|
}) {
|
|
@@ -5109,7 +5401,10 @@ function ReceiveModalTemplate({
|
|
|
5109
5401
|
/* @__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" }) }) }) })
|
|
5110
5402
|
] }),
|
|
5111
5403
|
chains && onSelectChain && /* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain }),
|
|
5112
|
-
|
|
5404
|
+
recoveryLocked ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-receive-locked", role: "alert", children: [
|
|
5405
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "Set up a way to recover this wallet before receiving funds. Without one, losing this device means losing whatever you receive, and nobody can get it back." }),
|
|
5406
|
+
onSetupRecovery && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-receive-copy-btn", onClick: onSetupRecovery, children: "Set up recovery" })
|
|
5407
|
+
] }) : walletAddress ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5113
5408
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-receive-qr", children: [
|
|
5114
5409
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-receive-network-badge", children: [
|
|
5115
5410
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-receive-network-dot", "aria-hidden": true }),
|
|
@@ -5183,7 +5478,7 @@ function ReceiveModalTemplate({
|
|
|
5183
5478
|
);
|
|
5184
5479
|
}
|
|
5185
5480
|
function ReceiveModal({ onClose }) {
|
|
5186
|
-
const { wallet, wallets, styles } = usePollar();
|
|
5481
|
+
const { wallet, wallets, styles, recoveryLocked, openRecoveryModal } = usePollar();
|
|
5187
5482
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
5188
5483
|
const [copied, setCopied] = react.useState(false);
|
|
5189
5484
|
const copyTimerRef = react.useRef(null);
|
|
@@ -5225,6 +5520,11 @@ function ReceiveModal({ onClose }) {
|
|
|
5225
5520
|
setSelectedChain(chain);
|
|
5226
5521
|
},
|
|
5227
5522
|
notReadyReason,
|
|
5523
|
+
recoveryLocked,
|
|
5524
|
+
onSetupRecovery: () => {
|
|
5525
|
+
onClose();
|
|
5526
|
+
openRecoveryModal();
|
|
5527
|
+
},
|
|
5228
5528
|
copied,
|
|
5229
5529
|
onCopy: handleCopy,
|
|
5230
5530
|
onClose
|
|
@@ -5440,7 +5740,7 @@ function formatBalance(balance) {
|
|
|
5440
5740
|
const n = parseFloat(balance);
|
|
5441
5741
|
return isNaN(n) ? balance : n.toLocaleString(void 0, { maximumFractionDigits: 7 });
|
|
5442
5742
|
}
|
|
5443
|
-
function
|
|
5743
|
+
function assetKey4(record) {
|
|
5444
5744
|
return `${record.code}:${record.issuer ?? "native"}`;
|
|
5445
5745
|
}
|
|
5446
5746
|
function chainLabel(chain) {
|
|
@@ -5511,8 +5811,8 @@ function SendAssetSelector({ assets, selectedAsset, loading, onSelectAsset }) {
|
|
|
5511
5811
|
}
|
|
5512
5812
|
),
|
|
5513
5813
|
open && assets.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-send-asset-menu", role: "listbox", "aria-label": "Assets", children: assets.map((asset) => {
|
|
5514
|
-
const key =
|
|
5515
|
-
const selected = selectedAsset ? key ===
|
|
5814
|
+
const key = assetKey4(asset);
|
|
5815
|
+
const selected = selectedAsset ? key === assetKey4(selectedAsset) : false;
|
|
5516
5816
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5517
5817
|
"button",
|
|
5518
5818
|
{
|
|
@@ -5556,6 +5856,9 @@ function SendModalTemplate({
|
|
|
5556
5856
|
destination,
|
|
5557
5857
|
formError,
|
|
5558
5858
|
isLoadingBalance,
|
|
5859
|
+
isCheckingDestination = false,
|
|
5860
|
+
minStartingBalance = 1,
|
|
5861
|
+
onCreateAccount,
|
|
5559
5862
|
transaction,
|
|
5560
5863
|
showXdr,
|
|
5561
5864
|
copied,
|
|
@@ -5585,8 +5888,10 @@ function SendModalTemplate({
|
|
|
5585
5888
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
5586
5889
|
const parsedAmount = amount ? Number(amount) : 0;
|
|
5587
5890
|
const availableAmount = selectedAsset?.available === null || selectedAsset?.available === void 0 ? 0 : Number(selectedAsset.available);
|
|
5588
|
-
const canSubmit = canSendOnChain && !notReadyReason && !!selectedAsset && Number.isFinite(parsedAmount) && parsedAmount > 0 && parsedAmount <= availableAmount && !!destination.trim() && !isLoadingBalance;
|
|
5589
|
-
const title = step === "form" ? "Send" : txTitle;
|
|
5891
|
+
const canSubmit = canSendOnChain && !notReadyReason && !!selectedAsset && Number.isFinite(parsedAmount) && parsedAmount > 0 && parsedAmount <= availableAmount && !!destination.trim() && !isLoadingBalance && !isCheckingDestination;
|
|
5892
|
+
const title = step === "form" ? "Send" : step === "create-account" ? "Create account?" : txTitle;
|
|
5893
|
+
const createsWithNative = selectedAsset?.type === "native";
|
|
5894
|
+
const meetsMinimum = Number.isFinite(parsedAmount) && parsedAmount >= minStartingBalance;
|
|
5590
5895
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5591
5896
|
"div",
|
|
5592
5897
|
{
|
|
@@ -5636,51 +5941,25 @@ function SendModalTemplate({
|
|
|
5636
5941
|
onSelectAsset
|
|
5637
5942
|
}
|
|
5638
5943
|
),
|
|
5944
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5945
|
+
AmountField,
|
|
5946
|
+
{
|
|
5947
|
+
id: "pollar-send-amount",
|
|
5948
|
+
label: "Amount",
|
|
5949
|
+
value: amount,
|
|
5950
|
+
onChange: onAmountChange,
|
|
5951
|
+
unit: selectedAsset?.code,
|
|
5952
|
+
available: selectedAsset ? selectedAsset.available : void 0,
|
|
5953
|
+
onMax
|
|
5954
|
+
}
|
|
5955
|
+
),
|
|
5639
5956
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
5640
|
-
/* @__PURE__ */ jsxRuntime.
|
|
5641
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "Amount" }),
|
|
5642
|
-
selectedAsset && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-send-hint", children: [
|
|
5643
|
-
"Available: ",
|
|
5644
|
-
formatBalance(selectedAsset.available),
|
|
5645
|
-
" ",
|
|
5646
|
-
selectedAsset.code
|
|
5647
|
-
] })
|
|
5648
|
-
] }),
|
|
5957
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "Destination wallet" }),
|
|
5649
5958
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-input-shell", children: [
|
|
5650
5959
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5651
5960
|
"input",
|
|
5652
5961
|
{
|
|
5653
|
-
className: "pollar-input pollar-send-
|
|
5654
|
-
type: "text",
|
|
5655
|
-
inputMode: "decimal",
|
|
5656
|
-
placeholder: "0.00",
|
|
5657
|
-
value: amount,
|
|
5658
|
-
onChange: (e) => onAmountChange(e.target.value),
|
|
5659
|
-
"aria-label": "Amount"
|
|
5660
|
-
}
|
|
5661
|
-
),
|
|
5662
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-input-suffix", children: [
|
|
5663
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5664
|
-
"button",
|
|
5665
|
-
{
|
|
5666
|
-
type: "button",
|
|
5667
|
-
className: "pollar-send-inline-action",
|
|
5668
|
-
onClick: onMax,
|
|
5669
|
-
disabled: !selectedAsset?.available,
|
|
5670
|
-
children: "Max"
|
|
5671
|
-
}
|
|
5672
|
-
),
|
|
5673
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: selectedAsset?.code ?? "" })
|
|
5674
|
-
] })
|
|
5675
|
-
] })
|
|
5676
|
-
] }),
|
|
5677
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
5678
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-send-label", children: "Destination wallet" }),
|
|
5679
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-input-shell", children: [
|
|
5680
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5681
|
-
"input",
|
|
5682
|
-
{
|
|
5683
|
-
className: "pollar-input pollar-send-destination-input",
|
|
5962
|
+
className: "pollar-input pollar-send-destination-input",
|
|
5684
5963
|
type: "text",
|
|
5685
5964
|
placeholder: destinationPlaceholder(selectedChain),
|
|
5686
5965
|
value: destination,
|
|
@@ -5725,7 +6004,41 @@ function SendModalTemplate({
|
|
|
5725
6004
|
] })
|
|
5726
6005
|
] }),
|
|
5727
6006
|
formError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: formError }),
|
|
5728
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-primary", onClick: onSubmit, disabled: !canSubmit, children: "Continue" }) })
|
|
6007
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-primary", onClick: onSubmit, disabled: !canSubmit, children: isCheckingDestination ? "Checking destination\u2026" : "Continue" }) })
|
|
6008
|
+
] }),
|
|
6009
|
+
step === "create-account" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
6010
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-notice", children: [
|
|
6011
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-send-notice-title", children: "This account doesn't exist yet" }),
|
|
6012
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-send-notice-address", children: destination.trim() }),
|
|
6013
|
+
createsWithNative ? /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
6014
|
+
"A Stellar account has to be created and funded before it can receive payments. Instead of a payment, this will",
|
|
6015
|
+
" ",
|
|
6016
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: "create the account" }),
|
|
6017
|
+
" with ",
|
|
6018
|
+
amount,
|
|
6019
|
+
" XLM as its starting balance."
|
|
6020
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
6021
|
+
"It can't receive ",
|
|
6022
|
+
selectedAsset?.code ?? "this asset",
|
|
6023
|
+
" yet: it has to be created and funded with XLM first, and then add a trustline for ",
|
|
6024
|
+
selectedAsset?.code ?? "the asset",
|
|
6025
|
+
"."
|
|
6026
|
+
] }),
|
|
6027
|
+
createsWithNative && !meetsMinimum && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-send-notice-warning", children: [
|
|
6028
|
+
"A new account needs a starting balance of at least ",
|
|
6029
|
+
minStartingBalance,
|
|
6030
|
+
" XLM. Go back and raise the amount to create it."
|
|
6031
|
+
] }),
|
|
6032
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "Or wait until another wallet funds it, and send afterwards." })
|
|
6033
|
+
] }),
|
|
6034
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-account-actions", children: [
|
|
6035
|
+
createsWithNative && onCreateAccount && /* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-btn-primary", onClick: onCreateAccount, disabled: !meetsMinimum, children: [
|
|
6036
|
+
"Create account with ",
|
|
6037
|
+
amount,
|
|
6038
|
+
" XLM"
|
|
6039
|
+
] }),
|
|
6040
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-secondary", onClick: onBack, children: "I'll wait until it's funded" })
|
|
6041
|
+
] })
|
|
5729
6042
|
] }),
|
|
5730
6043
|
step === "tx" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5731
6044
|
TxStatusView,
|
|
@@ -5748,6 +6061,11 @@ function SendModalTemplate({
|
|
|
5748
6061
|
);
|
|
5749
6062
|
}
|
|
5750
6063
|
var MAX_MEMO_ID = 18446744073709551615n;
|
|
6064
|
+
var SOLANA_FEE_MARGIN_LAMPORTS = 10000n;
|
|
6065
|
+
function solanaMaxAfterFee(available) {
|
|
6066
|
+
const lamports = BigInt(core.toBaseUnits(available, 9)) - SOLANA_FEE_MARGIN_LAMPORTS;
|
|
6067
|
+
return core.fromBaseUnits((lamports > 0n ? lamports : 0n).toString(), 9);
|
|
6068
|
+
}
|
|
5751
6069
|
function parseMemo(type, raw) {
|
|
5752
6070
|
const value = type === "id" ? raw.trim() : raw;
|
|
5753
6071
|
if (value.trim() === "") return void 0;
|
|
@@ -5757,6 +6075,7 @@ function parseMemo(type, raw) {
|
|
|
5757
6075
|
if (!/^\d+$/.test(value) || BigInt(value) > MAX_MEMO_ID) return "The memo ID must be a whole number up to 2^64 - 1.";
|
|
5758
6076
|
return { type, value };
|
|
5759
6077
|
}
|
|
6078
|
+
var MIN_STARTING_BALANCE_XLM = 1;
|
|
5760
6079
|
function assetParam(record) {
|
|
5761
6080
|
if (record.type === "native") return { type: "native" };
|
|
5762
6081
|
if (record.type === "credit_alphanum4") {
|
|
@@ -5774,11 +6093,14 @@ function SendModal({ onClose }) {
|
|
|
5774
6093
|
tx: transaction,
|
|
5775
6094
|
wallet,
|
|
5776
6095
|
network,
|
|
5777
|
-
styles
|
|
6096
|
+
styles,
|
|
6097
|
+
getClient
|
|
5778
6098
|
} = usePollar();
|
|
5779
6099
|
const walletType = wallet?.custody === "external" ? wallet.provider : null;
|
|
5780
6100
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
5781
6101
|
const [step, setStep] = react.useState("form");
|
|
6102
|
+
const [createsAccount, setCreatesAccount] = react.useState(false);
|
|
6103
|
+
const [checkingDestination, setCheckingDestination] = react.useState(false);
|
|
5782
6104
|
const [amount, setAmount] = react.useState("");
|
|
5783
6105
|
const [destination, setDestination] = react.useState("");
|
|
5784
6106
|
const [memo, setMemo] = react.useState("");
|
|
@@ -5834,8 +6156,15 @@ function SendModal({ onClose }) {
|
|
|
5834
6156
|
"building-signing-submitting"
|
|
5835
6157
|
];
|
|
5836
6158
|
const isInProgress = IN_FLIGHT_STEPS3.includes(transaction.step);
|
|
5837
|
-
const showBack = step === "tx" && (transaction.step === "error" || transaction.step === "success") && !isInProgress;
|
|
5838
|
-
const txTitle = isInProgress ? "Sending\u2026" : transaction.step === "success" ? "Sent!" : transaction.step === "error" ? "Send failed" : "Confirm Send";
|
|
6159
|
+
const showBack = step === "create-account" || step === "tx" && (transaction.step === "error" || transaction.step === "success") && !isInProgress;
|
|
6160
|
+
const txTitle = createsAccount ? isInProgress ? "Creating account\u2026" : transaction.step === "success" ? "Account created!" : transaction.step === "error" ? "Create account failed" : "Confirm Create Account" : isInProgress ? "Sending\u2026" : transaction.step === "success" ? "Sent!" : transaction.step === "error" ? "Send failed" : "Confirm Send";
|
|
6161
|
+
async function stellarAccountExists(address) {
|
|
6162
|
+
try {
|
|
6163
|
+
return (await getClient().getWalletBalance(address)).exists;
|
|
6164
|
+
} catch {
|
|
6165
|
+
return null;
|
|
6166
|
+
}
|
|
6167
|
+
}
|
|
5839
6168
|
async function handleSubmit() {
|
|
5840
6169
|
setFormError("");
|
|
5841
6170
|
if (!canSendOnChain) {
|
|
@@ -5882,6 +6211,16 @@ function SendModal({ onClose }) {
|
|
|
5882
6211
|
return;
|
|
5883
6212
|
}
|
|
5884
6213
|
}
|
|
6214
|
+
if (selectedChain === "STELLAR") {
|
|
6215
|
+
setCheckingDestination(true);
|
|
6216
|
+
const exists = await stellarAccountExists(destination.trim());
|
|
6217
|
+
setCheckingDestination(false);
|
|
6218
|
+
if (exists === false) {
|
|
6219
|
+
setStep("create-account");
|
|
6220
|
+
return;
|
|
6221
|
+
}
|
|
6222
|
+
}
|
|
6223
|
+
setCreatesAccount(false);
|
|
5885
6224
|
setStep("tx");
|
|
5886
6225
|
if (selectedChain === "SOLANA" || selectedChain === "POLYGON") {
|
|
5887
6226
|
await sendPayment({
|
|
@@ -5900,6 +6239,17 @@ function SendModal({ onClose }) {
|
|
|
5900
6239
|
parsedMemo ? { memo: parsedMemo } : void 0
|
|
5901
6240
|
);
|
|
5902
6241
|
}
|
|
6242
|
+
async function handleCreateAccount() {
|
|
6243
|
+
const parsedMemo = parseMemo(memoType, memo);
|
|
6244
|
+
if (typeof parsedMemo === "string" || parseFloat(amount) < MIN_STARTING_BALANCE_XLM) return;
|
|
6245
|
+
setCreatesAccount(true);
|
|
6246
|
+
setStep("tx");
|
|
6247
|
+
await buildTx(
|
|
6248
|
+
"create_account",
|
|
6249
|
+
{ destination: destination.trim(), startingBalance: amount },
|
|
6250
|
+
parsedMemo ? { memo: parsedMemo } : void 0
|
|
6251
|
+
);
|
|
6252
|
+
}
|
|
5903
6253
|
function handleSignAndSend() {
|
|
5904
6254
|
if (transaction.step === "built") {
|
|
5905
6255
|
void signAndSubmitTx(transaction.buildData.unsignedXdr);
|
|
@@ -5907,7 +6257,15 @@ function SendModal({ onClose }) {
|
|
|
5907
6257
|
}
|
|
5908
6258
|
function handleMax() {
|
|
5909
6259
|
if (selectedAsset?.available !== null && selectedAsset?.available !== void 0) {
|
|
5910
|
-
|
|
6260
|
+
const paysOwnSolFee = selectedChain === "SOLANA" && selectedAsset.type === "native" && selectedAsset.sponsored !== true;
|
|
6261
|
+
let max = selectedAsset.available;
|
|
6262
|
+
if (paysOwnSolFee) {
|
|
6263
|
+
try {
|
|
6264
|
+
max = solanaMaxAfterFee(selectedAsset.available);
|
|
6265
|
+
} catch {
|
|
6266
|
+
}
|
|
6267
|
+
}
|
|
6268
|
+
setAmount(max);
|
|
5911
6269
|
setFormError("");
|
|
5912
6270
|
}
|
|
5913
6271
|
}
|
|
@@ -5946,6 +6304,7 @@ function SendModal({ onClose }) {
|
|
|
5946
6304
|
}
|
|
5947
6305
|
function handleBack() {
|
|
5948
6306
|
setStep("form");
|
|
6307
|
+
setCreatesAccount(false);
|
|
5949
6308
|
setShowXdr(false);
|
|
5950
6309
|
setCopied(false);
|
|
5951
6310
|
}
|
|
@@ -5968,6 +6327,9 @@ function SendModal({ onClose }) {
|
|
|
5968
6327
|
destination,
|
|
5969
6328
|
formError,
|
|
5970
6329
|
isLoadingBalance: walletBalance.step === "loading",
|
|
6330
|
+
isCheckingDestination: checkingDestination,
|
|
6331
|
+
minStartingBalance: MIN_STARTING_BALANCE_XLM,
|
|
6332
|
+
onCreateAccount: () => void handleCreateAccount(),
|
|
5971
6333
|
transaction,
|
|
5972
6334
|
showXdr,
|
|
5973
6335
|
copied,
|
|
@@ -6255,7 +6617,7 @@ function SwapModalTemplate({
|
|
|
6255
6617
|
] })
|
|
6256
6618
|
] }),
|
|
6257
6619
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-panel-main", children: [
|
|
6258
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `pollar-swap-output${quoteLoading ? " is-loading" : ""}`, "aria-live": "polite", children: quoteLoading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }) : formatAmount2(quote
|
|
6620
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: `pollar-swap-output${quoteLoading ? " is-loading" : ""}`, "aria-live": "polite", children: quoteLoading ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }) : quote ? `~${formatAmount2(quote.amountOut)}` : "\u2014" }),
|
|
6259
6621
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-panel-selector", children: [
|
|
6260
6622
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6261
6623
|
AssetPill,
|
|
@@ -6719,7 +7081,6 @@ function EarnModal({ onClose }) {
|
|
|
6719
7081
|
earnWithdraw,
|
|
6720
7082
|
tx: transaction,
|
|
6721
7083
|
wallet,
|
|
6722
|
-
walletBalance,
|
|
6723
7084
|
refreshWalletBalance,
|
|
6724
7085
|
enabledAssets,
|
|
6725
7086
|
refreshAssets,
|
|
@@ -6801,13 +7162,9 @@ function EarnModal({ onClose }) {
|
|
|
6801
7162
|
const withdrawUnit = position?.withdrawUnit ?? "asset";
|
|
6802
7163
|
const assetCode = selectedOpportunity?.asset.code ?? "";
|
|
6803
7164
|
const amountUnitLabel = tab === "deposit" ? assetCode : withdrawUnit === "shares" ? "shares" : assetCode;
|
|
6804
|
-
const walletAvailable = (
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
const issuer = selectedOpportunity.asset.issuer;
|
|
6808
|
-
const rec = balances.find((b) => issuer === null ? b.type === "native" : b.code === assetCode && b.issuer === issuer);
|
|
6809
|
-
return rec ? rec.available : null;
|
|
6810
|
-
})();
|
|
7165
|
+
const walletAvailable = useWalletAvailable(
|
|
7166
|
+
selectedOpportunity ? { chain: "STELLAR", code: assetCode, issuer: selectedOpportunity.asset.issuer } : null
|
|
7167
|
+
);
|
|
6811
7168
|
const depositAssetRecord = (() => {
|
|
6812
7169
|
if (!selectedOpportunity?.asset.issuer || enabledAssets.step !== "loaded") return void 0;
|
|
6813
7170
|
return enabledAssets.data.assets.find(
|
|
@@ -7041,37 +7398,17 @@ function EarnModal({ onClose }) {
|
|
|
7041
7398
|
] })
|
|
7042
7399
|
] })
|
|
7043
7400
|
] }),
|
|
7044
|
-
/* @__PURE__ */ jsxRuntime.
|
|
7045
|
-
|
|
7046
|
-
|
|
7047
|
-
|
|
7048
|
-
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
formatAmount3(position.withdrawable),
|
|
7056
|
-
" ",
|
|
7057
|
-
amountUnitLabel
|
|
7058
|
-
] })
|
|
7059
|
-
] }),
|
|
7060
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-earn-amount", children: [
|
|
7061
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7062
|
-
"input",
|
|
7063
|
-
{
|
|
7064
|
-
className: "pollar-input",
|
|
7065
|
-
type: "text",
|
|
7066
|
-
inputMode: "decimal",
|
|
7067
|
-
placeholder: "0.00",
|
|
7068
|
-
value: amount,
|
|
7069
|
-
onChange: (e) => setAmount(e.target.value)
|
|
7070
|
-
}
|
|
7071
|
-
),
|
|
7072
|
-
amountUnitLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-earn-amount-unit", children: amountUnitLabel })
|
|
7073
|
-
] })
|
|
7074
|
-
] }),
|
|
7401
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
7402
|
+
AmountField,
|
|
7403
|
+
{
|
|
7404
|
+
id: "pollar-earn-amount",
|
|
7405
|
+
label: tab === "deposit" ? "Amount" : "Withdraw amount",
|
|
7406
|
+
value: amount,
|
|
7407
|
+
onChange: setAmount,
|
|
7408
|
+
unit: amountUnitLabel,
|
|
7409
|
+
available: tab === "deposit" ? walletAvailable : position ? position.withdrawable : void 0
|
|
7410
|
+
}
|
|
7411
|
+
),
|
|
7075
7412
|
formError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: formError }),
|
|
7076
7413
|
depositNeedsTrustline && selectedOpportunity && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-swap-trustline-notice", children: [
|
|
7077
7414
|
"To deposit ",
|
|
@@ -7103,13 +7440,16 @@ function EarnModal({ onClose }) {
|
|
|
7103
7440
|
}
|
|
7104
7441
|
|
|
7105
7442
|
// src/components/card-modal/card-kyc.ts
|
|
7106
|
-
var
|
|
7443
|
+
var nonEmpty = (value) => typeof value === "string" && !!value.trim();
|
|
7107
7444
|
function requiredCardStep(error) {
|
|
7108
7445
|
if (!error || typeof error !== "object") return null;
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7446
|
+
if (!("code" in error) || error.code !== "SDK_CARDS_REQUIREMENT_REQUIRED") return null;
|
|
7447
|
+
const body = "body" in error ? error.body : void 0;
|
|
7448
|
+
if (typeof body !== "object" || body === null) return null;
|
|
7449
|
+
const cardProviderId = "cardProviderId" in body ? body.cardProviderId : void 0;
|
|
7450
|
+
const requirementType = "requirementType" in body ? body.requirementType : void 0;
|
|
7451
|
+
const optionId = "optionId" in body ? body.optionId : void 0;
|
|
7452
|
+
if (!nonEmpty(cardProviderId) || !nonEmpty(optionId)) return null;
|
|
7113
7453
|
if (requirementType === "KYC" || requirementType === "FORM" || requirementType === "REGISTRY_CHECK" || requirementType === "PROVIDER_REGISTRATION") {
|
|
7114
7454
|
return { cardProviderId, type: requirementType, optionId };
|
|
7115
7455
|
}
|
|
@@ -7264,6 +7604,8 @@ function CardModal({ onClose }) {
|
|
|
7264
7604
|
const [error, setError] = react.useState("");
|
|
7265
7605
|
const revealTimer = react.useRef(null);
|
|
7266
7606
|
const provider = providers?.[0] ?? null;
|
|
7607
|
+
const fundingAsset = provider?.fundingAssets[0] ?? "USDC";
|
|
7608
|
+
const fundAvailable = useWalletAvailable(panel === "fund" ? { chain: "STELLAR", code: fundingAsset } : null);
|
|
7267
7609
|
const card = cards?.[0] ?? null;
|
|
7268
7610
|
const loadHolder = react.useCallback(async () => {
|
|
7269
7611
|
const h = await getClient().getCardHolder();
|
|
@@ -7762,15 +8104,17 @@ function CardModal({ onClose }) {
|
|
|
7762
8104
|
transactions === null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-note", children: "Loading..." }),
|
|
7763
8105
|
transactions?.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-note", children: "No movements yet." }),
|
|
7764
8106
|
transactions?.map((tx) => {
|
|
7765
|
-
const
|
|
7766
|
-
const
|
|
8107
|
+
const localAmount = typeof tx.purchase?.localAmount === "number" ? tx.purchase.localAmount : null;
|
|
8108
|
+
const localCurrency = typeof tx.purchase?.localCurrency === "string" ? tx.purchase.localCurrency : null;
|
|
8109
|
+
const purchaseStatus = typeof tx.purchase?.status === "string" ? tx.purchase.status : null;
|
|
8110
|
+
const local = localAmount && localCurrency && localCurrency !== "USD" ? money(String(localAmount), localCurrency) : null;
|
|
7767
8111
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-tx", children: [
|
|
7768
8112
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7769
8113
|
tx.merchantName ?? TX_LABELS[tx.type] ?? tx.type,
|
|
7770
8114
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-card-tx-meta", children: [
|
|
7771
8115
|
new Date(tx.occurredAt).toLocaleDateString(),
|
|
7772
8116
|
tx.merchantName ? ` \xB7 ${TX_LABELS[tx.type] ?? tx.type}` : "",
|
|
7773
|
-
|
|
8117
|
+
purchaseStatus && purchaseStatus !== "completed" ? ` \xB7 ${purchaseStatus}` : ""
|
|
7774
8118
|
] })
|
|
7775
8119
|
] }),
|
|
7776
8120
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-tx-amount", "data-direction": tx.direction ?? void 0, children: [
|
|
@@ -7787,19 +8131,18 @@ function CardModal({ onClose }) {
|
|
|
7787
8131
|
provider.fundingAssets.join(" or ") || "USDC",
|
|
7788
8132
|
" from your wallet to your card. It takes a few minutes to cross to the card network."
|
|
7789
8133
|
] }),
|
|
7790
|
-
/* @__PURE__ */ jsxRuntime.
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
"
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
] }),
|
|
8134
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8135
|
+
AmountField,
|
|
8136
|
+
{
|
|
8137
|
+
id: "pollar-card-fund-amount",
|
|
8138
|
+
label: "Amount",
|
|
8139
|
+
value: fundAmount,
|
|
8140
|
+
onChange: (value) => setFundAmount(value.replace(/[^0-9.]/g, "")),
|
|
8141
|
+
unit: fundingAsset,
|
|
8142
|
+
available: fundAvailable,
|
|
8143
|
+
placeholder: "10"
|
|
8144
|
+
}
|
|
8145
|
+
),
|
|
7803
8146
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
7804
8147
|
"button",
|
|
7805
8148
|
{
|
|
@@ -8169,7 +8512,8 @@ function useCosign() {
|
|
|
8169
8512
|
revokeDevice: react.useCallback(
|
|
8170
8513
|
(deviceId, options) => getClient().cosign.revokeDevice(deviceId, options),
|
|
8171
8514
|
[getClient]
|
|
8172
|
-
)
|
|
8515
|
+
),
|
|
8516
|
+
switchCustody: react.useCallback((to) => getClient().cosign.switchCustody(to), [getClient])
|
|
8173
8517
|
};
|
|
8174
8518
|
}
|
|
8175
8519
|
var OPERATION_LABELS = {
|
|
@@ -8191,6 +8535,15 @@ function expiresIn(request) {
|
|
|
8191
8535
|
const m = Math.floor(ms % 36e5 / 6e4);
|
|
8192
8536
|
return h > 0 ? `${h}h ${m}m` : `${m}m`;
|
|
8193
8537
|
}
|
|
8538
|
+
function readableAmount(details) {
|
|
8539
|
+
const { amount, decimals, symbol } = details;
|
|
8540
|
+
if (typeof amount !== "string" || typeof decimals !== "number" || typeof symbol !== "string") return null;
|
|
8541
|
+
try {
|
|
8542
|
+
return { amount: core.fromBaseUnits(amount, decimals), symbol };
|
|
8543
|
+
} catch {
|
|
8544
|
+
return null;
|
|
8545
|
+
}
|
|
8546
|
+
}
|
|
8194
8547
|
function detailRows(request) {
|
|
8195
8548
|
const details = request.details ?? {};
|
|
8196
8549
|
const rows = [];
|
|
@@ -8202,14 +8555,21 @@ function detailRows(request) {
|
|
|
8202
8555
|
]);
|
|
8203
8556
|
};
|
|
8204
8557
|
push("Destination", details.destination);
|
|
8205
|
-
|
|
8206
|
-
push("
|
|
8558
|
+
const readable = readableAmount(details);
|
|
8559
|
+
push("Amount", readable ? `${readable.amount} ${readable.symbol}` : details.amount);
|
|
8560
|
+
push("Asset", details.asset ?? details.assetCode ?? readable?.symbol);
|
|
8207
8561
|
push("Network", request.network);
|
|
8208
8562
|
return rows;
|
|
8209
8563
|
}
|
|
8210
8564
|
function CloseIcon2() {
|
|
8211
8565
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m3 3 8 8M11 3l-8 8", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
|
|
8212
8566
|
}
|
|
8567
|
+
function VerifiedIcon() {
|
|
8568
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
|
|
8569
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
|
|
8570
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3.5 7l2.5 2.5 4.5-5", stroke: "white", strokeWidth: "1.4", strokeLinecap: "round", strokeLinejoin: "round" })
|
|
8571
|
+
] });
|
|
8572
|
+
}
|
|
8213
8573
|
function CosignModalTemplate({
|
|
8214
8574
|
theme,
|
|
8215
8575
|
accentColor,
|
|
@@ -8222,6 +8582,8 @@ function CosignModalTemplate({
|
|
|
8222
8582
|
approveBlocked = false,
|
|
8223
8583
|
lastResolved,
|
|
8224
8584
|
explorerUrl,
|
|
8585
|
+
closesIn = null,
|
|
8586
|
+
nextStep = null,
|
|
8225
8587
|
onSelect,
|
|
8226
8588
|
onApprove,
|
|
8227
8589
|
onReject,
|
|
@@ -8230,6 +8592,8 @@ function CosignModalTemplate({
|
|
|
8230
8592
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
8231
8593
|
const verified = verification?.ok === true;
|
|
8232
8594
|
const canVote = !!current && verified && !busy && !approveBlocked;
|
|
8595
|
+
const [verifiedOpenFor, setVerifiedOpenFor] = react.useState(null);
|
|
8596
|
+
const verifiedOpen = !!current && verifiedOpenFor === current.id;
|
|
8233
8597
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8234
8598
|
"div",
|
|
8235
8599
|
{
|
|
@@ -8242,27 +8606,48 @@ function CosignModalTemplate({
|
|
|
8242
8606
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Confirm with your device" }),
|
|
8243
8607
|
/* @__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", title: "Close", children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon2, {}) }) })
|
|
8244
8608
|
] }),
|
|
8245
|
-
pending.length === 0 && /* @__PURE__ */ jsxRuntime.
|
|
8246
|
-
lastResolved
|
|
8247
|
-
/* @__PURE__ */ jsxRuntime.
|
|
8248
|
-
|
|
8249
|
-
|
|
8250
|
-
|
|
8251
|
-
|
|
8252
|
-
|
|
8253
|
-
|
|
8254
|
-
|
|
8255
|
-
|
|
8256
|
-
|
|
8257
|
-
|
|
8609
|
+
pending.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-empty", children: [
|
|
8610
|
+
lastResolved ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8611
|
+
lastResolved.status === "APPROVED" && /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "pollar-cosign-approved-icon", width: "44", height: "44", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
|
|
8612
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
|
|
8613
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8614
|
+
"path",
|
|
8615
|
+
{
|
|
8616
|
+
d: "M3.5 7l2.5 2.5 4.5-5",
|
|
8617
|
+
stroke: "white",
|
|
8618
|
+
strokeWidth: "1.2",
|
|
8619
|
+
strokeLinecap: "round",
|
|
8620
|
+
strokeLinejoin: "round"
|
|
8621
|
+
}
|
|
8622
|
+
)
|
|
8623
|
+
] }),
|
|
8624
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-empty-title", children: lastResolved.status === "APPROVED" ? "Approved" : lastResolved.status === "REJECTED" ? "Rejected" : lastResolved.status.toLowerCase() }),
|
|
8625
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: lastResolved.submit?.hash ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8626
|
+
"Sent. Transaction",
|
|
8627
|
+
" ",
|
|
8628
|
+
explorerUrl ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "pollar-cosign-tx-link", href: explorerUrl, target: "_blank", rel: "noopener noreferrer", children: cropAddress(lastResolved.submit.hash) }) : cropAddress(lastResolved.submit.hash),
|
|
8629
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8630
|
+
CopyButton,
|
|
8631
|
+
{
|
|
8632
|
+
value: lastResolved.submit.hash,
|
|
8633
|
+
label: "Copy transaction hash",
|
|
8634
|
+
className: "pollar-copy-btn-sm pollar-cosign-copy"
|
|
8635
|
+
}
|
|
8636
|
+
)
|
|
8637
|
+
] }) : lastResolved.signedXdr ? "Signed. The app will send it." : "Nothing was signed." })
|
|
8638
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: "Nothing waits for your approval." }),
|
|
8639
|
+
nextStep && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-cosign-next", children: [
|
|
8640
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm", "aria-hidden": true }),
|
|
8641
|
+
" Next: ",
|
|
8642
|
+
nextStep,
|
|
8643
|
+
". It appears here in a few seconds."
|
|
8258
8644
|
] }),
|
|
8259
|
-
/* @__PURE__ */ jsxRuntime.
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
"
|
|
8263
|
-
|
|
8264
|
-
|
|
8265
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: "Nothing waits for your approval." }) }),
|
|
8645
|
+
closesIn !== null && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-cosign-muted pollar-cosign-closing", children: [
|
|
8646
|
+
"Closing in ",
|
|
8647
|
+
closesIn,
|
|
8648
|
+
"s"
|
|
8649
|
+
] })
|
|
8650
|
+
] }),
|
|
8266
8651
|
pending.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "pollar-cosign-list", children: pending.map((r) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8267
8652
|
"button",
|
|
8268
8653
|
{
|
|
@@ -8276,9 +8661,27 @@ function CosignModalTemplate({
|
|
|
8276
8661
|
}
|
|
8277
8662
|
) }, r.id)) }),
|
|
8278
8663
|
current && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-detail", children: [
|
|
8279
|
-
/* @__PURE__ */ jsxRuntime.
|
|
8664
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-detail-head", children: [
|
|
8665
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-detail-title", children: labelOf(current) }),
|
|
8666
|
+
!verification && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-cosign-chip", children: [
|
|
8667
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm", "aria-hidden": true }),
|
|
8668
|
+
"Checking..."
|
|
8669
|
+
] }),
|
|
8670
|
+
verification?.ok && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8671
|
+
"button",
|
|
8672
|
+
{
|
|
8673
|
+
type: "button",
|
|
8674
|
+
className: "pollar-cosign-chip pollar-cosign-chip-ok",
|
|
8675
|
+
"aria-expanded": verifiedOpen,
|
|
8676
|
+
onClick: () => setVerifiedOpenFor(verifiedOpen ? null : current.id),
|
|
8677
|
+
children: [
|
|
8678
|
+
/* @__PURE__ */ jsxRuntime.jsx(VerifiedIcon, {}),
|
|
8679
|
+
"Verified"
|
|
8680
|
+
]
|
|
8681
|
+
}
|
|
8682
|
+
)
|
|
8683
|
+
] }),
|
|
8280
8684
|
current.summary && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: current.summary }),
|
|
8281
|
-
/* @__PURE__ */ jsxRuntime.jsx(GroupSteps, { request: current }),
|
|
8282
8685
|
/* @__PURE__ */ jsxRuntime.jsxs("dl", { className: "pollar-cosign-rows", children: [
|
|
8283
8686
|
detailRows(current).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-row", children: [
|
|
8284
8687
|
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: k }),
|
|
@@ -8289,140 +8692,637 @@ function CosignModalTemplate({
|
|
|
8289
8692
|
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: expiresIn(current) })
|
|
8290
8693
|
] })
|
|
8291
8694
|
] }),
|
|
8292
|
-
/* @__PURE__ */ jsxRuntime.
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
!verification && "Checking the transaction against Turnkey...",
|
|
8298
|
-
verification?.ok && "Verified: this is exactly what will be signed.",
|
|
8299
|
-
verification && !verification.ok && `Not verified: ${verification.reason}`
|
|
8300
|
-
]
|
|
8301
|
-
}
|
|
8302
|
-
),
|
|
8695
|
+
verification?.ok && verifiedOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-cosign-verify pollar-cosign-verify-ok", children: "Checked against Turnkey: this is exactly what will be signed." }),
|
|
8696
|
+
verification && !verification.ok && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-verify pollar-cosign-verify-bad", children: [
|
|
8697
|
+
"Not verified: ",
|
|
8698
|
+
verification.reason
|
|
8699
|
+
] }),
|
|
8303
8700
|
error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-cosign-error", children: error }),
|
|
8304
8701
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-actions", children: [
|
|
8305
8702
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8306
|
-
"button",
|
|
8703
|
+
"button",
|
|
8704
|
+
{
|
|
8705
|
+
type: "button",
|
|
8706
|
+
className: "pollar-cosign-btn pollar-cosign-btn-secondary",
|
|
8707
|
+
disabled: !!busy,
|
|
8708
|
+
onClick: () => onReject(current),
|
|
8709
|
+
children: busy === "rejecting" ? "Rejecting..." : "Reject"
|
|
8710
|
+
}
|
|
8711
|
+
),
|
|
8712
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8713
|
+
"button",
|
|
8714
|
+
{
|
|
8715
|
+
type: "button",
|
|
8716
|
+
className: "pollar-cosign-btn pollar-cosign-btn-primary",
|
|
8717
|
+
disabled: !canVote,
|
|
8718
|
+
onClick: () => onApprove(current),
|
|
8719
|
+
children: busy === "approving" ? "Approving..." : "Approve"
|
|
8720
|
+
}
|
|
8721
|
+
)
|
|
8722
|
+
] })
|
|
8723
|
+
] }),
|
|
8724
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
8725
|
+
]
|
|
8726
|
+
}
|
|
8727
|
+
);
|
|
8728
|
+
}
|
|
8729
|
+
var CLOSE_AFTER_SECONDS = 3;
|
|
8730
|
+
var CLOSE_AFTER_SENT_SECONDS = 5;
|
|
8731
|
+
var NEXT_REQUEST_EVERY_MS = 2e3;
|
|
8732
|
+
function CosignModal({ nextStep = null, onClose }) {
|
|
8733
|
+
const { getClient, styles, network } = usePollar();
|
|
8734
|
+
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
8735
|
+
const { pending, lastResolved, loaded, refresh, approve, reject, verify, inspectQuorum } = useCosign();
|
|
8736
|
+
const [selectedId, setSelectedId] = react.useState(null);
|
|
8737
|
+
const [verification, setVerification] = react.useState(null);
|
|
8738
|
+
const [busy, setBusy] = react.useState(null);
|
|
8739
|
+
const [error, setError] = react.useState(null);
|
|
8740
|
+
const [approveFailedFor, setApproveFailedFor] = react.useState(null);
|
|
8741
|
+
const [quorumFailure, setQuorumFailure] = react.useState(null);
|
|
8742
|
+
react.useEffect(() => {
|
|
8743
|
+
let cancelled = false;
|
|
8744
|
+
inspectQuorum().then((q) => {
|
|
8745
|
+
if (!cancelled && !q.ok) setQuorumFailure(q.reason);
|
|
8746
|
+
}).catch(() => void 0);
|
|
8747
|
+
return () => {
|
|
8748
|
+
cancelled = true;
|
|
8749
|
+
};
|
|
8750
|
+
}, [inspectQuorum]);
|
|
8751
|
+
const current = pending.find((r) => r.id === selectedId) ?? pending[0] ?? null;
|
|
8752
|
+
const currentRef = react.useRef(current);
|
|
8753
|
+
currentRef.current = current;
|
|
8754
|
+
const currentId = current?.id ?? null;
|
|
8755
|
+
react.useEffect(() => {
|
|
8756
|
+
const request = currentRef.current;
|
|
8757
|
+
if (!request) return;
|
|
8758
|
+
setVerification(null);
|
|
8759
|
+
setError(null);
|
|
8760
|
+
setApproveFailedFor(null);
|
|
8761
|
+
let cancelled = false;
|
|
8762
|
+
verify(request).then((v) => {
|
|
8763
|
+
if (!cancelled) setVerification(v);
|
|
8764
|
+
}).catch((err) => {
|
|
8765
|
+
if (!cancelled) setVerification({ ok: false, reason: err instanceof Error ? err.message : String(err) });
|
|
8766
|
+
});
|
|
8767
|
+
return () => {
|
|
8768
|
+
cancelled = true;
|
|
8769
|
+
};
|
|
8770
|
+
}, [currentId, verify]);
|
|
8771
|
+
const onCloseRef = react.useRef(onClose);
|
|
8772
|
+
onCloseRef.current = onClose;
|
|
8773
|
+
react.useEffect(() => {
|
|
8774
|
+
return getClient().onAuthStateChange((authState) => {
|
|
8775
|
+
if (authState.step === "idle") onCloseRef.current();
|
|
8776
|
+
});
|
|
8777
|
+
}, [getClient]);
|
|
8778
|
+
const silent = pending.length === 0 && (lastResolved ? lastResolved.status === "APPROVED" && !lastResolved.submit?.hash && !lastResolved.signedXdr : loaded);
|
|
8779
|
+
const sent = pending.length === 0 && lastResolved?.status === "APPROVED" && !!lastResolved.submit?.hash;
|
|
8780
|
+
const awaitingNext = sent && !!nextStep;
|
|
8781
|
+
const closeAfter = awaitingNext ? null : sent ? CLOSE_AFTER_SENT_SECONDS : silent ? CLOSE_AFTER_SECONDS : null;
|
|
8782
|
+
react.useEffect(() => {
|
|
8783
|
+
if (!awaitingNext) return;
|
|
8784
|
+
const timer = setInterval(() => void refresh().catch(() => void 0), NEXT_REQUEST_EVERY_MS);
|
|
8785
|
+
return () => clearInterval(timer);
|
|
8786
|
+
}, [awaitingNext, refresh]);
|
|
8787
|
+
const [closesIn, setClosesIn] = react.useState(null);
|
|
8788
|
+
react.useEffect(() => {
|
|
8789
|
+
if (closeAfter === null) {
|
|
8790
|
+
setClosesIn(null);
|
|
8791
|
+
return;
|
|
8792
|
+
}
|
|
8793
|
+
let left = closeAfter;
|
|
8794
|
+
setClosesIn(left);
|
|
8795
|
+
const timer = setInterval(() => {
|
|
8796
|
+
left -= 1;
|
|
8797
|
+
if (left > 0) setClosesIn(left);
|
|
8798
|
+
else {
|
|
8799
|
+
clearInterval(timer);
|
|
8800
|
+
onCloseRef.current();
|
|
8801
|
+
}
|
|
8802
|
+
}, 1e3);
|
|
8803
|
+
return () => clearInterval(timer);
|
|
8804
|
+
}, [closeAfter, lastResolved?.id]);
|
|
8805
|
+
const run = react.useCallback(
|
|
8806
|
+
async (kind, request, action) => {
|
|
8807
|
+
setBusy(kind);
|
|
8808
|
+
setError(null);
|
|
8809
|
+
try {
|
|
8810
|
+
await action(request);
|
|
8811
|
+
} catch (err) {
|
|
8812
|
+
setError(core.transactionErrorMessage(core.isPollarApiError(err) ? err.code : null, err instanceof Error ? err.message : null));
|
|
8813
|
+
if (kind === "approving") setApproveFailedFor(request.id);
|
|
8814
|
+
} finally {
|
|
8815
|
+
setBusy(null);
|
|
8816
|
+
}
|
|
8817
|
+
},
|
|
8818
|
+
[]
|
|
8819
|
+
);
|
|
8820
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8821
|
+
CosignModalTemplate,
|
|
8822
|
+
{
|
|
8823
|
+
theme,
|
|
8824
|
+
accentColor,
|
|
8825
|
+
styleOverrides,
|
|
8826
|
+
pending,
|
|
8827
|
+
current,
|
|
8828
|
+
verification: current ? quorumFailure ? { ok: false, reason: quorumFailure } : verification : null,
|
|
8829
|
+
busy,
|
|
8830
|
+
error,
|
|
8831
|
+
approveBlocked: !!current && approveFailedFor === current.id,
|
|
8832
|
+
...lastResolved ? { lastResolved } : {},
|
|
8833
|
+
closesIn,
|
|
8834
|
+
nextStep: awaitingNext ? nextStep : null,
|
|
8835
|
+
explorerUrl: lastResolved?.submit?.hash ? explorerTxUrl(lastResolved.network, lastResolved.submit.hash, network) : null,
|
|
8836
|
+
onSelect: (r) => setSelectedId(r.id),
|
|
8837
|
+
onApprove: (r) => void run("approving", r, approve),
|
|
8838
|
+
onReject: (r) => void run("rejecting", r, reject),
|
|
8839
|
+
onClose
|
|
8840
|
+
}
|
|
8841
|
+
) });
|
|
8842
|
+
}
|
|
8843
|
+
var CHAIN_NAME3 = { STELLAR: "Stellar", SOLANA: "Solana", POLYGON: "Polygon" };
|
|
8844
|
+
var short = (address) => `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
8845
|
+
var SELF_CUSTODY_RISKS = "In a self-custody wallet only your device can sign. If you lose this device and every recovery method, nobody can recover the wallet or its funds, not the app and not Pollar. Nobody can undo or freeze a transaction you sign.";
|
|
8846
|
+
function CustodyMigrationModalTemplate(p) {
|
|
8847
|
+
const cssVars = buildModalCssVars(p.theme, p.accentColor, p.styleOverrides);
|
|
8848
|
+
const [pick, setPick] = react.useState(p.state.choice ? null : p.state.toCustody);
|
|
8849
|
+
const [risksAccepted, setRisksAccepted] = react.useState(false);
|
|
8850
|
+
const custody = p.state.choice ? pick : p.state.toCustody;
|
|
8851
|
+
const canMove = !!custody && (custody !== "SELF_CUSTODY" || risksAccepted) && !p.busy;
|
|
8852
|
+
const moving = p.state.wallets.filter((w) => w.required);
|
|
8853
|
+
const changing = moving.filter((w) => w.addressChanges);
|
|
8854
|
+
const failed = moving.some((w) => w.status === "FAILED");
|
|
8855
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-card pollar-recovery-modal", "data-theme": p.theme, style: cssVars, children: [
|
|
8856
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Move your wallets to this device" }) }),
|
|
8857
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-body", children: [
|
|
8858
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "Until now Pollar held the keys of your wallets. This app now keeps wallets on its users' devices, so they move here, with everything they hold." }),
|
|
8859
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-recovery-section", children: [
|
|
8860
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: "What moves" }),
|
|
8861
|
+
moving.map((w) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-item", children: [
|
|
8862
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
8863
|
+
CHAIN_NAME3[w.chain] ?? w.chain,
|
|
8864
|
+
" \xB7 ",
|
|
8865
|
+
short(w.address)
|
|
8866
|
+
] }),
|
|
8867
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-recovery-tag", children: w.addressChanges ? "New address" : "Same address" })
|
|
8868
|
+
] }, w.chain))
|
|
8869
|
+
] }),
|
|
8870
|
+
changing.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "alert", children: [
|
|
8871
|
+
"Your ",
|
|
8872
|
+
changing.map((w) => CHAIN_NAME3[w.chain] ?? w.chain).join(" and "),
|
|
8873
|
+
" address changes: every token and the balance go to a new address on this device. Stop sharing the old one; anything sent there later needs help from support to recover."
|
|
8874
|
+
] }),
|
|
8875
|
+
p.state.choice && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-recovery-section", children: [
|
|
8876
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Choose how your wallet signs" }),
|
|
8877
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-recovery-check", children: [
|
|
8878
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "radio", name: "custody", checked: pick === "COSIGNED", onChange: () => setPick("COSIGNED") }),
|
|
8879
|
+
" ",
|
|
8880
|
+
"Co-signed: you and the app approve every signature together, and the wallet can be recovered with help."
|
|
8881
|
+
] }),
|
|
8882
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-recovery-check", children: [
|
|
8883
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "radio", name: "custody", checked: pick === "SELF_CUSTODY", onChange: () => setPick("SELF_CUSTODY") }),
|
|
8884
|
+
" ",
|
|
8885
|
+
"Self-custody: only your device signs. Nobody else can move or recover your funds."
|
|
8886
|
+
] })
|
|
8887
|
+
] }),
|
|
8888
|
+
custody === "SELF_CUSTODY" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8889
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "alert", children: SELF_CUSTODY_RISKS }),
|
|
8890
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-recovery-check", children: [
|
|
8891
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: risksAccepted, onChange: (e) => setRisksAccepted(e.target.checked) }),
|
|
8892
|
+
" I understand and accept these risks"
|
|
8893
|
+
] })
|
|
8894
|
+
] }),
|
|
8895
|
+
failed && !p.error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-error", role: "alert", children: "The last attempt did not finish. What did not move is still where it was; try again." }),
|
|
8896
|
+
p.blockedReasons && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "alert", children: [
|
|
8897
|
+
"A wallet cannot move while something still uses it: ",
|
|
8898
|
+
p.blockedReasons.join(", "),
|
|
8899
|
+
". Let it finish and try again."
|
|
8900
|
+
] }),
|
|
8901
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8902
|
+
"button",
|
|
8903
|
+
{
|
|
8904
|
+
type: "button",
|
|
8905
|
+
className: "pollar-recovery-btn pollar-recovery-btn-primary",
|
|
8906
|
+
onClick: () => custody && p.onMove(p.state.choice ? custody : void 0),
|
|
8907
|
+
disabled: !canMove,
|
|
8908
|
+
children: p.busy ? "Moving your wallets..." : "Move my wallets"
|
|
8909
|
+
}
|
|
8910
|
+
),
|
|
8911
|
+
p.blockedReasons && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-recovery-btn pollar-recovery-btn-quiet", onClick: p.onLater, disabled: p.busy, children: "Continue for now" }),
|
|
8912
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-recovery-btn pollar-recovery-btn-quiet", onClick: p.onLogout, disabled: p.busy, children: "Log out" }),
|
|
8913
|
+
p.error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-error", role: "alert", children: p.error })
|
|
8914
|
+
] }),
|
|
8915
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
8916
|
+
] });
|
|
8917
|
+
}
|
|
8918
|
+
function CustodyMigrationModal({ state, onMoved, onLater }) {
|
|
8919
|
+
const { getClient, styles } = usePollar();
|
|
8920
|
+
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
8921
|
+
const [busy, setBusy] = react.useState(false);
|
|
8922
|
+
const [error, setError] = react.useState(null);
|
|
8923
|
+
const [blockedReasons, setBlockedReasons] = react.useState(null);
|
|
8924
|
+
async function move(custody) {
|
|
8925
|
+
setBusy(true);
|
|
8926
|
+
setError(null);
|
|
8927
|
+
setBlockedReasons(null);
|
|
8928
|
+
try {
|
|
8929
|
+
await getClient().cosign.migrateWallets(custody);
|
|
8930
|
+
onMoved();
|
|
8931
|
+
} catch (err) {
|
|
8932
|
+
if (core.isPollarApiError(err) && err.code === "SDK_CUSTODY_MIGRATION_BLOCKED") {
|
|
8933
|
+
const reasons = err.body.reasons;
|
|
8934
|
+
setBlockedReasons(Array.isArray(reasons) ? reasons.map(String) : []);
|
|
8935
|
+
return;
|
|
8936
|
+
}
|
|
8937
|
+
setError(core.transactionErrorMessage(core.isPollarApiError(err) ? err.code : null, err instanceof Error ? err.message : null));
|
|
8938
|
+
} finally {
|
|
8939
|
+
setBusy(false);
|
|
8940
|
+
}
|
|
8941
|
+
}
|
|
8942
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8943
|
+
CustodyMigrationModalTemplate,
|
|
8944
|
+
{
|
|
8945
|
+
theme,
|
|
8946
|
+
accentColor,
|
|
8947
|
+
styleOverrides,
|
|
8948
|
+
state,
|
|
8949
|
+
busy,
|
|
8950
|
+
error,
|
|
8951
|
+
blockedReasons,
|
|
8952
|
+
onMove: (custody) => void move(custody),
|
|
8953
|
+
onLater,
|
|
8954
|
+
onLogout: () => void getClient().logout()
|
|
8955
|
+
}
|
|
8956
|
+
) });
|
|
8957
|
+
}
|
|
8958
|
+
function CloseIcon3() {
|
|
8959
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m3 3 8 8M11 3l-8 8", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
|
|
8960
|
+
}
|
|
8961
|
+
var shortKey = (key) => `${key.slice(0, 6)}...${key.slice(-4)}`;
|
|
8962
|
+
function Button(props) {
|
|
8963
|
+
const running = props.busy === props.id;
|
|
8964
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8965
|
+
"button",
|
|
8966
|
+
{
|
|
8967
|
+
type: "button",
|
|
8968
|
+
className: `pollar-recovery-btn pollar-recovery-btn-${props.kind ?? "quiet"}`,
|
|
8969
|
+
onClick: props.onClick,
|
|
8970
|
+
disabled: props.disabled || props.busy !== null,
|
|
8971
|
+
children: running ? props.busyLabel ?? "Working..." : props.label
|
|
8972
|
+
}
|
|
8973
|
+
);
|
|
8974
|
+
}
|
|
8975
|
+
function CodeForm(props) {
|
|
8976
|
+
const [code, setCode] = react.useState("");
|
|
8977
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8978
|
+
"form",
|
|
8979
|
+
{
|
|
8980
|
+
className: "pollar-recovery-row",
|
|
8981
|
+
onSubmit: (e) => {
|
|
8982
|
+
e.preventDefault();
|
|
8983
|
+
if (code.trim()) props.onSubmit(code);
|
|
8984
|
+
},
|
|
8985
|
+
children: [
|
|
8986
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8987
|
+
"input",
|
|
8988
|
+
{
|
|
8989
|
+
className: "pollar-recovery-input",
|
|
8990
|
+
value: code,
|
|
8991
|
+
onChange: (e) => setCode(e.target.value),
|
|
8992
|
+
placeholder: "Code from the email",
|
|
8993
|
+
autoComplete: "one-time-code",
|
|
8994
|
+
"aria-label": "Code from the email"
|
|
8995
|
+
}
|
|
8996
|
+
),
|
|
8997
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8998
|
+
Button,
|
|
8999
|
+
{
|
|
9000
|
+
busy: props.busy,
|
|
9001
|
+
id: props.id,
|
|
9002
|
+
label: props.label,
|
|
9003
|
+
kind: "primary",
|
|
9004
|
+
onClick: () => code.trim() && props.onSubmit(code)
|
|
9005
|
+
}
|
|
9006
|
+
)
|
|
9007
|
+
]
|
|
9008
|
+
}
|
|
9009
|
+
);
|
|
9010
|
+
}
|
|
9011
|
+
function RecoveryModalTemplate(p) {
|
|
9012
|
+
const cssVars = buildModalCssVars(p.theme, p.accentColor, p.styleOverrides);
|
|
9013
|
+
const [exportAccepted, setExportAccepted] = react.useState(false);
|
|
9014
|
+
const [risksAccepted, setRisksAccepted] = react.useState(false);
|
|
9015
|
+
const state = p.state;
|
|
9016
|
+
const locked = !!state && state.required && !state.configured;
|
|
9017
|
+
const risksPending = locked && p.selfCustodyRisks && !risksAccepted;
|
|
9018
|
+
const lastMethod = !!state && state.passkeys.length + (state.email.verified ? 1 : 0) + (state.devices.length >= 2 ? 1 : 0) <= 1;
|
|
9019
|
+
let body;
|
|
9020
|
+
if (!state) {
|
|
9021
|
+
body = /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "Loading your wallet's recovery methods..." });
|
|
9022
|
+
} else if (!state.required) {
|
|
9023
|
+
body = /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "This wallet doesn't need recovery methods: it isn't secured by your device." });
|
|
9024
|
+
} else if (!p.thisDeviceEnrolled && p.view !== "recover-email") {
|
|
9025
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9026
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "status", children: "This device isn't part of your wallet yet. Get back in with one of your recovery methods, or ask a device that already has the wallet to add this one." }),
|
|
9027
|
+
state.passkeys.length > 0 && p.passkeyAvailable && /* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "recover-passkey", label: "Use a passkey", kind: "primary", onClick: p.onRecoverWithPasskey }),
|
|
9028
|
+
state.email.verified && /* @__PURE__ */ jsxRuntime.jsx(
|
|
9029
|
+
Button,
|
|
9030
|
+
{
|
|
9031
|
+
busy: p.busy,
|
|
9032
|
+
id: "recover-send",
|
|
9033
|
+
label: `Email a code to ${state.email.address ?? "your email"}`,
|
|
9034
|
+
onClick: () => p.onView("recover-email")
|
|
9035
|
+
}
|
|
9036
|
+
),
|
|
9037
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "enroll", label: "Ask another device to add this one", onClick: p.onRequestEnrollment })
|
|
9038
|
+
] });
|
|
9039
|
+
} else if (risksPending && p.view === "overview") {
|
|
9040
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9041
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "alert", children: "This is a self-custody wallet: only your device can sign. If you lose this device and every recovery method, nobody can recover the wallet or its funds, not the app and not Pollar. Nobody can undo or freeze a transaction you sign." }),
|
|
9042
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9043
|
+
Button,
|
|
9044
|
+
{
|
|
9045
|
+
busy: p.busy,
|
|
9046
|
+
id: "accept-risks",
|
|
9047
|
+
label: "I understand and accept these risks",
|
|
9048
|
+
kind: "primary",
|
|
9049
|
+
onClick: () => setRisksAccepted(true)
|
|
9050
|
+
}
|
|
9051
|
+
)
|
|
9052
|
+
] });
|
|
9053
|
+
} else if (p.view === "recover-email") {
|
|
9054
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9055
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-recovery-muted", children: [
|
|
9056
|
+
"We'll email a code to ",
|
|
9057
|
+
state.email.address,
|
|
9058
|
+
". The code goes straight to the wallet provider, encrypted on this device."
|
|
9059
|
+
] }),
|
|
9060
|
+
!p.codeSent ? /* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "recover-send", label: "Send code", kind: "primary", onClick: p.onSendRecoveryCode }) : /* @__PURE__ */ jsxRuntime.jsx(CodeForm, { busy: p.busy, id: "recover-code", label: "Recover", onSubmit: p.onRecoverWithCode }),
|
|
9061
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "back", label: "Back", onClick: () => p.onView("overview") })
|
|
9062
|
+
] });
|
|
9063
|
+
} else if (p.view === "email") {
|
|
9064
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9065
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "Confirm an email you control. If you lose this device, a code sent there lets you add a new one. Anyone who controls this inbox could do the same, so use one that is well protected." }),
|
|
9066
|
+
!p.codeSent ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9067
|
+
"form",
|
|
9068
|
+
{
|
|
9069
|
+
className: "pollar-recovery-row",
|
|
9070
|
+
onSubmit: (e) => {
|
|
9071
|
+
e.preventDefault();
|
|
9072
|
+
p.onSendEmailCode();
|
|
9073
|
+
},
|
|
9074
|
+
children: [
|
|
9075
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9076
|
+
"input",
|
|
8307
9077
|
{
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
9078
|
+
className: "pollar-recovery-input",
|
|
9079
|
+
type: "email",
|
|
9080
|
+
value: p.emailDraft,
|
|
9081
|
+
onChange: (e) => p.onEmailDraft(e.target.value),
|
|
9082
|
+
placeholder: "you@example.com",
|
|
9083
|
+
"aria-label": "Email"
|
|
8313
9084
|
}
|
|
8314
9085
|
),
|
|
8315
9086
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8316
|
-
|
|
9087
|
+
Button,
|
|
8317
9088
|
{
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
9089
|
+
busy: p.busy,
|
|
9090
|
+
id: "email-send",
|
|
9091
|
+
label: "Send code",
|
|
9092
|
+
kind: "primary",
|
|
9093
|
+
onClick: p.onSendEmailCode,
|
|
9094
|
+
disabled: !p.emailDraft.trim()
|
|
8323
9095
|
}
|
|
8324
9096
|
)
|
|
9097
|
+
]
|
|
9098
|
+
}
|
|
9099
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(CodeForm, { busy: p.busy, id: "email-confirm", label: "Confirm", onSubmit: p.onConfirmEmail }),
|
|
9100
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "back", label: "Back", onClick: () => p.onView("overview") })
|
|
9101
|
+
] });
|
|
9102
|
+
} else if (p.view === "export") {
|
|
9103
|
+
body = p.phrase ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9104
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "alert", children: "Anyone with these words controls every account in this wallet. Write them down offline and never share them." }),
|
|
9105
|
+
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "pollar-recovery-phrase", children: p.phrase }),
|
|
9106
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "hide", label: "Hide", kind: "primary", onClick: () => p.onView("overview") })
|
|
9107
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9108
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "Your recovery phrase lets you take this wallet to another app. It is decrypted only on this device; the app and Pollar never see it." }),
|
|
9109
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-recovery-check", children: [
|
|
9110
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: exportAccepted, onChange: (e) => setExportAccepted(e.target.checked) }),
|
|
9111
|
+
" I understand that whoever sees the phrase controls the wallet"
|
|
9112
|
+
] }),
|
|
9113
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9114
|
+
Button,
|
|
9115
|
+
{
|
|
9116
|
+
busy: p.busy,
|
|
9117
|
+
id: "export",
|
|
9118
|
+
label: "Show recovery phrase",
|
|
9119
|
+
kind: "danger",
|
|
9120
|
+
onClick: p.onExport,
|
|
9121
|
+
disabled: !exportAccepted
|
|
9122
|
+
}
|
|
9123
|
+
),
|
|
9124
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "back", label: "Back", onClick: () => p.onView("overview") })
|
|
9125
|
+
] });
|
|
9126
|
+
} else {
|
|
9127
|
+
const enrollments = p.devices?.enrollments ?? [];
|
|
9128
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9129
|
+
locked ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "alert", children: "Your wallet is locked until you add a way to recover it. Without one, losing this device means losing the funds, and nobody can get them back, not the app and not Pollar. Add a passkey, a second device or your email." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-recovery-banner pollar-recovery-banner-ok", role: "status", children: "Your wallet can be recovered if you lose this device." }),
|
|
9130
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-recovery-section", children: [
|
|
9131
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Passkeys" }),
|
|
9132
|
+
state.passkeys.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "No passkey yet." }),
|
|
9133
|
+
state.passkeys.map((pk) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-item", children: [
|
|
9134
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: pk.name }),
|
|
9135
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9136
|
+
Button,
|
|
9137
|
+
{
|
|
9138
|
+
busy: p.busy,
|
|
9139
|
+
id: `passkey:${pk.authenticatorId}`,
|
|
9140
|
+
label: "Remove",
|
|
9141
|
+
kind: "danger",
|
|
9142
|
+
onClick: () => p.onRemovePasskey(pk.authenticatorId),
|
|
9143
|
+
disabled: lastMethod
|
|
9144
|
+
}
|
|
9145
|
+
)
|
|
9146
|
+
] }, pk.authenticatorId)),
|
|
9147
|
+
p.passkeyAvailable ? /* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "passkey", label: "Add a passkey", onClick: p.onAddPasskey }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "Passkeys aren't available on this device." })
|
|
9148
|
+
] }),
|
|
9149
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-recovery-section", children: [
|
|
9150
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Email" }),
|
|
9151
|
+
state.email.verified ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-item", children: [
|
|
9152
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: state.email.address }),
|
|
9153
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-recovery-tag", children: "Confirmed" })
|
|
9154
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "email", label: "Confirm an email", onClick: () => p.onView("email") })
|
|
9155
|
+
] }),
|
|
9156
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-recovery-section", children: [
|
|
9157
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Devices" }),
|
|
9158
|
+
(p.devices?.devices ?? []).map((d) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-item", children: [
|
|
9159
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: d.label ?? shortKey(d.publicKey) }),
|
|
9160
|
+
d.publicKey.toLowerCase() === p.thisDeviceKey && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-recovery-tag", children: "This device" })
|
|
9161
|
+
] }, d.id)),
|
|
9162
|
+
enrollments.map((e) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-item pollar-recovery-item-pending", children: [
|
|
9163
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
9164
|
+
e.label ?? "A device",
|
|
9165
|
+
" wants to join (",
|
|
9166
|
+
shortKey(e.publicKey),
|
|
9167
|
+
")"
|
|
9168
|
+
] }),
|
|
9169
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-recovery-actions", children: [
|
|
9170
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9171
|
+
Button,
|
|
9172
|
+
{
|
|
9173
|
+
busy: p.busy,
|
|
9174
|
+
id: `approve:${e.id}`,
|
|
9175
|
+
label: "Approve",
|
|
9176
|
+
kind: "primary",
|
|
9177
|
+
onClick: () => p.onApproveDevice(e.id)
|
|
9178
|
+
}
|
|
9179
|
+
),
|
|
9180
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: `reject:${e.id}`, label: "Reject", onClick: () => p.onRejectDevice(e.id) })
|
|
8325
9181
|
] })
|
|
9182
|
+
] }, e.id)),
|
|
9183
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: 'To add another device, sign in there and choose "Ask another device to add this one"; it shows up here to approve. Only approve a device you are holding.' })
|
|
9184
|
+
] }),
|
|
9185
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-recovery-section", children: [
|
|
9186
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Recovery phrase" }),
|
|
9187
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "export", label: "Export recovery phrase", onClick: () => p.onView("export") })
|
|
9188
|
+
] })
|
|
9189
|
+
] });
|
|
9190
|
+
}
|
|
9191
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9192
|
+
"div",
|
|
9193
|
+
{
|
|
9194
|
+
className: "pollar-modal-card pollar-recovery-modal",
|
|
9195
|
+
"data-theme": p.theme,
|
|
9196
|
+
style: cssVars,
|
|
9197
|
+
onClick: (e) => e.stopPropagation(),
|
|
9198
|
+
children: [
|
|
9199
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
9200
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Wallet recovery" }),
|
|
9201
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: p.onClose, "aria-label": "Close", title: "Close", children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon3, {}) }) })
|
|
9202
|
+
] }),
|
|
9203
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-body", children: [
|
|
9204
|
+
body,
|
|
9205
|
+
p.notice && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-notice", role: "status", children: p.notice }),
|
|
9206
|
+
p.error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-error", role: "alert", children: p.error })
|
|
8326
9207
|
] }),
|
|
8327
9208
|
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
8328
9209
|
]
|
|
8329
9210
|
}
|
|
8330
9211
|
);
|
|
8331
9212
|
}
|
|
8332
|
-
function
|
|
8333
|
-
|
|
8334
|
-
if (!group || group.steps.length < 2) return null;
|
|
8335
|
-
const stepKey = core.cosignStepKeyOf(request);
|
|
8336
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-group", children: [
|
|
8337
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-group-title", children: group.title }),
|
|
8338
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: "Approving covers these steps; each one is checked before it is signed." }),
|
|
8339
|
-
/* @__PURE__ */ jsxRuntime.jsx("ol", { className: "pollar-cosign-group-steps", children: group.steps.map((step) => {
|
|
8340
|
-
const isThis = stepKey !== null && core.stepInGroup({ steps: [step] }, stepKey);
|
|
8341
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: isThis ? "pollar-cosign-group-step-current" : void 0, children: [
|
|
8342
|
-
step.label,
|
|
8343
|
-
isThis && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-cosign-muted", children: " (this one)" })
|
|
8344
|
-
] }, step.key);
|
|
8345
|
-
}) })
|
|
8346
|
-
] });
|
|
9213
|
+
function errorText2(err) {
|
|
9214
|
+
return core.cosignRefusalMessage(err) ?? core.transactionErrorMessage(core.isPollarApiError(err) ? err.code : null, err instanceof Error ? err.message : null);
|
|
8347
9215
|
}
|
|
8348
|
-
function
|
|
8349
|
-
const { getClient, styles,
|
|
9216
|
+
function RecoveryModal({ onClose }) {
|
|
9217
|
+
const { getClient, styles, refreshRecovery, appConfig } = usePollar();
|
|
8350
9218
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
8351
|
-
const
|
|
8352
|
-
const [
|
|
8353
|
-
const [
|
|
9219
|
+
const recovery = getClient().cosign.recovery;
|
|
9220
|
+
const [state, setState] = react.useState(null);
|
|
9221
|
+
const [devices, setDevices] = react.useState(null);
|
|
9222
|
+
const [thisDeviceKey, setThisDeviceKey] = react.useState(null);
|
|
9223
|
+
const [view, setView] = react.useState("overview");
|
|
8354
9224
|
const [busy, setBusy] = react.useState(null);
|
|
8355
9225
|
const [error, setError] = react.useState(null);
|
|
8356
|
-
const [
|
|
8357
|
-
const [
|
|
8358
|
-
react.
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
9226
|
+
const [notice, setNotice] = react.useState(null);
|
|
9227
|
+
const [emailDraft, setEmailDraft] = react.useState("");
|
|
9228
|
+
const [codeSent, setCodeSent] = react.useState(false);
|
|
9229
|
+
const [phrase, setPhrase] = react.useState(null);
|
|
9230
|
+
const load = react.useCallback(async () => {
|
|
9231
|
+
const client = getClient();
|
|
9232
|
+
const [nextState, nextDevices, key] = await Promise.all([
|
|
9233
|
+
client.cosign.recovery.status(),
|
|
9234
|
+
client.cosign.devices(),
|
|
9235
|
+
client.cosign.publicKeyHex()
|
|
9236
|
+
]);
|
|
9237
|
+
setState(nextState);
|
|
9238
|
+
setDevices(nextDevices);
|
|
9239
|
+
setThisDeviceKey(key.toLowerCase());
|
|
9240
|
+
if (nextState.email.address) setEmailDraft((d) => d || nextState.email.address);
|
|
9241
|
+
refreshRecovery();
|
|
9242
|
+
}, [getClient, refreshRecovery]);
|
|
8371
9243
|
react.useEffect(() => {
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
setVerification(null);
|
|
8375
|
-
setError(null);
|
|
8376
|
-
setApproveFailedFor(null);
|
|
8377
|
-
let cancelled = false;
|
|
8378
|
-
verify(request).then((v) => {
|
|
8379
|
-
if (!cancelled) setVerification(v);
|
|
8380
|
-
}).catch((err) => {
|
|
8381
|
-
if (!cancelled) setVerification({ ok: false, reason: err instanceof Error ? err.message : String(err) });
|
|
8382
|
-
});
|
|
8383
|
-
return () => {
|
|
8384
|
-
cancelled = true;
|
|
8385
|
-
};
|
|
8386
|
-
}, [currentId, verify]);
|
|
9244
|
+
load().catch((err) => setError(errorText2(err)));
|
|
9245
|
+
}, [load]);
|
|
8387
9246
|
const onCloseRef = react.useRef(onClose);
|
|
8388
9247
|
onCloseRef.current = onClose;
|
|
8389
|
-
react.useEffect(
|
|
8390
|
-
|
|
9248
|
+
react.useEffect(
|
|
9249
|
+
() => getClient().onAuthStateChange((authState) => {
|
|
8391
9250
|
if (authState.step === "idle") onCloseRef.current();
|
|
8392
|
-
})
|
|
8393
|
-
|
|
9251
|
+
}),
|
|
9252
|
+
[getClient]
|
|
9253
|
+
);
|
|
8394
9254
|
const run = react.useCallback(
|
|
8395
|
-
async (
|
|
8396
|
-
setBusy(
|
|
9255
|
+
async (key, action, after) => {
|
|
9256
|
+
setBusy(key);
|
|
8397
9257
|
setError(null);
|
|
9258
|
+
setNotice(null);
|
|
8398
9259
|
try {
|
|
8399
|
-
await action(
|
|
9260
|
+
await action();
|
|
9261
|
+
await load();
|
|
9262
|
+
if (after?.notice) setNotice(after.notice);
|
|
9263
|
+
if (after?.view) setView(after.view);
|
|
8400
9264
|
} catch (err) {
|
|
8401
|
-
setError(
|
|
8402
|
-
if (kind === "approving") setApproveFailedFor(request.id);
|
|
9265
|
+
setError(errorText2(err));
|
|
8403
9266
|
} finally {
|
|
8404
9267
|
setBusy(null);
|
|
8405
9268
|
}
|
|
8406
9269
|
},
|
|
8407
|
-
[]
|
|
9270
|
+
[load]
|
|
8408
9271
|
);
|
|
9272
|
+
const enrolled = !!thisDeviceKey && !!devices?.devices.some((d) => d.publicKey.toLowerCase() === thisDeviceKey);
|
|
8409
9273
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8410
|
-
|
|
9274
|
+
RecoveryModalTemplate,
|
|
8411
9275
|
{
|
|
8412
9276
|
theme,
|
|
8413
9277
|
accentColor,
|
|
8414
9278
|
styleOverrides,
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
9279
|
+
state,
|
|
9280
|
+
devices,
|
|
9281
|
+
thisDeviceKey,
|
|
9282
|
+
thisDeviceEnrolled: enrolled,
|
|
9283
|
+
passkeyAvailable: recovery.passkeyAvailable,
|
|
9284
|
+
selfCustodyRisks: appConfig.application?.walletCustodyMode === "SELF_CUSTODY" && devices?.custody === "SELF_CUSTODY",
|
|
9285
|
+
view,
|
|
8418
9286
|
busy,
|
|
8419
9287
|
error,
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
9288
|
+
notice,
|
|
9289
|
+
emailDraft,
|
|
9290
|
+
codeSent,
|
|
9291
|
+
phrase,
|
|
9292
|
+
onView: (next) => {
|
|
9293
|
+
setError(null);
|
|
9294
|
+
setNotice(null);
|
|
9295
|
+
setCodeSent(false);
|
|
9296
|
+
if (next !== "export") setPhrase(null);
|
|
9297
|
+
setView(next);
|
|
9298
|
+
},
|
|
9299
|
+
onEmailDraft: setEmailDraft,
|
|
9300
|
+
onAddPasskey: () => void run("passkey", () => recovery.addPasskey(), { notice: "Passkey added." }),
|
|
9301
|
+
onRemovePasskey: (id) => void run(`passkey:${id}`, () => recovery.removePasskey(id)),
|
|
9302
|
+
onSendEmailCode: () => void run("email-send", async () => {
|
|
9303
|
+
await recovery.startEmail(emailDraft.trim());
|
|
9304
|
+
setCodeSent(true);
|
|
9305
|
+
}),
|
|
9306
|
+
onConfirmEmail: (code) => void run("email-confirm", () => recovery.confirmEmail(code.trim()), { notice: "Email confirmed.", view: "overview" }),
|
|
9307
|
+
onApproveDevice: (id) => void run(`approve:${id}`, () => recovery.approveDevice(id), { notice: "Device added." }),
|
|
9308
|
+
onRejectDevice: (id) => void run(`reject:${id}`, () => recovery.rejectDevice(id)),
|
|
9309
|
+
onRequestEnrollment: () => void run("enroll", () => recovery.requestDeviceEnrollment(), {
|
|
9310
|
+
notice: "Request sent. Approve it from a device that already has this wallet within 15 minutes."
|
|
9311
|
+
}),
|
|
9312
|
+
onRecoverWithPasskey: () => void run("recover-passkey", () => recovery.recoverWithPasskey(), {
|
|
9313
|
+
notice: "This device is part of your wallet again."
|
|
9314
|
+
}),
|
|
9315
|
+
onSendRecoveryCode: () => void run("recover-send", async () => {
|
|
9316
|
+
await recovery.startEmailRecovery();
|
|
9317
|
+
setCodeSent(true);
|
|
9318
|
+
}),
|
|
9319
|
+
onRecoverWithCode: (code) => void run("recover-code", () => recovery.recoverWithEmailCode(code.trim()), {
|
|
9320
|
+
notice: "This device is part of your wallet again.",
|
|
9321
|
+
view: "overview"
|
|
9322
|
+
}),
|
|
9323
|
+
onExport: () => void run("export", async () => {
|
|
9324
|
+
setPhrase(await recovery.exportWallet());
|
|
9325
|
+
}),
|
|
8426
9326
|
onClose
|
|
8427
9327
|
}
|
|
8428
9328
|
) });
|
|
@@ -8453,7 +9353,7 @@ function detailRows2(confirmation) {
|
|
|
8453
9353
|
push("Network", confirmation.network);
|
|
8454
9354
|
return rows;
|
|
8455
9355
|
}
|
|
8456
|
-
function
|
|
9356
|
+
function CloseIcon4() {
|
|
8457
9357
|
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m3 3 8 8M11 3l-8 8", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
|
|
8458
9358
|
}
|
|
8459
9359
|
function ConfirmModal({ confirmation }) {
|
|
@@ -8477,7 +9377,7 @@ function ConfirmModal({ confirmation }) {
|
|
|
8477
9377
|
children: [
|
|
8478
9378
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
8479
9379
|
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Confirm transaction" }),
|
|
8480
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: confirmation.reject, "aria-label": "Close", title: "Close", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9380
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: confirmation.reject, "aria-label": "Close", title: "Close", children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon4, {}) }) })
|
|
8481
9381
|
] }),
|
|
8482
9382
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-detail", children: [
|
|
8483
9383
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-detail-title", children: labelOf2(confirmation) }),
|
|
@@ -8614,6 +9514,25 @@ function formatDate(iso) {
|
|
|
8614
9514
|
function truncateMiddle(value, head = 4, tail = 4) {
|
|
8615
9515
|
return value.length <= head + tail + 1 ? value : `${value.slice(0, head)}\u2026${value.slice(-tail)}`;
|
|
8616
9516
|
}
|
|
9517
|
+
function formatFee(fee) {
|
|
9518
|
+
if (fee.unit === "lamports") {
|
|
9519
|
+
try {
|
|
9520
|
+
return `${core.fromBaseUnits(fee.amount, 9)} SOL`;
|
|
9521
|
+
} catch {
|
|
9522
|
+
}
|
|
9523
|
+
}
|
|
9524
|
+
return `${fee.amount} ${fee.unit}`;
|
|
9525
|
+
}
|
|
9526
|
+
function formatAmount4(details) {
|
|
9527
|
+
const { amount, decimals, symbol } = details ?? {};
|
|
9528
|
+
if (typeof amount !== "string" || typeof decimals !== "number") return null;
|
|
9529
|
+
try {
|
|
9530
|
+
const value = core.fromBaseUnits(amount, decimals);
|
|
9531
|
+
return typeof symbol === "string" ? `${value} ${symbol}` : value;
|
|
9532
|
+
} catch {
|
|
9533
|
+
return null;
|
|
9534
|
+
}
|
|
9535
|
+
}
|
|
8617
9536
|
var STELLAR_ADDRESS = /\b[GC][A-Z2-7]{55}\b/g;
|
|
8618
9537
|
function AddressChip({ value, label }) {
|
|
8619
9538
|
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-hist-item-issuer", children: [
|
|
@@ -8751,15 +9670,17 @@ function TxHistoryModalTemplate({
|
|
|
8751
9670
|
] }),
|
|
8752
9671
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-hist-item-meta", children: [
|
|
8753
9672
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: record.operation }),
|
|
9673
|
+
record.chain !== "STELLAR" && formatAmount4(record.details) && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
9674
|
+
"\xB7 ",
|
|
9675
|
+
formatAmount4(record.details)
|
|
9676
|
+
] }),
|
|
8754
9677
|
typeof record.details?.sponsored === "boolean" && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
8755
9678
|
"\xB7 ",
|
|
8756
9679
|
record.details.sponsored ? "Sponsored" : "Self-paid"
|
|
8757
9680
|
] }),
|
|
8758
9681
|
record.fee && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
8759
9682
|
"\xB7 ",
|
|
8760
|
-
record.fee
|
|
8761
|
-
" ",
|
|
8762
|
-
record.fee.unit
|
|
9683
|
+
formatFee(record.fee)
|
|
8763
9684
|
] })
|
|
8764
9685
|
] }),
|
|
8765
9686
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-hist-item-footer", children: [
|
|
@@ -9070,6 +9991,48 @@ var browserPasskeySigner = async ({ credentialId, challenge }) => {
|
|
|
9070
9991
|
signature: response.signature
|
|
9071
9992
|
};
|
|
9072
9993
|
};
|
|
9994
|
+
var browserRecoveryPasskey = {
|
|
9995
|
+
async create({ challenge, userName }) {
|
|
9996
|
+
const rpId = window.location.hostname;
|
|
9997
|
+
const response = await browser.startRegistration({
|
|
9998
|
+
optionsJSON: {
|
|
9999
|
+
challenge,
|
|
10000
|
+
rp: { id: rpId, name: rpId },
|
|
10001
|
+
user: { id: randomUserId(), name: userName, displayName: userName },
|
|
10002
|
+
pubKeyCredParams: [
|
|
10003
|
+
{ type: "public-key", alg: -7 },
|
|
10004
|
+
{ type: "public-key", alg: -257 }
|
|
10005
|
+
],
|
|
10006
|
+
authenticatorSelection: { residentKey: "preferred", userVerification: "preferred" },
|
|
10007
|
+
attestation: "none",
|
|
10008
|
+
timeout: 6e4
|
|
10009
|
+
}
|
|
10010
|
+
});
|
|
10011
|
+
return {
|
|
10012
|
+
credentialId: response.id,
|
|
10013
|
+
clientDataJson: response.response.clientDataJSON,
|
|
10014
|
+
attestationObject: response.response.attestationObject,
|
|
10015
|
+
transports: response.response.transports ?? []
|
|
10016
|
+
};
|
|
10017
|
+
},
|
|
10018
|
+
async get({ challenge, allowCredentials }) {
|
|
10019
|
+
const rpId = window.location.hostname;
|
|
10020
|
+
const response = await browser.startAuthentication({
|
|
10021
|
+
optionsJSON: {
|
|
10022
|
+
challenge,
|
|
10023
|
+
rpId,
|
|
10024
|
+
allowCredentials: allowCredentials.map((id) => ({ id, type: "public-key" })),
|
|
10025
|
+
userVerification: "preferred"
|
|
10026
|
+
}
|
|
10027
|
+
});
|
|
10028
|
+
return {
|
|
10029
|
+
credentialId: response.id,
|
|
10030
|
+
authenticatorData: response.response.authenticatorData,
|
|
10031
|
+
clientDataJson: response.response.clientDataJSON,
|
|
10032
|
+
signature: response.response.signature
|
|
10033
|
+
};
|
|
10034
|
+
}
|
|
10035
|
+
};
|
|
9073
10036
|
var DEFAULT_APP_CONFIG = {
|
|
9074
10037
|
application: { name: "", network: "testnet", chains: [] },
|
|
9075
10038
|
styles: {}
|
|
@@ -9094,7 +10057,11 @@ function PollarProvider({
|
|
|
9094
10057
|
}) {
|
|
9095
10058
|
const [pollarClient] = react.useState(() => {
|
|
9096
10059
|
if (core.isPollarClient(client)) {
|
|
9097
|
-
client.setPasskeyDefaults({
|
|
10060
|
+
client.setPasskeyDefaults({
|
|
10061
|
+
passkey: browserPasskeyCeremony,
|
|
10062
|
+
passkeySign: browserPasskeySigner,
|
|
10063
|
+
recoveryPasskey: browserRecoveryPasskey
|
|
10064
|
+
});
|
|
9098
10065
|
return client;
|
|
9099
10066
|
}
|
|
9100
10067
|
const alreadyBuilt = clientByConfig.get(client);
|
|
@@ -9102,7 +10069,8 @@ function PollarProvider({
|
|
|
9102
10069
|
const built = new core.PollarClient({
|
|
9103
10070
|
...client,
|
|
9104
10071
|
passkey: client.passkey ?? browserPasskeyCeremony,
|
|
9105
|
-
passkeySign: client.passkeySign ?? browserPasskeySigner
|
|
10072
|
+
passkeySign: client.passkeySign ?? browserPasskeySigner,
|
|
10073
|
+
recoveryPasskey: client.recoveryPasskey ?? browserRecoveryPasskey
|
|
9106
10074
|
});
|
|
9107
10075
|
clientByConfig.set(client, built);
|
|
9108
10076
|
return built;
|
|
@@ -9257,6 +10225,8 @@ function PollarProvider({
|
|
|
9257
10225
|
const [receiveModalOpen, setReceiveModalOpen] = react.useState(false);
|
|
9258
10226
|
const [sessionsModalOpen, setSessionsModalOpen] = react.useState(false);
|
|
9259
10227
|
const [cosignModalOpen, setCosignModalOpen] = react.useState(false);
|
|
10228
|
+
const [cosignNextStep, setCosignNextStep] = react.useState(null);
|
|
10229
|
+
const [recoveryModalOpen, setRecoveryModalOpen] = react.useState(false);
|
|
9260
10230
|
const cosignPendingCount = react.useRef(0);
|
|
9261
10231
|
react.useEffect(() => {
|
|
9262
10232
|
if (cosign.pending.length > cosignPendingCount.current) setCosignModalOpen(true);
|
|
@@ -9279,6 +10249,7 @@ function PollarProvider({
|
|
|
9279
10249
|
setReceiveModalOpen(false);
|
|
9280
10250
|
setSessionsModalOpen(false);
|
|
9281
10251
|
setCosignModalOpen(false);
|
|
10252
|
+
setRecoveryModalOpen(false);
|
|
9282
10253
|
setDistributionRulesModalOpen(false);
|
|
9283
10254
|
}),
|
|
9284
10255
|
[pollarClient]
|
|
@@ -9287,6 +10258,45 @@ function PollarProvider({
|
|
|
9287
10258
|
const walletProvisioning = sessionState?.wallet?.provisioning;
|
|
9288
10259
|
const hasSession = sessionState !== null;
|
|
9289
10260
|
const getClient = react.useCallback(() => pollarClient, [pollarClient]);
|
|
10261
|
+
const [recovery, setRecovery] = react.useState(null);
|
|
10262
|
+
const [recoveryTick, setRecoveryTick] = react.useState(0);
|
|
10263
|
+
const refreshRecovery = react.useCallback(() => setRecoveryTick((t) => t + 1), []);
|
|
10264
|
+
react.useEffect(() => {
|
|
10265
|
+
if (!hasSession) {
|
|
10266
|
+
setRecovery(null);
|
|
10267
|
+
return;
|
|
10268
|
+
}
|
|
10269
|
+
let cancelled = false;
|
|
10270
|
+
pollarClient.cosign.recovery.status().then((next) => {
|
|
10271
|
+
if (!cancelled) setRecovery(next);
|
|
10272
|
+
}).catch(() => {
|
|
10273
|
+
if (!cancelled) setRecovery(null);
|
|
10274
|
+
});
|
|
10275
|
+
return () => {
|
|
10276
|
+
cancelled = true;
|
|
10277
|
+
};
|
|
10278
|
+
}, [pollarClient, hasSession, walletAddress, recoveryTick]);
|
|
10279
|
+
const recoveryLocked = !!recovery && recovery.required && !recovery.configured;
|
|
10280
|
+
const [custodyMigration, setCustodyMigration] = react.useState(null);
|
|
10281
|
+
const [custodyMigrationTick, setCustodyMigrationTick] = react.useState(0);
|
|
10282
|
+
const refreshCustodyMigration = react.useCallback(() => setCustodyMigrationTick((t) => t + 1), []);
|
|
10283
|
+
const [custodyMigrationLater, setCustodyMigrationLater] = react.useState(false);
|
|
10284
|
+
react.useEffect(() => {
|
|
10285
|
+
if (!hasSession) {
|
|
10286
|
+
setCustodyMigration(null);
|
|
10287
|
+
setCustodyMigrationLater(false);
|
|
10288
|
+
return;
|
|
10289
|
+
}
|
|
10290
|
+
let cancelled = false;
|
|
10291
|
+
pollarClient.cosign.custodyMigration().then((next) => {
|
|
10292
|
+
if (!cancelled) setCustodyMigration(next);
|
|
10293
|
+
}).catch(() => {
|
|
10294
|
+
if (!cancelled) setCustodyMigration(null);
|
|
10295
|
+
});
|
|
10296
|
+
return () => {
|
|
10297
|
+
cancelled = true;
|
|
10298
|
+
};
|
|
10299
|
+
}, [pollarClient, hasSession, walletAddress, custodyMigrationTick]);
|
|
9290
10300
|
const refreshWalletBalance = react.useCallback(() => pollarClient.refreshBalance(), [pollarClient, walletAddress]);
|
|
9291
10301
|
const refreshAssets = react.useCallback(() => pollarClient.refreshAssets(), [pollarClient, walletAddress]);
|
|
9292
10302
|
const contextValue = react.useMemo(() => {
|
|
@@ -9297,7 +10307,7 @@ function PollarProvider({
|
|
|
9297
10307
|
wallets: pollarClient.getWallets(),
|
|
9298
10308
|
isAuthenticated: hasSession,
|
|
9299
10309
|
hasWallet: pollarClient.hasWallet(),
|
|
9300
|
-
createWallet: () => pollarClient.createWallet(),
|
|
10310
|
+
createWallet: (options) => pollarClient.createWallet(options),
|
|
9301
10311
|
verified,
|
|
9302
10312
|
// client
|
|
9303
10313
|
getClient,
|
|
@@ -9366,6 +10376,13 @@ function PollarProvider({
|
|
|
9366
10376
|
// cosign
|
|
9367
10377
|
cosign,
|
|
9368
10378
|
openCosignModal: () => setCosignModalOpen(true),
|
|
10379
|
+
setCosignNextStep,
|
|
10380
|
+
recovery,
|
|
10381
|
+
recoveryLocked,
|
|
10382
|
+
refreshRecovery,
|
|
10383
|
+
openRecoveryModal: () => setRecoveryModalOpen(true),
|
|
10384
|
+
custodyMigration,
|
|
10385
|
+
refreshCustodyMigration,
|
|
9369
10386
|
confirmations,
|
|
9370
10387
|
// distribution
|
|
9371
10388
|
openDistributionRulesModal: () => setDistributionRulesModalOpen(true),
|
|
@@ -9389,6 +10406,11 @@ function PollarProvider({
|
|
|
9389
10406
|
}, [
|
|
9390
10407
|
walletAddress,
|
|
9391
10408
|
walletProvisioning,
|
|
10409
|
+
recovery,
|
|
10410
|
+
recoveryLocked,
|
|
10411
|
+
refreshRecovery,
|
|
10412
|
+
custodyMigration,
|
|
10413
|
+
refreshCustodyMigration,
|
|
9392
10414
|
hasSession,
|
|
9393
10415
|
verified,
|
|
9394
10416
|
pollarClient,
|
|
@@ -9445,7 +10467,32 @@ function PollarProvider({
|
|
|
9445
10467
|
/* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setCardModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(CardModal, { onClose: () => setCardModalOpen(false) }) }, `${cardModalKey}:${walletAddress}`),
|
|
9446
10468
|
receiveModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setReceiveModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(ReceiveModal, { onClose: () => setReceiveModalOpen(false) }) }),
|
|
9447
10469
|
sessionsModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSessionsModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SessionsModal, { onClose: () => setSessionsModalOpen(false) }) }),
|
|
9448
|
-
cosignModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setCosignModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(CosignModal, { onClose: () => setCosignModalOpen(false) }) }),
|
|
10470
|
+
cosignModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setCosignModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(CosignModal, { nextStep: cosignNextStep, onClose: () => setCosignModalOpen(false) }) }),
|
|
10471
|
+
custodyMigration?.required && !custodyMigrationLater && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: refreshCustodyMigration, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10472
|
+
CustodyMigrationModal,
|
|
10473
|
+
{
|
|
10474
|
+
state: custodyMigration,
|
|
10475
|
+
onMoved: () => {
|
|
10476
|
+
refreshCustodyMigration();
|
|
10477
|
+
refreshRecovery();
|
|
10478
|
+
setRecoveryModalOpen(true);
|
|
10479
|
+
},
|
|
10480
|
+
onLater: () => {
|
|
10481
|
+
setCustodyMigrationLater(true);
|
|
10482
|
+
refreshCustodyMigration();
|
|
10483
|
+
refreshRecovery();
|
|
10484
|
+
}
|
|
10485
|
+
}
|
|
10486
|
+
) }),
|
|
10487
|
+
recoveryModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setRecoveryModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10488
|
+
RecoveryModal,
|
|
10489
|
+
{
|
|
10490
|
+
onClose: () => {
|
|
10491
|
+
setRecoveryModalOpen(false);
|
|
10492
|
+
refreshRecovery();
|
|
10493
|
+
}
|
|
10494
|
+
}
|
|
10495
|
+
) }),
|
|
9449
10496
|
firstConfirmation && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: firstConfirmation.reject, children: /* @__PURE__ */ jsxRuntime.jsx(ConfirmModal, { confirmation: firstConfirmation }, firstConfirmation.id) }),
|
|
9450
10497
|
distributionRulesModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setDistributionRulesModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(DistributionRulesModal, { onClose: () => setDistributionRulesModalOpen(false) }) })
|
|
9451
10498
|
] });
|
|
@@ -9477,8 +10524,9 @@ function createPollarAdapterHook(key) {
|
|
|
9477
10524
|
);
|
|
9478
10525
|
};
|
|
9479
10526
|
}
|
|
9480
|
-
function ButtonLogo() {
|
|
9481
|
-
|
|
10527
|
+
function ButtonLogo({ accentColor }) {
|
|
10528
|
+
const src = readableTextOn(accentColor) === "#ffffff" ? LOGO_POLLAR_MARK_ON_DARK : LOGO_POLLAR_MARK_ON_LIGHT;
|
|
10529
|
+
return /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt: "Pollar", width: 22, height: 22, className: "pollar-wallet-btn-logo" });
|
|
9482
10530
|
}
|
|
9483
10531
|
function cropWallet(address) {
|
|
9484
10532
|
if (address.length <= 12) return address;
|
|
@@ -9486,16 +10534,17 @@ function cropWallet(address) {
|
|
|
9486
10534
|
}
|
|
9487
10535
|
function WalletButtonTemplate({
|
|
9488
10536
|
walletAddress,
|
|
10537
|
+
theme,
|
|
9489
10538
|
accentColor,
|
|
10539
|
+
styleOverrides,
|
|
9490
10540
|
open,
|
|
9491
10541
|
copied,
|
|
9492
|
-
dropdownBg,
|
|
9493
|
-
dropdownBorder,
|
|
9494
|
-
itemColor,
|
|
9495
10542
|
wrapperRef,
|
|
9496
10543
|
isInProgress,
|
|
9497
10544
|
showCreateAccount,
|
|
9498
10545
|
notReadyReason,
|
|
10546
|
+
recoveryLocked,
|
|
10547
|
+
onRecovery,
|
|
9499
10548
|
creatingAccount,
|
|
9500
10549
|
onToggleOpen,
|
|
9501
10550
|
onCreateAccount,
|
|
@@ -9513,11 +10562,15 @@ function WalletButtonTemplate({
|
|
|
9513
10562
|
signedIn,
|
|
9514
10563
|
creatingWallet,
|
|
9515
10564
|
createWalletError,
|
|
10565
|
+
custodyChoice,
|
|
9516
10566
|
onCreateWallet
|
|
9517
10567
|
}) {
|
|
10568
|
+
const [selfCustodyNotice, setSelfCustodyNotice] = react.useState(false);
|
|
10569
|
+
const [risksAccepted, setRisksAccepted] = react.useState(false);
|
|
10570
|
+
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
9518
10571
|
if (!walletAddress && signedIn) {
|
|
9519
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-wrapper", ref: wrapperRef, children: [
|
|
9520
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-btn",
|
|
10572
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-wrapper", ref: wrapperRef, style: cssVars, children: [
|
|
10573
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-btn", onClick: onToggleOpen, children: [
|
|
9521
10574
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-wallet-btn-label", children: onCreateWallet ? "No wallet" : "Signed in" }),
|
|
9522
10575
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9523
10576
|
"svg",
|
|
@@ -9533,42 +10586,93 @@ function WalletButtonTemplate({
|
|
|
9533
10586
|
}
|
|
9534
10587
|
)
|
|
9535
10588
|
] }),
|
|
9536
|
-
open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-dropdown",
|
|
10589
|
+
open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-dropdown", children: [
|
|
9537
10590
|
createWalletError && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9538
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice",
|
|
10591
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice", role: "status", children: createWalletError }),
|
|
10592
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
10593
|
+
] }),
|
|
10594
|
+
onCreateWallet && !custodyChoice && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10595
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-wallet-dropdown-item", onClick: () => onCreateWallet(), disabled: creatingWallet, children: creatingWallet ? "Creating wallet\u2026" : "Create wallet" }),
|
|
10596
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
10597
|
+
] }),
|
|
10598
|
+
onCreateWallet && custodyChoice && !selfCustodyNotice && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10599
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10600
|
+
"button",
|
|
10601
|
+
{
|
|
10602
|
+
className: "pollar-wallet-dropdown-item",
|
|
10603
|
+
onClick: () => onCreateWallet("COSIGNED"),
|
|
10604
|
+
disabled: creatingWallet,
|
|
10605
|
+
children: creatingWallet ? "Creating wallet\u2026" : "Create co-signed wallet"
|
|
10606
|
+
}
|
|
10607
|
+
),
|
|
10608
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice", children: "You and the app approve every signature together. Your wallet can be recovered with help." }),
|
|
10609
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10610
|
+
"button",
|
|
10611
|
+
{
|
|
10612
|
+
className: "pollar-wallet-dropdown-item",
|
|
10613
|
+
onClick: () => setSelfCustodyNotice(true),
|
|
10614
|
+
disabled: creatingWallet,
|
|
10615
|
+
children: "Create self-custody wallet"
|
|
10616
|
+
}
|
|
10617
|
+
),
|
|
10618
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice", children: "Only your device signs. Nobody else can move or recover your funds." }),
|
|
9539
10619
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
9540
10620
|
] }),
|
|
9541
|
-
onCreateWallet && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10621
|
+
onCreateWallet && custodyChoice && selfCustodyNotice && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10622
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice", role: "alert", children: "In a self-custody wallet only your device can sign. If you lose this device and every recovery method, nobody can recover the wallet or its funds, not the app and not Pollar. Nobody can undo or freeze a transaction you sign." }),
|
|
10623
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-wallet-dropdown-notice", children: [
|
|
10624
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10625
|
+
"input",
|
|
10626
|
+
{
|
|
10627
|
+
type: "checkbox",
|
|
10628
|
+
checked: risksAccepted,
|
|
10629
|
+
onChange: (e) => setRisksAccepted(e.target.checked),
|
|
10630
|
+
disabled: creatingWallet
|
|
10631
|
+
}
|
|
10632
|
+
),
|
|
10633
|
+
" ",
|
|
10634
|
+
"I understand and accept these risks"
|
|
10635
|
+
] }),
|
|
10636
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10637
|
+
"button",
|
|
10638
|
+
{
|
|
10639
|
+
className: "pollar-wallet-dropdown-item",
|
|
10640
|
+
onClick: () => onCreateWallet("SELF_CUSTODY"),
|
|
10641
|
+
disabled: creatingWallet || !risksAccepted,
|
|
10642
|
+
children: creatingWallet ? "Creating wallet\u2026" : "Create self-custody wallet"
|
|
10643
|
+
}
|
|
10644
|
+
),
|
|
9542
10645
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9543
10646
|
"button",
|
|
9544
10647
|
{
|
|
9545
10648
|
className: "pollar-wallet-dropdown-item",
|
|
9546
|
-
|
|
9547
|
-
|
|
10649
|
+
onClick: () => {
|
|
10650
|
+
setSelfCustodyNotice(false);
|
|
10651
|
+
setRisksAccepted(false);
|
|
10652
|
+
},
|
|
9548
10653
|
disabled: creatingWallet,
|
|
9549
|
-
children:
|
|
10654
|
+
children: "Back"
|
|
9550
10655
|
}
|
|
9551
10656
|
),
|
|
9552
10657
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
9553
10658
|
] }),
|
|
9554
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-wallet-dropdown-item",
|
|
10659
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-wallet-dropdown-item", onClick: onSessions, children: "Active sessions" }),
|
|
9555
10660
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" }),
|
|
9556
10661
|
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-wallet-dropdown-item pollar-danger", onClick: onLogout, children: "Log out" })
|
|
9557
10662
|
] })
|
|
9558
10663
|
] });
|
|
9559
10664
|
}
|
|
9560
10665
|
if (!walletAddress) {
|
|
9561
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "pollar-wallet-login-btn", style:
|
|
9562
|
-
/* @__PURE__ */ jsxRuntime.jsx(ButtonLogo, {}),
|
|
10666
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "pollar-wallet-login-btn", style: cssVars, onClick: onLogin, children: [
|
|
10667
|
+
/* @__PURE__ */ jsxRuntime.jsx(ButtonLogo, { accentColor }),
|
|
9563
10668
|
"Login with Pollar"
|
|
9564
10669
|
] });
|
|
9565
10670
|
}
|
|
9566
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-wrapper", ref: wrapperRef, children: [
|
|
10671
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-wrapper", ref: wrapperRef, style: cssVars, children: [
|
|
9567
10672
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9568
10673
|
"button",
|
|
9569
10674
|
{
|
|
9570
10675
|
className: "pollar-wallet-btn",
|
|
9571
|
-
style: { backgroundColor: accentColor },
|
|
9572
10676
|
onClick: isInProgress ? void 0 : onToggleOpen,
|
|
9573
10677
|
disabled: isInProgress,
|
|
9574
10678
|
"aria-busy": isInProgress,
|
|
@@ -9605,46 +10709,41 @@ function WalletButtonTemplate({
|
|
|
9605
10709
|
]
|
|
9606
10710
|
}
|
|
9607
10711
|
),
|
|
9608
|
-
open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-dropdown",
|
|
10712
|
+
open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-dropdown", children: [
|
|
10713
|
+
recoveryLocked && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10714
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice pollar-danger", role: "alert", children: "Locked: add a way to recover this wallet before sending or receiving. If you lose this device without one, the funds are lost." }),
|
|
10715
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
10716
|
+
] }),
|
|
9609
10717
|
notReadyReason && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9610
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice",
|
|
10718
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice", role: "status", children: notReadyReason }),
|
|
9611
10719
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
9612
10720
|
] }),
|
|
9613
10721
|
showCreateAccount && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9614
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9615
|
-
|
|
9616
|
-
|
|
9617
|
-
|
|
9618
|
-
|
|
9619
|
-
|
|
9620
|
-
|
|
9621
|
-
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
|
|
9625
|
-
|
|
9626
|
-
|
|
9627
|
-
|
|
9628
|
-
|
|
9629
|
-
|
|
9630
|
-
|
|
9631
|
-
|
|
9632
|
-
|
|
9633
|
-
|
|
9634
|
-
|
|
9635
|
-
|
|
9636
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "19", y1: "8", x2: "19", y2: "14" }),
|
|
9637
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "22", y1: "11", x2: "16", y2: "11" })
|
|
9638
|
-
]
|
|
9639
|
-
}
|
|
9640
|
-
),
|
|
9641
|
-
creatingAccount ? "Creating account\u2026" : "Create account"
|
|
9642
|
-
]
|
|
9643
|
-
}
|
|
9644
|
-
),
|
|
10722
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item", onClick: onCreateAccount, disabled: creatingAccount, children: [
|
|
10723
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10724
|
+
"svg",
|
|
10725
|
+
{
|
|
10726
|
+
width: "14",
|
|
10727
|
+
height: "14",
|
|
10728
|
+
viewBox: "0 0 24 24",
|
|
10729
|
+
fill: "none",
|
|
10730
|
+
stroke: "currentColor",
|
|
10731
|
+
strokeWidth: "2",
|
|
10732
|
+
strokeLinecap: "round",
|
|
10733
|
+
strokeLinejoin: "round",
|
|
10734
|
+
children: [
|
|
10735
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2" }),
|
|
10736
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "7", r: "4" }),
|
|
10737
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "19", y1: "8", x2: "19", y2: "14" }),
|
|
10738
|
+
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "22", y1: "11", x2: "16", y2: "11" })
|
|
10739
|
+
]
|
|
10740
|
+
}
|
|
10741
|
+
),
|
|
10742
|
+
creatingAccount ? "Creating account\u2026" : "Create account"
|
|
10743
|
+
] }),
|
|
9645
10744
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
9646
10745
|
] }),
|
|
9647
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item",
|
|
10746
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item", onClick: onSend, children: [
|
|
9648
10747
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9649
10748
|
"svg",
|
|
9650
10749
|
{
|
|
@@ -9664,7 +10763,7 @@ function WalletButtonTemplate({
|
|
|
9664
10763
|
),
|
|
9665
10764
|
"Send"
|
|
9666
10765
|
] }),
|
|
9667
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item",
|
|
10766
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item", onClick: onReceive, children: [
|
|
9668
10767
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9669
10768
|
"svg",
|
|
9670
10769
|
{
|
|
@@ -9686,7 +10785,7 @@ function WalletButtonTemplate({
|
|
|
9686
10785
|
"Receive"
|
|
9687
10786
|
] }),
|
|
9688
10787
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" }),
|
|
9689
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item",
|
|
10788
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item", onClick: onCopy, children: [
|
|
9690
10789
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9691
10790
|
"svg",
|
|
9692
10791
|
{
|
|
@@ -9706,7 +10805,7 @@ function WalletButtonTemplate({
|
|
|
9706
10805
|
),
|
|
9707
10806
|
copied ? "Copied!" : "Copy address"
|
|
9708
10807
|
] }),
|
|
9709
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item",
|
|
10808
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item", onClick: onWalletBalance, children: [
|
|
9710
10809
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9711
10810
|
"svg",
|
|
9712
10811
|
{
|
|
@@ -9727,7 +10826,7 @@ function WalletButtonTemplate({
|
|
|
9727
10826
|
),
|
|
9728
10827
|
"Wallet balance"
|
|
9729
10828
|
] }),
|
|
9730
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item",
|
|
10829
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item", onClick: onTxHistory, children: [
|
|
9731
10830
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9732
10831
|
"svg",
|
|
9733
10832
|
{
|
|
@@ -9751,7 +10850,7 @@ function WalletButtonTemplate({
|
|
|
9751
10850
|
"Transaction history"
|
|
9752
10851
|
] }),
|
|
9753
10852
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" }),
|
|
9754
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item",
|
|
10853
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item", onClick: onRamp, children: [
|
|
9755
10854
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9756
10855
|
"svg",
|
|
9757
10856
|
{
|
|
@@ -9773,7 +10872,7 @@ function WalletButtonTemplate({
|
|
|
9773
10872
|
),
|
|
9774
10873
|
"Buy / Sell"
|
|
9775
10874
|
] }),
|
|
9776
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item",
|
|
10875
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item", onClick: onKyc, children: [
|
|
9777
10876
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9778
10877
|
"svg",
|
|
9779
10878
|
{
|
|
@@ -9794,7 +10893,7 @@ function WalletButtonTemplate({
|
|
|
9794
10893
|
),
|
|
9795
10894
|
"Identity verification"
|
|
9796
10895
|
] }),
|
|
9797
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item",
|
|
10896
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item", onClick: onDistributionRules, children: [
|
|
9798
10897
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9799
10898
|
"svg",
|
|
9800
10899
|
{
|
|
@@ -9817,7 +10916,7 @@ function WalletButtonTemplate({
|
|
|
9817
10916
|
),
|
|
9818
10917
|
"Distribution rules"
|
|
9819
10918
|
] }),
|
|
9820
|
-
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item",
|
|
10919
|
+
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item", onClick: onSessions, children: [
|
|
9821
10920
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9822
10921
|
"svg",
|
|
9823
10922
|
{
|
|
@@ -9838,6 +10937,23 @@ function WalletButtonTemplate({
|
|
|
9838
10937
|
),
|
|
9839
10938
|
"Active sessions"
|
|
9840
10939
|
] }),
|
|
10940
|
+
onRecovery && /* @__PURE__ */ jsxRuntime.jsxs("button", { className: `pollar-wallet-dropdown-item${recoveryLocked ? " pollar-danger" : ""}`, onClick: onRecovery, children: [
|
|
10941
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10942
|
+
"svg",
|
|
10943
|
+
{
|
|
10944
|
+
width: "14",
|
|
10945
|
+
height: "14",
|
|
10946
|
+
viewBox: "0 0 24 24",
|
|
10947
|
+
fill: "none",
|
|
10948
|
+
stroke: "currentColor",
|
|
10949
|
+
strokeWidth: "2",
|
|
10950
|
+
strokeLinecap: "round",
|
|
10951
|
+
strokeLinejoin: "round",
|
|
10952
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2 4 5v6c0 5 3.4 9.3 8 11 4.6-1.7 8-6 8-11V5l-8-3z" })
|
|
10953
|
+
}
|
|
10954
|
+
),
|
|
10955
|
+
recoveryLocked ? "Set up wallet recovery" : "Wallet recovery"
|
|
10956
|
+
] }),
|
|
9841
10957
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" }),
|
|
9842
10958
|
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item pollar-danger", onClick: onLogout, children: [
|
|
9843
10959
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -9880,7 +10996,10 @@ function WalletButton() {
|
|
|
9880
10996
|
tx: transaction,
|
|
9881
10997
|
isAuthenticated,
|
|
9882
10998
|
createWallet,
|
|
9883
|
-
appConfig
|
|
10999
|
+
appConfig,
|
|
11000
|
+
recovery,
|
|
11001
|
+
recoveryLocked,
|
|
11002
|
+
openRecoveryModal
|
|
9884
11003
|
} = usePollar();
|
|
9885
11004
|
const { primaryChain, primaryAddress } = useChains();
|
|
9886
11005
|
const walletAddress = primaryAddress || (wallet?.address ?? "");
|
|
@@ -9895,11 +11014,7 @@ function WalletButton() {
|
|
|
9895
11014
|
const isInProgress = transaction.step === "building" || transaction.step === "signing";
|
|
9896
11015
|
const canCreateAccount = !created && wallet?.custody === "external" && wallet.existsOnStellar === false && wallet.fundingMode === "IMMEDIATE";
|
|
9897
11016
|
const notReadyReason = walletNotReadyReason(wallet, primaryChain);
|
|
9898
|
-
const { theme
|
|
9899
|
-
const isDark = theme === "dark";
|
|
9900
|
-
const dropdownBg = isDark ? "#18181b" : "#fff";
|
|
9901
|
-
const dropdownBorder = isDark ? "#3f3f46" : "#e4e4e7";
|
|
9902
|
-
const itemColor = isDark ? "#fafafa" : "#18181b";
|
|
11017
|
+
const { theme, accentColor, styleOverrides } = modalChrome(styles);
|
|
9903
11018
|
react.useEffect(() => {
|
|
9904
11019
|
function handleClickOutside(e) {
|
|
9905
11020
|
if (wrapperRef.current && !wrapperRef.current.contains(e.target)) {
|
|
@@ -9943,12 +11058,12 @@ function WalletButton() {
|
|
|
9943
11058
|
setCreating(false);
|
|
9944
11059
|
}
|
|
9945
11060
|
}
|
|
9946
|
-
async function handleCreateWallet() {
|
|
11061
|
+
async function handleCreateWallet(custody) {
|
|
9947
11062
|
if (creatingWallet) return;
|
|
9948
11063
|
setCreatingWallet(true);
|
|
9949
11064
|
setCreateWalletError(null);
|
|
9950
11065
|
try {
|
|
9951
|
-
await createWallet();
|
|
11066
|
+
await createWallet(custody ? { custody } : void 0);
|
|
9952
11067
|
setOpen(false);
|
|
9953
11068
|
} catch (err) {
|
|
9954
11069
|
setCreateWalletError(
|
|
@@ -9978,6 +11093,10 @@ function WalletButton() {
|
|
|
9978
11093
|
setOpen(false);
|
|
9979
11094
|
openSessionsModal();
|
|
9980
11095
|
}
|
|
11096
|
+
function handleRecovery() {
|
|
11097
|
+
setOpen(false);
|
|
11098
|
+
openRecoveryModal();
|
|
11099
|
+
}
|
|
9981
11100
|
function handleKyc() {
|
|
9982
11101
|
setOpen(false);
|
|
9983
11102
|
openKycModal();
|
|
@@ -9994,18 +11113,18 @@ function WalletButton() {
|
|
|
9994
11113
|
WalletButtonTemplate,
|
|
9995
11114
|
{
|
|
9996
11115
|
walletAddress: walletAddress ?? null,
|
|
11116
|
+
theme,
|
|
9997
11117
|
accentColor,
|
|
11118
|
+
styleOverrides,
|
|
9998
11119
|
open,
|
|
9999
11120
|
copied,
|
|
10000
|
-
dropdownBg,
|
|
10001
|
-
dropdownBorder,
|
|
10002
|
-
itemColor,
|
|
10003
11121
|
wrapperRef,
|
|
10004
11122
|
isInProgress,
|
|
10005
11123
|
showCreateAccount: canCreateAccount,
|
|
10006
11124
|
signedIn: isAuthenticated,
|
|
10007
11125
|
creatingWallet,
|
|
10008
11126
|
createWalletError,
|
|
11127
|
+
custodyChoice: appConfig.application?.walletCustodyMode === "USER_CHOICE",
|
|
10009
11128
|
...appConfig.application?.walletProvisioning === "NONE" ? {} : { onCreateWallet: handleCreateWallet },
|
|
10010
11129
|
notReadyReason,
|
|
10011
11130
|
creatingAccount: creating,
|
|
@@ -10017,6 +11136,8 @@ function WalletButton() {
|
|
|
10017
11136
|
onSend: handleSend,
|
|
10018
11137
|
onReceive: handleReceive,
|
|
10019
11138
|
onSessions: handleSessions,
|
|
11139
|
+
recoveryLocked,
|
|
11140
|
+
...recovery?.required ? { onRecovery: handleRecovery } : {},
|
|
10020
11141
|
onKyc: handleKyc,
|
|
10021
11142
|
onRamp: handleRamp,
|
|
10022
11143
|
onDistributionRules: handleDistributionRules,
|
|
@@ -10030,6 +11151,8 @@ exports.CardModal = CardModal;
|
|
|
10030
11151
|
exports.ChainSelect = ChainSelect;
|
|
10031
11152
|
exports.CosignModal = CosignModal;
|
|
10032
11153
|
exports.CosignModalTemplate = CosignModalTemplate;
|
|
11154
|
+
exports.CustodyMigrationModal = CustodyMigrationModal;
|
|
11155
|
+
exports.CustodyMigrationModalTemplate = CustodyMigrationModalTemplate;
|
|
10033
11156
|
exports.DistributionRulesModal = DistributionRulesModal;
|
|
10034
11157
|
exports.DistributionRulesModalTemplate = DistributionRulesModalTemplate;
|
|
10035
11158
|
exports.EarnModal = EarnModal;
|
|
@@ -10045,7 +11168,10 @@ exports.RampWidget = RampWidget;
|
|
|
10045
11168
|
exports.RampWidgetTemplate = RampWidgetTemplate;
|
|
10046
11169
|
exports.ReceiveModal = ReceiveModal;
|
|
10047
11170
|
exports.ReceiveModalTemplate = ReceiveModalTemplate;
|
|
11171
|
+
exports.RecoveryModal = RecoveryModal;
|
|
11172
|
+
exports.RecoveryModalTemplate = RecoveryModalTemplate;
|
|
10048
11173
|
exports.RegistryCheckModal = RegistryCheckModal;
|
|
11174
|
+
exports.RejectedRouteDisplay = RejectedRouteDisplay;
|
|
10049
11175
|
exports.RequirementFormModal = RequirementFormModal;
|
|
10050
11176
|
exports.RouteDisplay = RouteDisplay;
|
|
10051
11177
|
exports.SendModal = SendModal;
|
|
@@ -10064,6 +11190,7 @@ exports.WalletButtonTemplate = WalletButtonTemplate;
|
|
|
10064
11190
|
exports.addressForChain = addressForChain;
|
|
10065
11191
|
exports.browserPasskeyCeremony = browserPasskeyCeremony;
|
|
10066
11192
|
exports.browserPasskeySigner = browserPasskeySigner;
|
|
11193
|
+
exports.browserRecoveryPasskey = browserRecoveryPasskey;
|
|
10067
11194
|
exports.buildModalCssVars = buildModalCssVars;
|
|
10068
11195
|
exports.chainsOf = chainsOf;
|
|
10069
11196
|
exports.createPollarAdapterHook = createPollarAdapterHook;
|