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