@pollar/react 0.11.4 → 0.12.0-rc.2
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 +9 -2
- package/dist/index.css +390 -32
- package/dist/index.css.map +1 -1
- package/dist/index.d.mts +264 -11
- package/dist/index.d.ts +264 -11
- package/dist/index.js +1949 -186
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1942 -188
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1002,6 +1002,10 @@ var require_QRCode = __commonJS({
|
|
|
1002
1002
|
|
|
1003
1003
|
// src/constants.ts
|
|
1004
1004
|
var LOGO_POLLAR = "https://pollar.xyz/assets/logo_pollar.png";
|
|
1005
|
+
var LOGO_POLLAR_WORDMARK_ON_LIGHT = "https://www.pollar.xyz/brandkit/pollar-logo-horizontal-on-light.png";
|
|
1006
|
+
var LOGO_POLLAR_WORDMARK_ON_DARK = "https://www.pollar.xyz/brandkit/pollar-logo-horizontal-on-dark.png";
|
|
1007
|
+
var LOGO_POLLAR_MARK_ON_LIGHT = "https://www.pollar.xyz/brandkit/pollar-mark-on-light.png";
|
|
1008
|
+
var LOGO_POLLAR_MARK_ON_DARK = "https://www.pollar.xyz/brandkit/pollar-mark-on-dark.png";
|
|
1005
1009
|
var LOGO_FREIGHTER = "https://pollar.xyz/assets/logo_freighter.png";
|
|
1006
1010
|
var LOGO_ALBEDO = "https://pollar.xyz/assets/logo_albedo.svg";
|
|
1007
1011
|
var _modalLog = console;
|
|
@@ -1027,22 +1031,26 @@ var ModalErrorBoundary = class extends react.Component {
|
|
|
1027
1031
|
return this.props.children;
|
|
1028
1032
|
}
|
|
1029
1033
|
};
|
|
1030
|
-
var PollarModalFooter = (
|
|
1034
|
+
var PollarModalFooter = () => {
|
|
1031
1035
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-footer", children: [
|
|
1032
1036
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-protected", children: "Protected by" }),
|
|
1033
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
|
|
1039
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-footer-version", children: [
|
|
1040
|
-
"v",
|
|
1041
|
-
"0.11.4"
|
|
1042
|
-
] })
|
|
1037
|
+
/* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR_WORDMARK_ON_LIGHT, alt: "Pollar", className: "pollar-footer-logo pollar-logo-on-light" }),
|
|
1038
|
+
/* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR_WORDMARK_ON_DARK, alt: "Pollar", className: "pollar-footer-logo pollar-logo-on-dark" }),
|
|
1039
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-footer-version", children: [
|
|
1040
|
+
"v",
|
|
1041
|
+
"0.12.0-rc.2"
|
|
1043
1042
|
] })
|
|
1044
1043
|
] });
|
|
1045
1044
|
};
|
|
1045
|
+
function explorerTxUrl(chain, hash, network) {
|
|
1046
|
+
if (chain === "SOLANA") {
|
|
1047
|
+
return `https://explorer.solana.com/tx/${hash}${network === "testnet" ? "?cluster=devnet" : ""}`;
|
|
1048
|
+
}
|
|
1049
|
+
if (chain === "POLYGON") {
|
|
1050
|
+
return `https://${network === "testnet" ? "amoy." : ""}polygonscan.com/tx/${hash}`;
|
|
1051
|
+
}
|
|
1052
|
+
return `https://stellar.expert/explorer/${network === "testnet" ? "testnet" : "public"}/tx/${hash}`;
|
|
1053
|
+
}
|
|
1046
1054
|
function RefreshIcon({ spinning = false, className = "" }) {
|
|
1047
1055
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1048
1056
|
"svg",
|
|
@@ -1234,6 +1242,8 @@ function buildModalCssVars(theme, accentColor, overrides = {}, variant = "compac
|
|
|
1234
1242
|
"--pollar-error-border": isDark ? "#7f1d1d" : "#fecaca",
|
|
1235
1243
|
"--pollar-error-text": isDark ? "#f87171" : "#dc2626",
|
|
1236
1244
|
"--pollar-success-text": isDark ? "#4ade80" : "#16a34a",
|
|
1245
|
+
"--pollar-logo-on-light-display": isDark ? "none" : "block",
|
|
1246
|
+
"--pollar-logo-on-dark-display": isDark ? "block" : "none",
|
|
1237
1247
|
"--pollar-modal-border-radius": px(overrides.modalBorderRadius, DEFAULT_MODAL_BORDER_RADIUS),
|
|
1238
1248
|
"--pollar-buttons-border-radius": px(overrides.buttonBorderRadius, DEFAULT_BUTTON_BORDER_RADIUS),
|
|
1239
1249
|
"--pollar-buttons-height": "44px",
|
|
@@ -1905,7 +1915,7 @@ function KycStatus({ status, label, className }) {
|
|
|
1905
1915
|
|
|
1906
1916
|
// src/components/kyc-modal/kyc-messages.ts
|
|
1907
1917
|
function kycErrorMessage(error, phase) {
|
|
1908
|
-
const code = error
|
|
1918
|
+
const code = typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
1909
1919
|
switch (code) {
|
|
1910
1920
|
case "SDK_KYC_NOT_CONFIGURED":
|
|
1911
1921
|
return "Identity verification is not available for this app yet.";
|
|
@@ -2150,7 +2160,13 @@ function KycModal({
|
|
|
2150
2160
|
finish("approved");
|
|
2151
2161
|
return;
|
|
2152
2162
|
}
|
|
2153
|
-
|
|
2163
|
+
const { sessionId } = result;
|
|
2164
|
+
if (sessionId === void 0) throw new Error("The KYC provider answered without a session.");
|
|
2165
|
+
setSession({
|
|
2166
|
+
sessionId,
|
|
2167
|
+
...result.kycUrl !== void 0 ? { kycUrl: result.kycUrl } : {},
|
|
2168
|
+
...result.fields !== void 0 ? { fields: result.fields } : {}
|
|
2169
|
+
});
|
|
2154
2170
|
setStep("verifying");
|
|
2155
2171
|
} catch (e) {
|
|
2156
2172
|
const code = core.isPollarApiError(e) ? e.code : void 0;
|
|
@@ -2337,10 +2353,14 @@ function fieldErrorMessage(code, language) {
|
|
|
2337
2353
|
}
|
|
2338
2354
|
function fieldErrorsOf(error) {
|
|
2339
2355
|
if (!error || typeof error !== "object") return null;
|
|
2340
|
-
|
|
2341
|
-
|
|
2356
|
+
if (!("code" in error) || error.code !== "KYC_FORM_INVALID_ANSWERS") return null;
|
|
2357
|
+
const body = "body" in error ? error.body : void 0;
|
|
2358
|
+
const list = typeof body === "object" && body !== null && "errors" in body ? body.errors : void 0;
|
|
2359
|
+
if (!Array.isArray(list)) return null;
|
|
2360
|
+
const items = list;
|
|
2342
2361
|
const errors = {};
|
|
2343
|
-
for (const item of
|
|
2362
|
+
for (const item of items) {
|
|
2363
|
+
if (typeof item !== "object" || item === null || !("key" in item) || !("code" in item)) continue;
|
|
2344
2364
|
if (typeof item.key === "string" && typeof item.code === "string") errors[item.key] = item.code;
|
|
2345
2365
|
}
|
|
2346
2366
|
return Object.keys(errors).length ? errors : null;
|
|
@@ -3239,7 +3259,11 @@ function LoginModal({ onClose }) {
|
|
|
3239
3259
|
const [email, setEmail] = react.useState("");
|
|
3240
3260
|
const { getClient, styles, appConfig: config, configStatus, retryConfig } = usePollar();
|
|
3241
3261
|
const [authState, setAuthState] = react.useState(() => getClient().getAuthState());
|
|
3242
|
-
const
|
|
3262
|
+
const servedChains = config?.application?.chains;
|
|
3263
|
+
const walletAdapters = react.useMemo(
|
|
3264
|
+
() => getClient().listWalletAdapters().filter((a) => !servedChains || servedChains.includes(a.chain)),
|
|
3265
|
+
[getClient, servedChains]
|
|
3266
|
+
);
|
|
3243
3267
|
const [codeInputKey, setCodeInputKey] = react.useState(0);
|
|
3244
3268
|
const pendingEmail = react.useRef(null);
|
|
3245
3269
|
const [interactiveAdapter, setInteractiveAdapter] = react.useState(null);
|
|
@@ -3386,13 +3410,200 @@ function LoginModal({ onClose }) {
|
|
|
3386
3410
|
) });
|
|
3387
3411
|
}
|
|
3388
3412
|
|
|
3413
|
+
// src/lib/qr-code/index.tsx
|
|
3414
|
+
var import_ErrorCorrectLevel = __toESM(require_ErrorCorrectLevel());
|
|
3415
|
+
var import_QRCode = __toESM(require_QRCode());
|
|
3416
|
+
var QRCodeSvg = react.forwardRef(function QRCodeSvg2({ bgColor, bgD, fgD, fgColor, size, title, viewBoxSize, xmlns = "http://www.w3.org/2000/svg", ...props }, ref) {
|
|
3417
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...props, height: size, ref, viewBox: `0 0 ${viewBoxSize} ${viewBoxSize}`, width: size, xmlns, children: [
|
|
3418
|
+
title ? /* @__PURE__ */ jsxRuntime.jsx("title", { children: title }) : null,
|
|
3419
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: bgD, fill: bgColor }),
|
|
3420
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: fgD, fill: fgColor })
|
|
3421
|
+
] });
|
|
3422
|
+
});
|
|
3423
|
+
QRCodeSvg.displayName = "QRCodeSvg";
|
|
3424
|
+
function bytesToBinaryString(bytes) {
|
|
3425
|
+
return bytes.map((b) => String.fromCharCode(b & 255)).join("");
|
|
3426
|
+
}
|
|
3427
|
+
function encodeStringToUtf8Bytes(input) {
|
|
3428
|
+
return Array.from(new TextEncoder().encode(input));
|
|
3429
|
+
}
|
|
3430
|
+
var QRCode = react.forwardRef(function QRCode2({ bgColor = "#FFFFFF", fgColor = "#000000", level = "L", size = 256, value, ...props }, ref) {
|
|
3431
|
+
const qrcode = new import_QRCode.default(-1, import_ErrorCorrectLevel.default[level]);
|
|
3432
|
+
const utf8Bytes = encodeStringToUtf8Bytes(value);
|
|
3433
|
+
const binaryString = bytesToBinaryString(utf8Bytes);
|
|
3434
|
+
qrcode.addData(binaryString, "Byte");
|
|
3435
|
+
qrcode.make();
|
|
3436
|
+
const cells = qrcode.modules;
|
|
3437
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3438
|
+
QRCodeSvg,
|
|
3439
|
+
{
|
|
3440
|
+
...props,
|
|
3441
|
+
bgColor,
|
|
3442
|
+
bgD: cells.map(
|
|
3443
|
+
(row, rowIndex) => row.map((cell, cellIndex) => !cell ? `M ${cellIndex} ${rowIndex} l 1 0 0 1 -1 0 Z` : "").join(" ")
|
|
3444
|
+
).join(" "),
|
|
3445
|
+
fgColor,
|
|
3446
|
+
fgD: cells.map(
|
|
3447
|
+
(row, rowIndex) => row.map((cell, cellIndex) => cell ? `M ${cellIndex} ${rowIndex} l 1 0 0 1 -1 0 Z` : "").join(" ")
|
|
3448
|
+
).join(" "),
|
|
3449
|
+
ref,
|
|
3450
|
+
size,
|
|
3451
|
+
viewBoxSize: cells.length
|
|
3452
|
+
}
|
|
3453
|
+
);
|
|
3454
|
+
});
|
|
3455
|
+
function RampWorkflow({
|
|
3456
|
+
client,
|
|
3457
|
+
snapshot,
|
|
3458
|
+
onChange,
|
|
3459
|
+
onBusyChange
|
|
3460
|
+
}) {
|
|
3461
|
+
const model = core.describeRampAction(snapshot);
|
|
3462
|
+
const locked = react.useRef(false);
|
|
3463
|
+
react.useEffect(() => {
|
|
3464
|
+
setFields({});
|
|
3465
|
+
setError(null);
|
|
3466
|
+
}, [model.action?.actionId]);
|
|
3467
|
+
const [busy, setBusy] = react.useState(false);
|
|
3468
|
+
const [error, setError] = react.useState(null);
|
|
3469
|
+
const [fields, setFields] = react.useState({});
|
|
3470
|
+
const fieldsComplete = model.action?.kind !== "collect_information" || model.action.fields.every((field) => {
|
|
3471
|
+
const value = (fields[field.key] ?? "").trim();
|
|
3472
|
+
if (!value) return field.optional;
|
|
3473
|
+
if (field.type === "email") return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
|
3474
|
+
return field.type !== "select" || field.options?.some((option) => option.value === value);
|
|
3475
|
+
});
|
|
3476
|
+
async function continueAction() {
|
|
3477
|
+
if (!model.action || locked.current || !fieldsComplete) return;
|
|
3478
|
+
locked.current = true;
|
|
3479
|
+
setBusy(true);
|
|
3480
|
+
onBusyChange?.(true);
|
|
3481
|
+
setError(null);
|
|
3482
|
+
try {
|
|
3483
|
+
onChange(
|
|
3484
|
+
model.canSign ? await client.signRampAction(snapshot.txId, snapshot) : await client.continueRamp(snapshot.txId, {
|
|
3485
|
+
actionId: model.action.actionId,
|
|
3486
|
+
transactionVersion: snapshot.transactionVersion,
|
|
3487
|
+
...model.action.kind === "collect_information" ? { fields } : {}
|
|
3488
|
+
})
|
|
3489
|
+
);
|
|
3490
|
+
} catch (e) {
|
|
3491
|
+
setError(e instanceof Error ? e.message : "Unable to continue.");
|
|
3492
|
+
} finally {
|
|
3493
|
+
locked.current = false;
|
|
3494
|
+
setBusy(false);
|
|
3495
|
+
onBusyChange?.(false);
|
|
3496
|
+
}
|
|
3497
|
+
}
|
|
3498
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3499
|
+
"section",
|
|
3500
|
+
{
|
|
3501
|
+
className: "pollar-ramp-payment pollar-ramp-workflow",
|
|
3502
|
+
"aria-label": "Ramp progress",
|
|
3503
|
+
"aria-live": "polite",
|
|
3504
|
+
"aria-busy": busy,
|
|
3505
|
+
children: [
|
|
3506
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "pollar-ramp-payment-title", children: model.title }),
|
|
3507
|
+
snapshot.terms && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-ramp-terms", children: [
|
|
3508
|
+
snapshot.terms.fiatAmount,
|
|
3509
|
+
" ",
|
|
3510
|
+
snapshot.terms.fiatCurrency,
|
|
3511
|
+
" \xB7 ",
|
|
3512
|
+
snapshot.terms.cryptoAmount,
|
|
3513
|
+
" ",
|
|
3514
|
+
snapshot.terms.assetCode,
|
|
3515
|
+
/* @__PURE__ */ jsxRuntime.jsx("br", {}),
|
|
3516
|
+
"Includes ",
|
|
3517
|
+
snapshot.terms.feeAmount,
|
|
3518
|
+
" ",
|
|
3519
|
+
snapshot.terms.feeCurrency,
|
|
3520
|
+
" fee"
|
|
3521
|
+
] }),
|
|
3522
|
+
model.details.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-ramp-workflow-detail", children: [
|
|
3523
|
+
/* @__PURE__ */ jsxRuntime.jsxs("strong", { children: [
|
|
3524
|
+
item.label,
|
|
3525
|
+
": "
|
|
3526
|
+
] }),
|
|
3527
|
+
item.value
|
|
3528
|
+
] }, index)),
|
|
3529
|
+
model.links.map((link, index) => /* @__PURE__ */ jsxRuntime.jsx("p", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { className: "pollar-btn-primary pollar-ramp-hosted-link", href: link.url, target: "_blank", rel: "noopener noreferrer", children: link.label }) }, index)),
|
|
3530
|
+
model.qr && /* @__PURE__ */ jsxRuntime.jsx(QRCode, { value: model.qr, size: 180 }),
|
|
3531
|
+
model.qr && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3532
|
+
"button",
|
|
3533
|
+
{
|
|
3534
|
+
className: "pollar-btn-secondary",
|
|
3535
|
+
type: "button",
|
|
3536
|
+
onClick: () => void navigator.clipboard.writeText(model.qr).catch(() => setError("Unable to copy. Select the payment code to copy it manually.")),
|
|
3537
|
+
children: "Copy payment code"
|
|
3538
|
+
}
|
|
3539
|
+
),
|
|
3540
|
+
model.action?.kind === "collect_information" && model.action.fields.map((field) => /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-ramp-field", children: [
|
|
3541
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-ramp-label", children: [
|
|
3542
|
+
field.label,
|
|
3543
|
+
field.optional ? " (optional)" : ""
|
|
3544
|
+
] }),
|
|
3545
|
+
field.type === "select" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3546
|
+
"select",
|
|
3547
|
+
{
|
|
3548
|
+
className: "pollar-ramp-input",
|
|
3549
|
+
disabled: busy,
|
|
3550
|
+
value: fields[field.key] ?? "",
|
|
3551
|
+
onChange: (e) => setFields((previous) => ({ ...previous, [field.key]: e.target.value })),
|
|
3552
|
+
children: [
|
|
3553
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Choose" }),
|
|
3554
|
+
field.options?.map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: option.value, children: option.label }, option.value))
|
|
3555
|
+
]
|
|
3556
|
+
}
|
|
3557
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3558
|
+
"input",
|
|
3559
|
+
{
|
|
3560
|
+
className: "pollar-ramp-input",
|
|
3561
|
+
disabled: busy,
|
|
3562
|
+
type: field.type,
|
|
3563
|
+
placeholder: field.placeholder,
|
|
3564
|
+
value: fields[field.key] ?? "",
|
|
3565
|
+
onChange: (e) => setFields((previous) => ({ ...previous, [field.key]: e.target.value }))
|
|
3566
|
+
}
|
|
3567
|
+
),
|
|
3568
|
+
field.hint && /* @__PURE__ */ jsxRuntime.jsx("small", { className: "pollar-ramp-field-hint", children: field.hint })
|
|
3569
|
+
] }, field.key)),
|
|
3570
|
+
(model.canContinue || model.canSign) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3571
|
+
"button",
|
|
3572
|
+
{
|
|
3573
|
+
className: "pollar-btn-primary",
|
|
3574
|
+
type: "button",
|
|
3575
|
+
disabled: busy || !fieldsComplete,
|
|
3576
|
+
onClick: () => void continueAction(),
|
|
3577
|
+
children: busy ? model.canSign ? "Waiting for your wallet\u2026" : "Continuing\u2026" : model.canSign ? "Authorize" : "Continue"
|
|
3578
|
+
}
|
|
3579
|
+
),
|
|
3580
|
+
snapshot.milestones?.map((milestone, index) => /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
|
|
3581
|
+
milestone.kind.replace(/_/g, " "),
|
|
3582
|
+
" \xB7 ",
|
|
3583
|
+
milestone.verifiedAt
|
|
3584
|
+
] }, index)),
|
|
3585
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-field-error", role: "alert", children: error }),
|
|
3586
|
+
/* @__PURE__ */ jsxRuntime.jsxs("small", { className: "pollar-ramp-reference", children: [
|
|
3587
|
+
"Reference: ",
|
|
3588
|
+
snapshot.txId
|
|
3589
|
+
] })
|
|
3590
|
+
]
|
|
3591
|
+
}
|
|
3592
|
+
);
|
|
3593
|
+
}
|
|
3594
|
+
|
|
3389
3595
|
// src/components/ramp-widget/ramp-kyc.ts
|
|
3390
3596
|
var nonEmpty = (value) => typeof value === "string" && !!value.trim();
|
|
3391
3597
|
function requiredRampKyc(error) {
|
|
3392
3598
|
if (!error || typeof error !== "object") return null;
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3599
|
+
if (!("code" in error) || error.code !== "SDK_RAMPS_KYC_REQUIRED") return null;
|
|
3600
|
+
const body = "body" in error ? error.body : void 0;
|
|
3601
|
+
if (typeof body !== "object" || body === null) return null;
|
|
3602
|
+
const rampProviderId = "rampProviderId" in body ? body.rampProviderId : void 0;
|
|
3603
|
+
const corridorId = "corridorId" in body ? body.corridorId : void 0;
|
|
3604
|
+
const requirementType = "requirementType" in body ? body.requirementType : void 0;
|
|
3605
|
+
const optionId = "optionId" in body ? body.optionId : void 0;
|
|
3606
|
+
const kycProviderId = "kycProviderId" in body ? body.kycProviderId : void 0;
|
|
3396
3607
|
if (!nonEmpty(rampProviderId) || !nonEmpty(corridorId)) return null;
|
|
3397
3608
|
if ((requirementType === "FORM" || requirementType === "REGISTRY_CHECK" || requirementType === "PROVIDER_REGISTRATION") && nonEmpty(optionId)) {
|
|
3398
3609
|
return { rampProviderId, corridorId, type: requirementType, optionId };
|
|
@@ -3459,13 +3670,14 @@ function RouteDisplay({ quote, busy = false, disabled = false, onSelect }) {
|
|
|
3459
3670
|
children: [
|
|
3460
3671
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-route-left", children: [
|
|
3461
3672
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-provider", children: quote.provider }),
|
|
3462
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-meta", children: busy ? "Starting\u2026" :
|
|
3673
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-meta", children: busy ? "Starting\u2026" : [
|
|
3674
|
+
quote.route ? `${quote.route.asset.code} on ${quote.route.asset.chain}` : null,
|
|
3675
|
+
RAIL_LABELS[quote.rail] ?? quote.rail,
|
|
3676
|
+
quote.estimatedTime
|
|
3677
|
+
].filter(Boolean).join(" \xB7 ") })
|
|
3463
3678
|
] }),
|
|
3464
3679
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-route-right", children: busy ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3465
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3466
|
-
quote.fee,
|
|
3467
|
-
"% fee"
|
|
3468
|
-
] }),
|
|
3680
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-fee", children: quote.terms ? `${quote.terms.fiatAmount} ${quote.terms.fiatCurrency} \xB7 ${quote.terms.cryptoAmount} ${quote.terms.assetCode} \xB7 Includes ${quote.terms.feeAmount} ${quote.terms.feeCurrency}` : `${quote.fee}% fee` }),
|
|
3469
3681
|
quote.recommended && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-route-badge", children: "Best rate" })
|
|
3470
3682
|
] }) })
|
|
3471
3683
|
]
|
|
@@ -3524,6 +3736,8 @@ function placeholderFor(field, fields, values) {
|
|
|
3524
3736
|
}
|
|
3525
3737
|
return field.placeholder;
|
|
3526
3738
|
}
|
|
3739
|
+
var CHAIN_NAME = { STELLAR: "Stellar", POLYGON: "Polygon", SOLANA: "Solana" };
|
|
3740
|
+
var EXPLORER_NAME = { STELLAR: "Stellar Expert", POLYGON: "Polygonscan", SOLANA: "Solana Explorer" };
|
|
3527
3741
|
var LOADING_STEPS = ["Detecting your country\u2026", "Consulting providers\u2026", "Route found!"];
|
|
3528
3742
|
function flagEmoji(code) {
|
|
3529
3743
|
const cc = code.trim().toUpperCase();
|
|
@@ -3543,6 +3757,8 @@ function displayValue(field) {
|
|
|
3543
3757
|
return Number.isNaN(at.getTime()) ? field.value : at.toLocaleString();
|
|
3544
3758
|
}
|
|
3545
3759
|
function RampWidgetTemplate({
|
|
3760
|
+
workflowContent,
|
|
3761
|
+
routeSelector,
|
|
3546
3762
|
theme,
|
|
3547
3763
|
accentColor,
|
|
3548
3764
|
styleOverrides,
|
|
@@ -3570,10 +3786,20 @@ function RampWidgetTemplate({
|
|
|
3570
3786
|
onboardingStatus,
|
|
3571
3787
|
kycJustApproved,
|
|
3572
3788
|
stellarTxHash,
|
|
3789
|
+
txHash,
|
|
3790
|
+
txChain,
|
|
3573
3791
|
explorerUrl,
|
|
3792
|
+
fundsInTransit = false,
|
|
3793
|
+
retrying = false,
|
|
3794
|
+
onRetryTransit,
|
|
3574
3795
|
depositInstructions,
|
|
3575
3796
|
canComplete,
|
|
3576
3797
|
completing,
|
|
3798
|
+
savedRamps = [],
|
|
3799
|
+
onResumeRamp,
|
|
3800
|
+
onDismissRamp,
|
|
3801
|
+
onDismissCurrentRamp,
|
|
3802
|
+
onExploreRoutes,
|
|
3577
3803
|
errorMsg,
|
|
3578
3804
|
noticeMsg,
|
|
3579
3805
|
onDirectionChange,
|
|
@@ -3592,6 +3818,8 @@ function RampWidgetTemplate({
|
|
|
3592
3818
|
onRefresh,
|
|
3593
3819
|
onClose
|
|
3594
3820
|
}) {
|
|
3821
|
+
const settledHash = txHash ?? stellarTxHash;
|
|
3822
|
+
const chainName = CHAIN_NAME[txChain ?? "STELLAR"];
|
|
3595
3823
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides, "hero");
|
|
3596
3824
|
const stepTitle = {
|
|
3597
3825
|
input: direction === "onramp" ? "Buy crypto" : "Sell crypto",
|
|
@@ -3610,7 +3838,7 @@ function RampWidgetTemplate({
|
|
|
3610
3838
|
// money, not who you are. Say which, rather than asserting the Bridge case
|
|
3611
3839
|
// over every provider.
|
|
3612
3840
|
contact: `${provider || "This provider"} needs ${listOf(requiredFields.filter((f) => !f.optional).map((f) => f.label.toLowerCase()))} to continue`,
|
|
3613
|
-
status: `Finish the flow at ${provider || "the provider"} to continue`,
|
|
3841
|
+
status: workflowContent ? "Follow the next step below to continue" : `Finish the flow at ${provider || "the provider"} to continue`,
|
|
3614
3842
|
error: "Please try again"
|
|
3615
3843
|
};
|
|
3616
3844
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-card pollar-ramp-modal", style: cssVars, onClick: (e) => e.stopPropagation(), children: [
|
|
@@ -3664,7 +3892,39 @@ function RampWidgetTemplate({
|
|
|
3664
3892
|
}
|
|
3665
3893
|
)
|
|
3666
3894
|
] }),
|
|
3895
|
+
step === "input" && savedRamps.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-ramp-payment pollar-ramp-saved", "aria-label": "Pending operations", children: [
|
|
3896
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: "Your pending operations are saved. Starting another route does not cancel them." }),
|
|
3897
|
+
savedRamps.map((ramp) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-saved-row", children: [
|
|
3898
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3899
|
+
"button",
|
|
3900
|
+
{
|
|
3901
|
+
type: "button",
|
|
3902
|
+
className: "pollar-btn-secondary",
|
|
3903
|
+
disabled: isLoading,
|
|
3904
|
+
onClick: () => onResumeRamp?.(ramp.txId),
|
|
3905
|
+
children: [
|
|
3906
|
+
"Resume ",
|
|
3907
|
+
ramp.provider,
|
|
3908
|
+
" \xB7 ",
|
|
3909
|
+
ramp.txId.slice(-8)
|
|
3910
|
+
]
|
|
3911
|
+
}
|
|
3912
|
+
),
|
|
3913
|
+
onDismissRamp && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3914
|
+
"button",
|
|
3915
|
+
{
|
|
3916
|
+
type: "button",
|
|
3917
|
+
className: "pollar-btn-secondary",
|
|
3918
|
+
disabled: isLoading,
|
|
3919
|
+
"aria-label": `Remove ${ramp.provider} ${ramp.txId.slice(-8)} from pending list`,
|
|
3920
|
+
onClick: () => onDismissRamp(ramp.txId),
|
|
3921
|
+
children: "Remove"
|
|
3922
|
+
}
|
|
3923
|
+
)
|
|
3924
|
+
] }, ramp.txId))
|
|
3925
|
+
] }),
|
|
3667
3926
|
step === "input" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3927
|
+
noticeMsg && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", role: "status", children: noticeMsg }),
|
|
3668
3928
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tabs", children: [
|
|
3669
3929
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3670
3930
|
"button",
|
|
@@ -3688,25 +3948,36 @@ function RampWidgetTemplate({
|
|
|
3688
3948
|
)
|
|
3689
3949
|
] }),
|
|
3690
3950
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-field", children: [
|
|
3691
|
-
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-ramp-label", children: "Country" }),
|
|
3951
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { className: "pollar-ramp-label", htmlFor: "pollar-ramp-country", children: "Country" }),
|
|
3692
3952
|
countriesLoading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-input pollar-select-loading", children: [
|
|
3693
3953
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
3694
3954
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading countries\u2026" })
|
|
3695
|
-
] }) : countries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: "No ramp providers available on this network yet." }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3955
|
+
] }) : countries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: "No ramp providers available on this network yet." }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
3956
|
+
"select",
|
|
3957
|
+
{
|
|
3958
|
+
id: "pollar-ramp-country",
|
|
3959
|
+
className: "pollar-ramp-input",
|
|
3960
|
+
value: country,
|
|
3961
|
+
onChange: (e) => onCountryChange(e.target.value),
|
|
3962
|
+
children: countries.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: c.code, children: [
|
|
3963
|
+
flagEmoji(c.code),
|
|
3964
|
+
" ",
|
|
3965
|
+
c.code,
|
|
3966
|
+
c.currency ? ` \u2014 ${c.currency}` : ""
|
|
3967
|
+
] }, c.code))
|
|
3968
|
+
}
|
|
3969
|
+
)
|
|
3701
3970
|
] }),
|
|
3971
|
+
routeSelector,
|
|
3702
3972
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-field", children: [
|
|
3703
|
-
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-ramp-label", children: [
|
|
3973
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-ramp-label", htmlFor: "pollar-ramp-amount", children: [
|
|
3704
3974
|
"Amount",
|
|
3705
3975
|
currency ? ` (${currency})` : ""
|
|
3706
3976
|
] }),
|
|
3707
3977
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3708
3978
|
"input",
|
|
3709
3979
|
{
|
|
3980
|
+
id: "pollar-ramp-amount",
|
|
3710
3981
|
type: "number",
|
|
3711
3982
|
className: "pollar-ramp-input",
|
|
3712
3983
|
placeholder: "0.00",
|
|
@@ -3812,7 +4083,16 @@ function RampWidgetTemplate({
|
|
|
3812
4083
|
)
|
|
3813
4084
|
] })
|
|
3814
4085
|
] }),
|
|
3815
|
-
step === "status" &&
|
|
4086
|
+
step === "status" && workflowContent,
|
|
4087
|
+
step === "status" && onDismissCurrentRamp && txStatus !== "completed" && txStatus !== "failed" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-explore", children: [
|
|
4088
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", disabled: completing, onClick: onDismissCurrentRamp, children: "Remove from pending list" }),
|
|
4089
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: "This only hides the operation in this tab. To request cancellation, open the provider link above when available or contact the provider\u2019s support. Payments and refunds must be confirmed by the provider." })
|
|
4090
|
+
] }),
|
|
4091
|
+
step === "status" && onExploreRoutes && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-explore", children: [
|
|
4092
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", disabled: completing, onClick: onExploreRoutes, children: txStatus === "completed" || txStatus === "failed" ? "Start another operation" : "Try another route" }),
|
|
4093
|
+
txStatus !== "completed" && txStatus !== "failed" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: "Your current operation stays saved so you can resume it later." })
|
|
4094
|
+
] }),
|
|
4095
|
+
step === "status" && !workflowContent && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment", children: [
|
|
3816
4096
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
3817
4097
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "Provider" }),
|
|
3818
4098
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-ramp-payment-value", children: /* @__PURE__ */ jsxRuntime.jsx("code", { children: provider }) })
|
|
@@ -3824,15 +4104,23 @@ function RampWidgetTemplate({
|
|
|
3824
4104
|
txStatus !== "completed" && txStatus !== "failed" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm", "aria-label": "Checking status" })
|
|
3825
4105
|
] })
|
|
3826
4106
|
] }),
|
|
3827
|
-
|
|
3828
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "
|
|
4107
|
+
fundsInTransit && txStatus !== "completed" && txStatus !== "failed" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
4108
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "Funds in transit" }),
|
|
4109
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: "Your money is safe in your own wallet, waiting for the next step of the transfer." }),
|
|
4110
|
+
onRetryTransit && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onRetryTransit, disabled: retrying, children: retrying ? "Retrying..." : "Retry now" })
|
|
4111
|
+
] }),
|
|
4112
|
+
settledHash && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
|
|
4113
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-ramp-payment-label", children: [
|
|
4114
|
+
chainName,
|
|
4115
|
+
" tx"
|
|
4116
|
+
] }),
|
|
3829
4117
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-value", style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
3830
4118
|
/* @__PURE__ */ jsxRuntime.jsxs("code", { style: { flex: 1, wordBreak: "break-all" }, children: [
|
|
3831
|
-
|
|
4119
|
+
settledHash.slice(0, 8),
|
|
3832
4120
|
"\u2026",
|
|
3833
|
-
|
|
4121
|
+
settledHash.slice(-8)
|
|
3834
4122
|
] }),
|
|
3835
|
-
/* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value:
|
|
4123
|
+
/* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: settledHash, label: "Copy transaction hash" }),
|
|
3836
4124
|
explorerUrl && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3837
4125
|
"a",
|
|
3838
4126
|
{
|
|
@@ -3840,8 +4128,8 @@ function RampWidgetTemplate({
|
|
|
3840
4128
|
target: "_blank",
|
|
3841
4129
|
rel: "noopener noreferrer",
|
|
3842
4130
|
className: "pollar-copy-btn",
|
|
3843
|
-
"aria-label":
|
|
3844
|
-
title:
|
|
4131
|
+
"aria-label": `View on ${EXPLORER_NAME[txChain ?? "STELLAR"]}`,
|
|
4132
|
+
title: `View on ${EXPLORER_NAME[txChain ?? "STELLAR"]}`,
|
|
3845
4133
|
children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
|
|
3846
4134
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3847
4135
|
"path",
|
|
@@ -3936,7 +4224,7 @@ function RampWidgetTemplate({
|
|
|
3936
4224
|
canComplete && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-primary", disabled: completing, onClick: onCompleteWithdraw, children: completing ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3937
4225
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm" }),
|
|
3938
4226
|
"Submitting\u2026"
|
|
3939
|
-
] }) : "
|
|
4227
|
+
] }) : "Check verification and continue" }),
|
|
3940
4228
|
errorMsg && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", style: { color: "var(--pollar-error-text)" }, children: errorMsg }),
|
|
3941
4229
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onClose, children: txStatus === "completed" ? "Done" : "Close" })
|
|
3942
4230
|
] }),
|
|
@@ -4102,19 +4390,26 @@ var SHARED_FIELD_LABELS = {
|
|
|
4102
4390
|
country_code: "Pa\xEDs de residencia"
|
|
4103
4391
|
}
|
|
4104
4392
|
};
|
|
4105
|
-
var errorCode = (error) =>
|
|
4393
|
+
var errorCode = (error) => typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" ? error.code : null;
|
|
4394
|
+
var errorBody = (error) => {
|
|
4395
|
+
const body = typeof error === "object" && error !== null && "body" in error ? error.body : void 0;
|
|
4396
|
+
return typeof body === "object" && body !== null ? body : void 0;
|
|
4397
|
+
};
|
|
4106
4398
|
function missingFieldsOf(error) {
|
|
4107
|
-
const body = error
|
|
4108
|
-
|
|
4399
|
+
const body = errorBody(error);
|
|
4400
|
+
const missing = body && "missing" in body ? body.missing : void 0;
|
|
4401
|
+
return Array.isArray(missing) ? missing.filter((item) => typeof item === "string") : [];
|
|
4109
4402
|
}
|
|
4110
4403
|
function registrationFixOf(error) {
|
|
4111
|
-
const body = error
|
|
4404
|
+
const body = errorBody(error);
|
|
4405
|
+
const invalid = body && "invalid" in body ? body.invalid : void 0;
|
|
4406
|
+
const formList = body && "forms" in body ? body.forms : void 0;
|
|
4112
4407
|
const strings = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
4113
|
-
const forms = Array.isArray(
|
|
4114
|
-
|
|
4115
|
-
return
|
|
4408
|
+
const forms = Array.isArray(formList) ? formList.flatMap((item) => {
|
|
4409
|
+
if (typeof item !== "object" || item === null || !("formId" in item) || typeof item.formId !== "string") return [];
|
|
4410
|
+
return [{ formId: item.formId, keys: strings("keys" in item ? item.keys : void 0) }];
|
|
4116
4411
|
}) : [];
|
|
4117
|
-
return { invalid: strings(
|
|
4412
|
+
return { invalid: strings(invalid), forms };
|
|
4118
4413
|
}
|
|
4119
4414
|
function RegistryCheckModal({ optionId, progress, onClose, onApproved }) {
|
|
4120
4415
|
const { getClient, styles } = usePollar();
|
|
@@ -4434,9 +4729,51 @@ function ProviderRegistrationModal({
|
|
|
4434
4729
|
}
|
|
4435
4730
|
) });
|
|
4436
4731
|
}
|
|
4732
|
+
|
|
4733
|
+
// src/components/ramp-widget/ramp-quotes.ts
|
|
4734
|
+
function unavailableRampMessage(country, unavailable) {
|
|
4735
|
+
if (!unavailable.length) return `No ramp providers available for ${country} yet.`;
|
|
4736
|
+
return unavailable.map(
|
|
4737
|
+
({ provider, code }) => code === "SDK_RAMPS_PROVIDER_NOT_CONFIGURED" ? `${provider} is not configured correctly. Contact the app administrator to enable this provider.` : `${provider} is temporarily unavailable. Please try again later.`
|
|
4738
|
+
).join(" ");
|
|
4739
|
+
}
|
|
4740
|
+
async function quoteRampOptions(client, query, routes) {
|
|
4741
|
+
const matching = routes.filter(
|
|
4742
|
+
(route) => route.country === query.country && route.direction === query.direction && route.fiatCurrency === query.currency
|
|
4743
|
+
);
|
|
4744
|
+
const responses = await Promise.allSettled([
|
|
4745
|
+
client.getRampsQuote(query),
|
|
4746
|
+
...matching.map((route) => client.getRampsQuote({ ...query, routeId: route.routeId, chain: route.asset.chain }))
|
|
4747
|
+
]);
|
|
4748
|
+
const results = responses.flatMap((response) => response.status === "fulfilled" ? [response.value] : []);
|
|
4749
|
+
if (!results.length) throw responses[0].reason;
|
|
4750
|
+
const quotes = /* @__PURE__ */ new Map();
|
|
4751
|
+
const requirements = /* @__PURE__ */ new Map();
|
|
4752
|
+
const unavailable = /* @__PURE__ */ new Map();
|
|
4753
|
+
for (const result of results) {
|
|
4754
|
+
for (const quote of result.quotes) {
|
|
4755
|
+
const key = JSON.stringify([quote.provider, quote.route?.routeId, quote.route?.asset.chain, quote.rail, quote.protocol]);
|
|
4756
|
+
if (!quotes.has(key)) quotes.set(key, quote);
|
|
4757
|
+
}
|
|
4758
|
+
for (const requirement of result.requirementsRequired ?? [])
|
|
4759
|
+
requirements.set(`${requirement.rampProviderId}:${requirement.corridorId}`, requirement);
|
|
4760
|
+
for (const item of result.unavailable ?? []) unavailable.set(item.provider, item);
|
|
4761
|
+
}
|
|
4762
|
+
const failed = responses.find((response) => response.status === "rejected");
|
|
4763
|
+
if (!quotes.size && !requirements.size && failed?.status === "rejected") throw failed.reason;
|
|
4764
|
+
return {
|
|
4765
|
+
quotes: [...quotes.values()],
|
|
4766
|
+
requirementsRequired: [...requirements.values()],
|
|
4767
|
+
unavailable: [...unavailable.values()]
|
|
4768
|
+
};
|
|
4769
|
+
}
|
|
4437
4770
|
var TERMINAL = ["completed", "failed"];
|
|
4771
|
+
var BANK_TYPES = ["CLABE", "PIX", "PSE", "ACH", "BREB"];
|
|
4772
|
+
function isBankType(value) {
|
|
4773
|
+
return BANK_TYPES.some((type) => type === value);
|
|
4774
|
+
}
|
|
4438
4775
|
function requiredFieldsOf(quote) {
|
|
4439
|
-
return quote.requiredFields
|
|
4776
|
+
return "requiredFields" in quote ? quote.requiredFields : [];
|
|
4440
4777
|
}
|
|
4441
4778
|
function flowStepsOf(quotes, selected) {
|
|
4442
4779
|
const needsDetails = selected != null ? requiredFieldsOf(selected).length > 0 : quotes.some((q) => requiredFieldsOf(q).length > 0);
|
|
@@ -4450,7 +4787,8 @@ var STEP_LABEL = {
|
|
|
4450
4787
|
status: "Complete"
|
|
4451
4788
|
};
|
|
4452
4789
|
function brokenLimitOf(amount, quote) {
|
|
4453
|
-
const
|
|
4790
|
+
const minAmount = "minAmount" in quote ? quote.minAmount : void 0;
|
|
4791
|
+
const maxAmount = "maxAmount" in quote ? quote.maxAmount : void 0;
|
|
4454
4792
|
if (!Number.isFinite(amount)) return null;
|
|
4455
4793
|
if (minAmount != null && amount < minAmount) return { limit: "min", value: minAmount };
|
|
4456
4794
|
if (maxAmount != null && amount > maxAmount) return { limit: "max", value: maxAmount };
|
|
@@ -4474,19 +4812,58 @@ var RAMP_ERROR_MESSAGES = {
|
|
|
4474
4812
|
SDK_RAMPS_ONCHAIN_SUBMIT_FAILED: "The network rejected the transaction, so nothing was sent. The wallet may need XLM for the fee."
|
|
4475
4813
|
};
|
|
4476
4814
|
function rampErrorMessage(e, fallback) {
|
|
4477
|
-
const
|
|
4478
|
-
const code = e?.code;
|
|
4815
|
+
const code = typeof e === "object" && e !== null && "code" in e ? e.code : void 0;
|
|
4479
4816
|
if (typeof code !== "string") return e instanceof Error ? e.message : fallback;
|
|
4480
|
-
const
|
|
4481
|
-
const
|
|
4482
|
-
const
|
|
4817
|
+
const raw = typeof e === "object" && e !== null && "body" in e ? e.body : void 0;
|
|
4818
|
+
const body = typeof raw === "object" && raw !== null ? raw : {};
|
|
4819
|
+
const limit = "limit" in body ? body.limit : void 0;
|
|
4820
|
+
const value = "limitAmount" in body ? body.limitAmount : void 0;
|
|
4821
|
+
const currency = "limitCurrency" in body ? body.limitCurrency : void 0;
|
|
4483
4822
|
if ((limit === "min" || limit === "max") && typeof value === "number" && typeof currency === "string") {
|
|
4484
4823
|
return limitMessage(limit, value, currency);
|
|
4485
4824
|
}
|
|
4486
4825
|
return RAMP_ERROR_MESSAGES[code] ?? (e instanceof Error ? e.message : fallback);
|
|
4487
4826
|
}
|
|
4827
|
+
function readRampStorage(key) {
|
|
4828
|
+
try {
|
|
4829
|
+
return typeof window === "undefined" ? null : window.sessionStorage.getItem(key);
|
|
4830
|
+
} catch {
|
|
4831
|
+
return null;
|
|
4832
|
+
}
|
|
4833
|
+
}
|
|
4834
|
+
function writeRampStorage(key, value) {
|
|
4835
|
+
try {
|
|
4836
|
+
if (typeof window === "undefined") return;
|
|
4837
|
+
if (value === null) window.sessionStorage.removeItem(key);
|
|
4838
|
+
else window.sessionStorage.setItem(key, value);
|
|
4839
|
+
} catch {
|
|
4840
|
+
}
|
|
4841
|
+
}
|
|
4842
|
+
function savedRampsOf(key) {
|
|
4843
|
+
try {
|
|
4844
|
+
const value = JSON.parse(readRampStorage(`${key}:saved`) ?? "[]");
|
|
4845
|
+
return Array.isArray(value) ? value.filter((item) => typeof item?.txId === "string" && typeof item?.provider === "string") : [];
|
|
4846
|
+
} catch {
|
|
4847
|
+
return [];
|
|
4848
|
+
}
|
|
4849
|
+
}
|
|
4850
|
+
function hiddenRampsOf(key) {
|
|
4851
|
+
try {
|
|
4852
|
+
const value = JSON.parse(readRampStorage(`${key}:hidden`) ?? "[]");
|
|
4853
|
+
return Array.isArray(value) ? value.filter((id) => typeof id === "string") : [];
|
|
4854
|
+
} catch {
|
|
4855
|
+
return [];
|
|
4856
|
+
}
|
|
4857
|
+
}
|
|
4858
|
+
function explorerTxUrl2(chain, hash, network) {
|
|
4859
|
+
if (!hash) return null;
|
|
4860
|
+
const testnet = network === "testnet";
|
|
4861
|
+
if (chain === "SOLANA") return `https://explorer.solana.com/tx/${hash}${testnet ? "?cluster=devnet" : ""}`;
|
|
4862
|
+
if (chain === "POLYGON") return `https://${testnet ? "amoy." : ""}polygonscan.com/tx/${hash}`;
|
|
4863
|
+
return `https://stellar.expert/explorer/${testnet ? "testnet" : "public"}/tx/${hash}`;
|
|
4864
|
+
}
|
|
4488
4865
|
function RampWidget({ onClose }) {
|
|
4489
|
-
const { getClient,
|
|
4866
|
+
const { getClient, wallet, styles, network } = usePollar();
|
|
4490
4867
|
const walletAddress = wallet?.address ?? "";
|
|
4491
4868
|
const client = getClient();
|
|
4492
4869
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
@@ -4497,7 +4874,7 @@ function RampWidget({ onClose }) {
|
|
|
4497
4874
|
const [country, setCountry] = react.useState("");
|
|
4498
4875
|
const [fieldValues, setFieldValues] = react.useState({});
|
|
4499
4876
|
const setFieldValue = (key, value) => setFieldValues((v) => ({ ...v, [key]: value }));
|
|
4500
|
-
const [
|
|
4877
|
+
const [legacyCountries, setCountries] = react.useState([]);
|
|
4501
4878
|
const [countriesLoading, setCountriesLoading] = react.useState(true);
|
|
4502
4879
|
const [refreshing, setRefreshing] = react.useState(false);
|
|
4503
4880
|
const [quotes, setQuotes] = react.useState([]);
|
|
@@ -4522,21 +4899,129 @@ function RampWidget({ onClose }) {
|
|
|
4522
4899
|
const [onboardingStatus, setOnboardingStatus] = react.useState(void 0);
|
|
4523
4900
|
const [txStatus, setTxStatus] = react.useState(null);
|
|
4524
4901
|
const [stellarTxHash, setStellarTxHash] = react.useState(null);
|
|
4902
|
+
const [txHash, setTxHash] = react.useState(null);
|
|
4903
|
+
const [txChain, setTxChain] = react.useState(null);
|
|
4904
|
+
const [fundsInTransit, setFundsInTransit] = react.useState(false);
|
|
4905
|
+
const [retrying, setRetrying] = react.useState(false);
|
|
4525
4906
|
const [depositInstructions, setDepositInstructions] = react.useState(null);
|
|
4907
|
+
const [workflow, setWorkflow] = react.useState(null);
|
|
4908
|
+
const workflowRef = react.useRef(null);
|
|
4909
|
+
const storageKey = `pollar:ramp:${client.apiKey}:${walletAddress}`;
|
|
4910
|
+
const [savedRamps, setSavedRamps] = react.useState([]);
|
|
4911
|
+
const [legacySignature, setLegacySignature] = react.useState(void 0);
|
|
4912
|
+
function acceptWorkflow(incoming) {
|
|
4913
|
+
if (hiddenRampsOf(storageKey).includes(incoming.txId)) return false;
|
|
4914
|
+
const next = core.mergeRampSnapshot(workflowRef.current, incoming);
|
|
4915
|
+
workflowRef.current = next;
|
|
4916
|
+
setWorkflow(next);
|
|
4917
|
+
if (next === incoming) {
|
|
4918
|
+
const pending = savedRampsOf(storageKey).filter((item) => item.txId !== incoming.txId);
|
|
4919
|
+
if (!["completed", "failed", "refunded"].includes(incoming.lifecycleState ?? incoming.status))
|
|
4920
|
+
pending.push({
|
|
4921
|
+
txId: incoming.txId,
|
|
4922
|
+
provider: "provider" in incoming && typeof incoming.provider === "string" ? incoming.provider : provider || "Ramp"
|
|
4923
|
+
});
|
|
4924
|
+
writeRampStorage(`${storageKey}:saved`, JSON.stringify(pending));
|
|
4925
|
+
writeRampStorage(storageKey, incoming.txId);
|
|
4926
|
+
writeRampStorage(`${storageKey}:selection`, null);
|
|
4927
|
+
setSavedRamps(pending);
|
|
4928
|
+
}
|
|
4929
|
+
return next === incoming;
|
|
4930
|
+
}
|
|
4931
|
+
const [routes, setRoutes] = react.useState([]);
|
|
4932
|
+
const countries = core.mergeRampCountries(legacyCountries, routes);
|
|
4933
|
+
react.useEffect(() => {
|
|
4934
|
+
if (!country && countries[0]) {
|
|
4935
|
+
setCountry(countries[0].code);
|
|
4936
|
+
setCurrency(countries[0].currency ?? "");
|
|
4937
|
+
}
|
|
4938
|
+
}, [countries, country]);
|
|
4939
|
+
react.useEffect(() => {
|
|
4940
|
+
let active = true;
|
|
4941
|
+
void client.getRampRoutes().then((result) => {
|
|
4942
|
+
if (active) setRoutes(result.routes);
|
|
4943
|
+
}).catch(() => {
|
|
4944
|
+
});
|
|
4945
|
+
return () => {
|
|
4946
|
+
active = false;
|
|
4947
|
+
};
|
|
4948
|
+
}, [client]);
|
|
4526
4949
|
const [completing, setCompleting] = react.useState(false);
|
|
4950
|
+
const completionLocked = react.useRef(false);
|
|
4527
4951
|
const [errorMsg, setErrorMsg] = react.useState(null);
|
|
4952
|
+
react.useEffect(() => {
|
|
4953
|
+
if (typeof window === "undefined" || !walletAddress) return;
|
|
4954
|
+
setSavedRamps(savedRampsOf(storageKey));
|
|
4955
|
+
if (readRampStorage(`${storageKey}:selection`) === "1") return;
|
|
4956
|
+
const hidden = hiddenRampsOf(storageKey);
|
|
4957
|
+
const savedId = [new URLSearchParams(window.location.search).get("rampTxId"), readRampStorage(storageKey)].find(
|
|
4958
|
+
(id) => id && !hidden.includes(id)
|
|
4959
|
+
);
|
|
4960
|
+
if (!savedId) return;
|
|
4961
|
+
let active = true;
|
|
4962
|
+
void client.getRampTransaction(savedId).then(async (result) => {
|
|
4963
|
+
if (!active || result.transactionVersion === void 0) return;
|
|
4964
|
+
setDirection(result.direction);
|
|
4965
|
+
await applyResult(result);
|
|
4966
|
+
}).catch(() => {
|
|
4967
|
+
if (active)
|
|
4968
|
+
setErrorMsg("Could not restore the saved ramp. Retry opening the modal; do not create a replacement order.");
|
|
4969
|
+
});
|
|
4970
|
+
return () => {
|
|
4971
|
+
active = false;
|
|
4972
|
+
};
|
|
4973
|
+
}, [client, storageKey, walletAddress]);
|
|
4974
|
+
async function resumeSavedRamp(id) {
|
|
4975
|
+
if (completionLocked.current) return;
|
|
4976
|
+
setIsLoading(true);
|
|
4977
|
+
setErrorMsg(null);
|
|
4978
|
+
try {
|
|
4979
|
+
const result = await client.getRampTransaction(id);
|
|
4980
|
+
if (result.transactionVersion === void 0) throw new Error("This saved ramp cannot be restored.");
|
|
4981
|
+
setDirection(result.direction);
|
|
4982
|
+
await applyResult(result);
|
|
4983
|
+
} catch (error) {
|
|
4984
|
+
setErrorMsg(rampErrorMessage(error, "Could not resume the saved ramp."));
|
|
4985
|
+
} finally {
|
|
4986
|
+
setIsLoading(false);
|
|
4987
|
+
}
|
|
4988
|
+
}
|
|
4528
4989
|
const directionRef = react.useRef(direction);
|
|
4529
4990
|
directionRef.current = direction;
|
|
4991
|
+
function applySettlement(tx) {
|
|
4992
|
+
if (tx.stellarTxHash) setStellarTxHash(tx.stellarTxHash);
|
|
4993
|
+
if (tx.txHash) setTxHash(tx.txHash);
|
|
4994
|
+
if (tx.chain) setTxChain(tx.chain);
|
|
4995
|
+
setFundsInTransit(tx.fundsInTransit === true);
|
|
4996
|
+
}
|
|
4997
|
+
async function handleRetryTransit() {
|
|
4998
|
+
if (!txId || retrying) return;
|
|
4999
|
+
setRetrying(true);
|
|
5000
|
+
setErrorMsg(null);
|
|
5001
|
+
try {
|
|
5002
|
+
const tx = await client.retryRampTransaction(txId);
|
|
5003
|
+
setTxStatus(tx.status);
|
|
5004
|
+
applySettlement(tx);
|
|
5005
|
+
} catch (e) {
|
|
5006
|
+
setErrorMsg(e instanceof Error && e.message ? e.message : "Could not retry the transfer. Try again in a moment.");
|
|
5007
|
+
} finally {
|
|
5008
|
+
setRetrying(false);
|
|
5009
|
+
}
|
|
5010
|
+
}
|
|
5011
|
+
const workflowTerminal = !!workflow && ["completed", "failed", "refunded"].includes(workflow.lifecycleState ?? workflow.status);
|
|
4530
5012
|
react.useEffect(() => {
|
|
4531
5013
|
if (step !== "status" || !txId) return;
|
|
4532
|
-
if (txStatus && TERMINAL.includes(txStatus)) return;
|
|
5014
|
+
if (workflowTerminal || txStatus && TERMINAL.includes(txStatus)) return;
|
|
4533
5015
|
let active = true;
|
|
4534
5016
|
const id = setInterval(async () => {
|
|
4535
5017
|
try {
|
|
4536
5018
|
const tx = await client.getRampTransaction(txId);
|
|
4537
5019
|
if (!active) return;
|
|
5020
|
+
if (tx.transactionVersion !== void 0 && !acceptWorkflow(tx)) return;
|
|
4538
5021
|
setTxStatus(tx.status);
|
|
4539
|
-
|
|
5022
|
+
applySettlement(tx);
|
|
5023
|
+
const pending = "pendingSignature" in tx ? tx.pendingSignature : void 0;
|
|
5024
|
+
if (pending) setLegacySignature(pending);
|
|
4540
5025
|
if (tx.kycUrl) setKycUrl(tx.kycUrl);
|
|
4541
5026
|
if (tx.depositInstructions) setDepositInstructions(tx.depositInstructions);
|
|
4542
5027
|
if (TERMINAL.includes(tx.status)) clearInterval(id);
|
|
@@ -4547,9 +5032,9 @@ function RampWidget({ onClose }) {
|
|
|
4547
5032
|
active = false;
|
|
4548
5033
|
clearInterval(id);
|
|
4549
5034
|
};
|
|
4550
|
-
}, [step, txId, txStatus, client]);
|
|
5035
|
+
}, [step, txId, txStatus, workflowTerminal, client]);
|
|
4551
5036
|
react.useEffect(() => {
|
|
4552
|
-
if (step !== "status" || !kycPending || kycApproved) return;
|
|
5037
|
+
if (workflow || step !== "status" || !kycPending || kycApproved || provider.toLowerCase() !== "abroad") return;
|
|
4553
5038
|
if (onboardingStatus === "awaiting_provider") return;
|
|
4554
5039
|
let active = true;
|
|
4555
5040
|
const check = async () => {
|
|
@@ -4565,14 +5050,15 @@ function RampWidget({ onClose }) {
|
|
|
4565
5050
|
active = false;
|
|
4566
5051
|
clearInterval(id);
|
|
4567
5052
|
};
|
|
4568
|
-
}, [step, kycPending, kycApproved, onboardingStatus, client]);
|
|
5053
|
+
}, [step, kycPending, kycApproved, onboardingStatus, workflow, client, provider]);
|
|
4569
5054
|
async function loadCountries(resetSelection) {
|
|
4570
5055
|
setCountriesLoading(true);
|
|
4571
5056
|
try {
|
|
4572
5057
|
const { countries: list } = await client.getRampCountries();
|
|
4573
5058
|
setCountries(list);
|
|
4574
|
-
const
|
|
4575
|
-
const
|
|
5059
|
+
const available = core.mergeRampCountries(list, routes);
|
|
5060
|
+
const first = available[0];
|
|
5061
|
+
const stillValid = available.some((c) => c.code === country);
|
|
4576
5062
|
if (first && (resetSelection || !stillValid)) {
|
|
4577
5063
|
setCountry(first.code);
|
|
4578
5064
|
if (first.currency) setCurrency(first.currency);
|
|
@@ -4597,13 +5083,24 @@ function RampWidget({ onClose }) {
|
|
|
4597
5083
|
try {
|
|
4598
5084
|
await loadCountries(false);
|
|
4599
5085
|
if (step === "select_route") {
|
|
4600
|
-
const result = await
|
|
5086
|
+
const result = await quoteRampOptions(
|
|
5087
|
+
client,
|
|
5088
|
+
{
|
|
5089
|
+
country,
|
|
5090
|
+
amount: Number(amount),
|
|
5091
|
+
amountExact: amount,
|
|
5092
|
+
currency,
|
|
5093
|
+
direction
|
|
5094
|
+
},
|
|
5095
|
+
routes
|
|
5096
|
+
);
|
|
4601
5097
|
setQuotes(result.quotes ?? []);
|
|
4602
5098
|
setRequirementsRequired(result.requirementsRequired ?? []);
|
|
4603
5099
|
} else if (step === "status" && txId) {
|
|
4604
5100
|
const tx = await client.getRampTransaction(txId);
|
|
5101
|
+
if (tx.transactionVersion !== void 0 && !acceptWorkflow(tx)) return;
|
|
4605
5102
|
setTxStatus(tx.status);
|
|
4606
|
-
|
|
5103
|
+
applySettlement(tx);
|
|
4607
5104
|
if (tx.kycUrl) setKycUrl(tx.kycUrl);
|
|
4608
5105
|
if (tx.depositInstructions) setDepositInstructions(tx.depositInstructions);
|
|
4609
5106
|
}
|
|
@@ -4613,25 +5110,50 @@ function RampWidget({ onClose }) {
|
|
|
4613
5110
|
}
|
|
4614
5111
|
}
|
|
4615
5112
|
function resetToInput({ keepMessage = false } = {}) {
|
|
5113
|
+
writeRampStorage(storageKey, null);
|
|
5114
|
+
writeRampStorage(`${storageKey}:selection`, "1");
|
|
4616
5115
|
setStep("input");
|
|
4617
5116
|
setQuotes([]);
|
|
4618
5117
|
setRequirementsRequired([]);
|
|
4619
5118
|
setSelectedQuote(null);
|
|
4620
5119
|
setFieldValues({});
|
|
5120
|
+
setWorkflow(null);
|
|
5121
|
+
workflowRef.current = null;
|
|
5122
|
+
setLegacySignature(void 0);
|
|
4621
5123
|
setTxId(null);
|
|
4622
5124
|
setProvider("");
|
|
4623
5125
|
setKycUrl(null);
|
|
4624
5126
|
setTosUrl(null);
|
|
4625
5127
|
setTxStatus(null);
|
|
4626
5128
|
setStellarTxHash(null);
|
|
5129
|
+
setTxHash(null);
|
|
5130
|
+
setTxChain(null);
|
|
5131
|
+
setFundsInTransit(false);
|
|
4627
5132
|
setDepositInstructions(null);
|
|
4628
5133
|
setKycPending(false);
|
|
4629
5134
|
setKycApproved(false);
|
|
4630
5135
|
setNoticeMsg(null);
|
|
4631
5136
|
if (!keepMessage) setErrorMsg(null);
|
|
4632
5137
|
}
|
|
5138
|
+
function dismissSavedRamp(id) {
|
|
5139
|
+
if (completionLocked.current) return;
|
|
5140
|
+
const pending = savedRampsOf(storageKey).filter((ramp) => ramp.txId !== id);
|
|
5141
|
+
writeRampStorage(`${storageKey}:saved`, JSON.stringify(pending));
|
|
5142
|
+
writeRampStorage(`${storageKey}:hidden`, JSON.stringify([.../* @__PURE__ */ new Set([...hiddenRampsOf(storageKey), id])]));
|
|
5143
|
+
if (readRampStorage(storageKey) === id) writeRampStorage(storageKey, null);
|
|
5144
|
+
setSavedRamps(pending);
|
|
5145
|
+
if (txId === id) resetToInput();
|
|
5146
|
+
setNoticeMsg(
|
|
5147
|
+
"Removed from this tab\u2019s pending list. The operation may still be active at the provider; no payment was cancelled or refunded."
|
|
5148
|
+
);
|
|
5149
|
+
}
|
|
4633
5150
|
async function resumeWithSignature(id, ps) {
|
|
4634
|
-
const outcome = await signTx(ps.unsignedXdr);
|
|
5151
|
+
const outcome = await client.signTx(ps.unsignedXdr, { skipSponsorship: ps.action === "sep10" });
|
|
5152
|
+
if (outcome.status === "cosign_pending") {
|
|
5153
|
+
setErrorMsg("Approve the signature on your device, then resume.");
|
|
5154
|
+
setStep("error");
|
|
5155
|
+
return;
|
|
5156
|
+
}
|
|
4635
5157
|
if (outcome.status !== "signed") {
|
|
4636
5158
|
setErrorMsg(outcome.message ?? outcome.details ?? "Signing was cancelled.");
|
|
4637
5159
|
setStep("error");
|
|
@@ -4644,12 +5166,10 @@ function RampWidget({ onClose }) {
|
|
|
4644
5166
|
await applyResult(result);
|
|
4645
5167
|
}
|
|
4646
5168
|
async function applyResult(result) {
|
|
5169
|
+
if ("transactionVersion" in result && result.transactionVersion !== void 0 && !acceptWorkflow(result)) return;
|
|
4647
5170
|
setTxId(result.txId);
|
|
4648
5171
|
setProvider(result.provider);
|
|
4649
|
-
|
|
4650
|
-
await resumeWithSignature(result.txId, result.pendingSignature);
|
|
4651
|
-
return;
|
|
4652
|
-
}
|
|
5172
|
+
setLegacySignature(result.pendingSignature);
|
|
4653
5173
|
setKycUrl(result.kycUrl ?? null);
|
|
4654
5174
|
setTosUrl(result.tosUrl ?? null);
|
|
4655
5175
|
setOnboardingStatus(result.onboardingStatus);
|
|
@@ -4661,14 +5181,21 @@ function RampWidget({ onClose }) {
|
|
|
4661
5181
|
setStep("status");
|
|
4662
5182
|
}
|
|
4663
5183
|
async function loadQuotes() {
|
|
4664
|
-
const result = await
|
|
5184
|
+
const result = await quoteRampOptions(
|
|
5185
|
+
client,
|
|
5186
|
+
{
|
|
5187
|
+
country,
|
|
5188
|
+
amount: Number(amount),
|
|
5189
|
+
amountExact: amount,
|
|
5190
|
+
currency,
|
|
5191
|
+
direction
|
|
5192
|
+
},
|
|
5193
|
+
routes
|
|
5194
|
+
);
|
|
4665
5195
|
const list = result.quotes ?? [];
|
|
4666
5196
|
const locked = result.requirementsRequired ?? [];
|
|
4667
5197
|
if (list.length === 0 && locked.length === 0) {
|
|
4668
|
-
|
|
4669
|
-
setErrorMsg(
|
|
4670
|
-
down.length > 0 ? `${down.join(", ")} ${down.length === 1 ? "is" : "are"} temporarily unavailable. Please try again later.` : `No ramp providers available for ${country} yet.`
|
|
4671
|
-
);
|
|
5198
|
+
setErrorMsg(unavailableRampMessage(country, result.unavailable ?? []));
|
|
4672
5199
|
setStep("error");
|
|
4673
5200
|
return false;
|
|
4674
5201
|
}
|
|
@@ -4714,19 +5241,40 @@ function RampWidget({ onClose }) {
|
|
|
4714
5241
|
setIsLoading(true);
|
|
4715
5242
|
setErrorMsg(null);
|
|
4716
5243
|
try {
|
|
4717
|
-
const
|
|
4718
|
-
|
|
4719
|
-
|
|
5244
|
+
const body = {
|
|
5245
|
+
quoteId: quote.quoteId,
|
|
5246
|
+
amount: quote.fiatAmount ?? Number(amount),
|
|
5247
|
+
...quote.terms ? { amountExact: quote.terms.fiatAmount } : {},
|
|
5248
|
+
currency,
|
|
5249
|
+
country,
|
|
5250
|
+
...walletAddress ? { walletAddress } : {}
|
|
5251
|
+
};
|
|
4720
5252
|
const extraFields = {};
|
|
4721
5253
|
for (const f of requiredFieldsOf(quote)) {
|
|
4722
5254
|
const val = (fieldValues[f.key] ?? "").trim();
|
|
4723
5255
|
if (!val) continue;
|
|
4724
|
-
if (f.bankType)
|
|
4725
|
-
|
|
5256
|
+
if (f.bankType) {
|
|
5257
|
+
if (isBankType(f.bankType)) body.bankDetails = { type: f.bankType, value: val };
|
|
5258
|
+
} else if (f.key === "email" || f.key === "fullName" || f.key === "taxId" || f.key === "qrCode") body[f.key] = val;
|
|
4726
5259
|
else extraFields[f.key] = val;
|
|
4727
5260
|
}
|
|
4728
|
-
if (
|
|
4729
|
-
|
|
5261
|
+
if (quote.route)
|
|
5262
|
+
body.fields = Object.fromEntries(
|
|
5263
|
+
requiredFieldsOf(quote).map((field) => [field.key, (fieldValues[field.key] ?? "").trim()]).filter(([, value]) => value)
|
|
5264
|
+
);
|
|
5265
|
+
else if (Object.keys(extraFields).length > 0) body.fields = extraFields;
|
|
5266
|
+
const onrampBody = {
|
|
5267
|
+
quoteId: body.quoteId,
|
|
5268
|
+
amount: body.amount,
|
|
5269
|
+
currency: body.currency,
|
|
5270
|
+
country: body.country,
|
|
5271
|
+
...body.amountExact !== void 0 ? { amountExact: body.amountExact } : {},
|
|
5272
|
+
...body.walletAddress !== void 0 ? { walletAddress: body.walletAddress } : {},
|
|
5273
|
+
...body.email !== void 0 ? { email: body.email } : {},
|
|
5274
|
+
...body.fullName !== void 0 ? { fullName: body.fullName } : {},
|
|
5275
|
+
...body.fields !== void 0 ? { fields: body.fields } : {}
|
|
5276
|
+
};
|
|
5277
|
+
const result = direction === "onramp" ? await client.createOnRamp(onrampBody) : await client.createOffRamp(body);
|
|
4730
5278
|
await applyResult(result);
|
|
4731
5279
|
} catch (e) {
|
|
4732
5280
|
const requirement = requiredRampKyc(e);
|
|
@@ -4776,8 +5324,24 @@ function RampWidget({ onClose }) {
|
|
|
4776
5324
|
function handleOpenTos() {
|
|
4777
5325
|
if (tosUrl) window.open(tosUrl, "_blank", "noopener,noreferrer");
|
|
4778
5326
|
}
|
|
5327
|
+
async function handleLegacySignature() {
|
|
5328
|
+
if (!txId || !legacySignature || completionLocked.current) return;
|
|
5329
|
+
completionLocked.current = true;
|
|
5330
|
+
setCompleting(true);
|
|
5331
|
+
setErrorMsg(null);
|
|
5332
|
+
try {
|
|
5333
|
+
await resumeWithSignature(txId, legacySignature);
|
|
5334
|
+
} catch (e) {
|
|
5335
|
+
setErrorMsg(rampErrorMessage(e, "Failed to submit the signature."));
|
|
5336
|
+
setStep("error");
|
|
5337
|
+
} finally {
|
|
5338
|
+
completionLocked.current = false;
|
|
5339
|
+
setCompleting(false);
|
|
5340
|
+
}
|
|
5341
|
+
}
|
|
4779
5342
|
async function handleCompleteWithdraw() {
|
|
4780
|
-
if (!txId) return;
|
|
5343
|
+
if (!txId || completionLocked.current) return;
|
|
5344
|
+
completionLocked.current = true;
|
|
4781
5345
|
setCompleting(true);
|
|
4782
5346
|
setErrorMsg(null);
|
|
4783
5347
|
try {
|
|
@@ -4794,11 +5358,12 @@ function RampWidget({ onClose }) {
|
|
|
4794
5358
|
msg.includes("KYC") ? "Finish KYC at the provider first, then try again." : msg || "Failed to complete the withdrawal."
|
|
4795
5359
|
);
|
|
4796
5360
|
} finally {
|
|
5361
|
+
completionLocked.current = false;
|
|
4797
5362
|
setCompleting(false);
|
|
4798
5363
|
}
|
|
4799
5364
|
}
|
|
4800
5365
|
const kycBlocking = kycPending && !kycApproved;
|
|
4801
|
-
const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash && !kycPending;
|
|
5366
|
+
const canComplete = !workflow && !legacySignature && direction === "offramp" && step === "status" && txStatus !== "completed" && txStatus !== "failed" && !stellarTxHash && !txHash && !kycPending;
|
|
4802
5367
|
const flowSteps = flowStepsOf(quotes, selectedQuote);
|
|
4803
5368
|
const flowStepIndex = flowSteps.indexOf(STEP_LABEL[step] ?? "");
|
|
4804
5369
|
if (pendingKyc?.type === "FORM") {
|
|
@@ -4856,6 +5421,20 @@ function RampWidget({ onClose }) {
|
|
|
4856
5421
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4857
5422
|
RampWidgetTemplate,
|
|
4858
5423
|
{
|
|
5424
|
+
workflowContent: workflow ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5425
|
+
RampWorkflow,
|
|
5426
|
+
{
|
|
5427
|
+
client,
|
|
5428
|
+
snapshot: workflow,
|
|
5429
|
+
onBusyChange: (busy) => {
|
|
5430
|
+
completionLocked.current = busy;
|
|
5431
|
+
setCompleting(busy);
|
|
5432
|
+
},
|
|
5433
|
+
onChange: (next) => {
|
|
5434
|
+
if (acceptWorkflow(next)) setTxStatus(next.status);
|
|
5435
|
+
}
|
|
5436
|
+
}
|
|
5437
|
+
) : legacySignature && step === "status" && txStatus !== "completed" && txStatus !== "failed" ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", disabled: completing, onClick: () => void handleLegacySignature(), children: "Authorize wallet request" }) : void 0,
|
|
4859
5438
|
theme,
|
|
4860
5439
|
accentColor,
|
|
4861
5440
|
styleOverrides,
|
|
@@ -4883,13 +5462,27 @@ function RampWidget({ onClose }) {
|
|
|
4883
5462
|
onboardingStatus: onboardingStatus ?? null,
|
|
4884
5463
|
kycJustApproved: kycPending && kycApproved,
|
|
4885
5464
|
stellarTxHash,
|
|
4886
|
-
|
|
5465
|
+
txHash,
|
|
5466
|
+
txChain,
|
|
5467
|
+
explorerUrl: explorerTxUrl2(txChain ?? "STELLAR", txHash ?? stellarTxHash, network),
|
|
5468
|
+
fundsInTransit,
|
|
5469
|
+
retrying,
|
|
5470
|
+
onRetryTransit: handleRetryTransit,
|
|
4887
5471
|
depositInstructions,
|
|
4888
5472
|
canComplete,
|
|
4889
5473
|
completing,
|
|
5474
|
+
savedRamps,
|
|
5475
|
+
onResumeRamp: resumeSavedRamp,
|
|
5476
|
+
onDismissRamp: dismissSavedRamp,
|
|
5477
|
+
onDismissCurrentRamp: workflow ? () => dismissSavedRamp(workflow.txId) : void 0,
|
|
5478
|
+
onExploreRoutes: workflow ? () => {
|
|
5479
|
+
if (!completionLocked.current) resetToInput();
|
|
5480
|
+
} : void 0,
|
|
4890
5481
|
errorMsg,
|
|
4891
5482
|
noticeMsg,
|
|
4892
|
-
onDirectionChange:
|
|
5483
|
+
onDirectionChange: (next) => {
|
|
5484
|
+
setDirection(next);
|
|
5485
|
+
},
|
|
4893
5486
|
onAmountChange: (next) => {
|
|
4894
5487
|
setAmount(next);
|
|
4895
5488
|
setErrorMsg(null);
|
|
@@ -4922,49 +5515,6 @@ function walletNotReadyReason(wallet, chain) {
|
|
|
4922
5515
|
}
|
|
4923
5516
|
return null;
|
|
4924
5517
|
}
|
|
4925
|
-
|
|
4926
|
-
// src/lib/qr-code/index.tsx
|
|
4927
|
-
var import_ErrorCorrectLevel = __toESM(require_ErrorCorrectLevel());
|
|
4928
|
-
var import_QRCode = __toESM(require_QRCode());
|
|
4929
|
-
var QRCodeSvg = react.forwardRef(function QRCodeSvg2({ bgColor, bgD, fgD, fgColor, size, title, viewBoxSize, xmlns = "http://www.w3.org/2000/svg", ...props }, ref) {
|
|
4930
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...props, height: size, ref, viewBox: `0 0 ${viewBoxSize} ${viewBoxSize}`, width: size, xmlns, children: [
|
|
4931
|
-
title ? /* @__PURE__ */ jsxRuntime.jsx("title", { children: title }) : null,
|
|
4932
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: bgD, fill: bgColor }),
|
|
4933
|
-
/* @__PURE__ */ jsxRuntime.jsx("path", { d: fgD, fill: fgColor })
|
|
4934
|
-
] });
|
|
4935
|
-
});
|
|
4936
|
-
QRCodeSvg.displayName = "QRCodeSvg";
|
|
4937
|
-
function bytesToBinaryString(bytes) {
|
|
4938
|
-
return bytes.map((b) => String.fromCharCode(b & 255)).join("");
|
|
4939
|
-
}
|
|
4940
|
-
function encodeStringToUtf8Bytes(input) {
|
|
4941
|
-
return Array.from(new TextEncoder().encode(input));
|
|
4942
|
-
}
|
|
4943
|
-
var QRCode = react.forwardRef(function QRCode2({ bgColor = "#FFFFFF", fgColor = "#000000", level = "L", size = 256, value, ...props }, ref) {
|
|
4944
|
-
const qrcode = new import_QRCode.default(-1, import_ErrorCorrectLevel.default[level]);
|
|
4945
|
-
const utf8Bytes = encodeStringToUtf8Bytes(value);
|
|
4946
|
-
const binaryString = bytesToBinaryString(utf8Bytes);
|
|
4947
|
-
qrcode.addData(binaryString, "Byte");
|
|
4948
|
-
qrcode.make();
|
|
4949
|
-
const cells = qrcode.modules;
|
|
4950
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4951
|
-
QRCodeSvg,
|
|
4952
|
-
{
|
|
4953
|
-
...props,
|
|
4954
|
-
bgColor,
|
|
4955
|
-
bgD: cells.map(
|
|
4956
|
-
(row, rowIndex) => row.map((cell, cellIndex) => !cell ? `M ${cellIndex} ${rowIndex} l 1 0 0 1 -1 0 Z` : "").join(" ")
|
|
4957
|
-
).join(" "),
|
|
4958
|
-
fgColor,
|
|
4959
|
-
fgD: cells.map(
|
|
4960
|
-
(row, rowIndex) => row.map((cell, cellIndex) => cell ? `M ${cellIndex} ${rowIndex} l 1 0 0 1 -1 0 Z` : "").join(" ")
|
|
4961
|
-
).join(" "),
|
|
4962
|
-
ref,
|
|
4963
|
-
size,
|
|
4964
|
-
viewBoxSize: cells.length
|
|
4965
|
-
}
|
|
4966
|
-
);
|
|
4967
|
-
});
|
|
4968
5518
|
function PollarLogo(props) {
|
|
4969
5519
|
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "45", height: "48", viewBox: "0 0 45 48", fill: "none", xmlns: "http://www.w3.org/2000/svg", ...props, children: [
|
|
4970
5520
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4990,7 +5540,7 @@ function PollarLogo(props) {
|
|
|
4990
5540
|
)
|
|
4991
5541
|
] });
|
|
4992
5542
|
}
|
|
4993
|
-
var
|
|
5543
|
+
var CHAIN_NAME2 = {
|
|
4994
5544
|
STELLAR: "Stellar",
|
|
4995
5545
|
POLYGON: "Polygon",
|
|
4996
5546
|
SOLANA: "Solana"
|
|
@@ -5005,11 +5555,13 @@ function ReceiveModalTemplate({
|
|
|
5005
5555
|
onSelectChain,
|
|
5006
5556
|
copied,
|
|
5007
5557
|
notReadyReason,
|
|
5558
|
+
recoveryLocked,
|
|
5559
|
+
onSetupRecovery,
|
|
5008
5560
|
onCopy,
|
|
5009
5561
|
onClose
|
|
5010
5562
|
}) {
|
|
5011
5563
|
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
5012
|
-
const chainName = selectedChain ?
|
|
5564
|
+
const chainName = selectedChain ? CHAIN_NAME2[selectedChain] ?? selectedChain : "wallet";
|
|
5013
5565
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5014
5566
|
"div",
|
|
5015
5567
|
{
|
|
@@ -5023,7 +5575,10 @@ function ReceiveModalTemplate({
|
|
|
5023
5575
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M2 2l12 12M14 2L2 14", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" }) }) }) })
|
|
5024
5576
|
] }),
|
|
5025
5577
|
chains && onSelectChain && /* @__PURE__ */ jsxRuntime.jsx(ChainSelect, { value: selectedChain, options: chains, onChange: onSelectChain }),
|
|
5026
|
-
|
|
5578
|
+
recoveryLocked ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-receive-locked", role: "alert", children: [
|
|
5579
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "Set up a way to recover this wallet before receiving funds. Without one, losing this device means losing whatever you receive, and nobody can get it back." }),
|
|
5580
|
+
onSetupRecovery && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-receive-copy-btn", onClick: onSetupRecovery, children: "Set up recovery" })
|
|
5581
|
+
] }) : walletAddress ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5027
5582
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-receive-qr", children: [
|
|
5028
5583
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-receive-network-badge", children: [
|
|
5029
5584
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-receive-network-dot", "aria-hidden": true }),
|
|
@@ -5091,13 +5646,13 @@ function ReceiveModalTemplate({
|
|
|
5091
5646
|
] })
|
|
5092
5647
|
] })
|
|
5093
5648
|
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No wallet connected." }),
|
|
5094
|
-
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {
|
|
5649
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
5095
5650
|
]
|
|
5096
5651
|
}
|
|
5097
5652
|
);
|
|
5098
5653
|
}
|
|
5099
5654
|
function ReceiveModal({ onClose }) {
|
|
5100
|
-
const { wallet, wallets, styles } = usePollar();
|
|
5655
|
+
const { wallet, wallets, styles, recoveryLocked, openRecoveryModal } = usePollar();
|
|
5101
5656
|
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
5102
5657
|
const [copied, setCopied] = react.useState(false);
|
|
5103
5658
|
const copyTimerRef = react.useRef(null);
|
|
@@ -5139,6 +5694,11 @@ function ReceiveModal({ onClose }) {
|
|
|
5139
5694
|
setSelectedChain(chain);
|
|
5140
5695
|
},
|
|
5141
5696
|
notReadyReason,
|
|
5697
|
+
recoveryLocked,
|
|
5698
|
+
onSetupRecovery: () => {
|
|
5699
|
+
onClose();
|
|
5700
|
+
openRecoveryModal();
|
|
5701
|
+
},
|
|
5142
5702
|
copied,
|
|
5143
5703
|
onCopy: handleCopy,
|
|
5144
5704
|
onClose
|
|
@@ -5154,6 +5714,7 @@ var STATUS_MESSAGES = {
|
|
|
5154
5714
|
submitting: "Submitting transaction\u2026",
|
|
5155
5715
|
submitted: "Submitted \u2014 waiting for confirmation\u2026",
|
|
5156
5716
|
"signing-submitting": "Signing and submitting transaction\u2026",
|
|
5717
|
+
awaiting_cosign: "Waiting for your approval on this device\u2026",
|
|
5157
5718
|
"building-signing-submitting": "Processing transaction\u2026",
|
|
5158
5719
|
success: "Transaction sent successfully",
|
|
5159
5720
|
error: "Transaction failed"
|
|
@@ -5189,14 +5750,22 @@ function TxStatusView({
|
|
|
5189
5750
|
}) {
|
|
5190
5751
|
const buildData = "buildData" in transaction ? transaction.buildData : null;
|
|
5191
5752
|
const hash = transaction.step === "success" ? transaction.hash : null;
|
|
5192
|
-
const errorDetails = transaction.step === "error" ? transaction.details
|
|
5753
|
+
const errorDetails = transaction.step === "error" ? core.transactionErrorMessage(transaction.code, transaction.details) : null;
|
|
5193
5754
|
const isBuilt = transaction.step === "built";
|
|
5194
5755
|
const isInFlight = IN_FLIGHT_STEPS.has(transaction.step);
|
|
5195
5756
|
const isSuccess = transaction.step === "success";
|
|
5196
5757
|
const isError = transaction.step === "error";
|
|
5197
5758
|
const showDetails = buildData !== null && SHOW_DETAILS_STEPS.has(transaction.step);
|
|
5198
|
-
const walletImg = walletType === core.WalletType.FREIGHTER ? LOGO_FREIGHTER : walletType === core.WalletType.ALBEDO ? LOGO_ALBEDO :
|
|
5759
|
+
const walletImg = walletType === core.WalletType.FREIGHTER ? LOGO_FREIGHTER : walletType === core.WalletType.ALBEDO ? LOGO_ALBEDO : null;
|
|
5199
5760
|
const walletAlt = walletType === core.WalletType.FREIGHTER ? "Freighter" : walletType === core.WalletType.ALBEDO ? "Albedo" : "Pollar";
|
|
5761
|
+
const statusBanner = /* @__PURE__ */ jsxRuntime.jsx(
|
|
5762
|
+
ModalStatusBanner,
|
|
5763
|
+
{
|
|
5764
|
+
message: STATUS_MESSAGES[transaction.step],
|
|
5765
|
+
status: isError ? "ERROR" : isInFlight ? "LOADING" : isSuccess ? "SUCCESS" : "NONE"
|
|
5766
|
+
}
|
|
5767
|
+
);
|
|
5768
|
+
const showSpinner = isInFlight || isSuccess || isError;
|
|
5200
5769
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5201
5770
|
showDetails && buildData && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5202
5771
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-summary", children: [
|
|
@@ -5237,7 +5806,7 @@ function TxStatusView({
|
|
|
5237
5806
|
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "pollar-tx-error-details-content", children: errorDetails })
|
|
5238
5807
|
] }),
|
|
5239
5808
|
isBuilt && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-primary pollar-tx-sign-btn", onClick: onSignAndSend, children: "Sign & Send" }),
|
|
5240
|
-
|
|
5809
|
+
showSpinner && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-wallet-spinner", children: [
|
|
5241
5810
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-spinner-ring", children: [
|
|
5242
5811
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5243
5812
|
"svg",
|
|
@@ -5267,8 +5836,12 @@ function TxStatusView({
|
|
|
5267
5836
|
]
|
|
5268
5837
|
}
|
|
5269
5838
|
),
|
|
5270
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-tx-wallet-icon", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: walletImg, alt: walletAlt, className: "pollar-tx-wallet-img" })
|
|
5839
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-tx-wallet-icon", children: walletImg ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: walletImg, alt: walletAlt, className: "pollar-tx-wallet-img" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5840
|
+
/* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR_MARK_ON_LIGHT, alt: walletAlt, className: "pollar-tx-wallet-img pollar-logo-on-light" }),
|
|
5841
|
+
/* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR_MARK_ON_DARK, alt: walletAlt, className: "pollar-tx-wallet-img pollar-logo-on-dark" })
|
|
5842
|
+
] }) })
|
|
5271
5843
|
] }),
|
|
5844
|
+
statusBanner,
|
|
5272
5845
|
isInFlight && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-tx-spinner-label", children: walletType === core.WalletType.FREIGHTER ? "Waiting for Freighter\u2026" : walletType === core.WalletType.ALBEDO ? "Waiting for Albedo\u2026" : "Signing and sending\u2026" }),
|
|
5273
5846
|
isError && onRetry && "buildData" in transaction && transaction.buildData && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-secondary pollar-tx-retry-btn", onClick: onRetry, children: "Try again" })
|
|
5274
5847
|
] }),
|
|
@@ -5333,13 +5906,7 @@ function TxStatusView({
|
|
|
5333
5906
|
] })
|
|
5334
5907
|
] }),
|
|
5335
5908
|
isSuccess && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-primary pollar-tx-sign-btn", onClick: onDone, children: "Done" }),
|
|
5336
|
-
|
|
5337
|
-
ModalStatusBanner,
|
|
5338
|
-
{
|
|
5339
|
-
message: STATUS_MESSAGES[transaction.step],
|
|
5340
|
-
status: isError ? "ERROR" : isInFlight ? "LOADING" : isSuccess ? "SUCCESS" : "NONE"
|
|
5341
|
-
}
|
|
5342
|
-
)
|
|
5909
|
+
!showSpinner && statusBanner
|
|
5343
5910
|
] });
|
|
5344
5911
|
}
|
|
5345
5912
|
function formatBalance(balance) {
|
|
@@ -5356,6 +5923,11 @@ function chainLabel(chain) {
|
|
|
5356
5923
|
if (chain === "POLYGON") return "Polygon";
|
|
5357
5924
|
return "network";
|
|
5358
5925
|
}
|
|
5926
|
+
function destinationPlaceholder(chain) {
|
|
5927
|
+
if (chain === "SOLANA") return "Solana address";
|
|
5928
|
+
if (chain === "POLYGON") return "0x\u2026";
|
|
5929
|
+
return "G\u2026";
|
|
5930
|
+
}
|
|
5359
5931
|
function AssetIcon({ code }) {
|
|
5360
5932
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-asset-icon", "aria-hidden": true, children: code.slice(0, 2).toUpperCase() });
|
|
5361
5933
|
}
|
|
@@ -5473,6 +6045,10 @@ function SendModalTemplate({
|
|
|
5473
6045
|
onMax,
|
|
5474
6046
|
onPaste,
|
|
5475
6047
|
onDestinationChange,
|
|
6048
|
+
memo = "",
|
|
6049
|
+
memoType = "text",
|
|
6050
|
+
onMemoChange,
|
|
6051
|
+
onMemoTypeChange,
|
|
5476
6052
|
onSubmit,
|
|
5477
6053
|
onSignAndSend,
|
|
5478
6054
|
onToggleXdr,
|
|
@@ -5580,7 +6156,7 @@ function SendModalTemplate({
|
|
|
5580
6156
|
{
|
|
5581
6157
|
className: "pollar-input pollar-send-destination-input",
|
|
5582
6158
|
type: "text",
|
|
5583
|
-
placeholder:
|
|
6159
|
+
placeholder: destinationPlaceholder(selectedChain),
|
|
5584
6160
|
value: destination,
|
|
5585
6161
|
onChange: (e) => onDestinationChange(e.target.value),
|
|
5586
6162
|
"aria-label": "Destination wallet"
|
|
@@ -5589,6 +6165,39 @@ function SendModalTemplate({
|
|
|
5589
6165
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-send-inline-action", onClick: onPaste, children: "Paste" })
|
|
5590
6166
|
] })
|
|
5591
6167
|
] }),
|
|
6168
|
+
selectedChain === "STELLAR" && onMemoChange && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
|
|
6169
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-send-label", htmlFor: "pollar-send-memo", children: [
|
|
6170
|
+
"Memo ",
|
|
6171
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-label-optional", children: "(optional)" })
|
|
6172
|
+
] }),
|
|
6173
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-memo-row", children: [
|
|
6174
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
6175
|
+
"select",
|
|
6176
|
+
{
|
|
6177
|
+
className: "pollar-input pollar-send-memo-type",
|
|
6178
|
+
value: memoType,
|
|
6179
|
+
onChange: (e) => onMemoTypeChange?.(e.target.value),
|
|
6180
|
+
"aria-label": "Memo type",
|
|
6181
|
+
children: [
|
|
6182
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "text", children: "Text" }),
|
|
6183
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "id", children: "ID" })
|
|
6184
|
+
]
|
|
6185
|
+
}
|
|
6186
|
+
),
|
|
6187
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6188
|
+
"input",
|
|
6189
|
+
{
|
|
6190
|
+
id: "pollar-send-memo",
|
|
6191
|
+
className: "pollar-input pollar-send-memo-input",
|
|
6192
|
+
type: "text",
|
|
6193
|
+
inputMode: memoType === "id" ? "numeric" : "text",
|
|
6194
|
+
placeholder: memoType === "id" ? "123456789" : "Up to 28 characters",
|
|
6195
|
+
value: memo,
|
|
6196
|
+
onChange: (e) => onMemoChange(e.target.value)
|
|
6197
|
+
}
|
|
6198
|
+
)
|
|
6199
|
+
] })
|
|
6200
|
+
] }),
|
|
5592
6201
|
formError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: formError }),
|
|
5593
6202
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-primary", onClick: onSubmit, disabled: !canSubmit, children: "Continue" }) })
|
|
5594
6203
|
] }),
|
|
@@ -5612,6 +6221,21 @@ function SendModalTemplate({
|
|
|
5612
6221
|
}
|
|
5613
6222
|
);
|
|
5614
6223
|
}
|
|
6224
|
+
var MAX_MEMO_ID = 18446744073709551615n;
|
|
6225
|
+
var SOLANA_FEE_MARGIN_LAMPORTS = 10000n;
|
|
6226
|
+
function solanaMaxAfterFee(available) {
|
|
6227
|
+
const lamports = BigInt(core.toBaseUnits(available, 9)) - SOLANA_FEE_MARGIN_LAMPORTS;
|
|
6228
|
+
return core.fromBaseUnits((lamports > 0n ? lamports : 0n).toString(), 9);
|
|
6229
|
+
}
|
|
6230
|
+
function parseMemo(type, raw) {
|
|
6231
|
+
const value = type === "id" ? raw.trim() : raw;
|
|
6232
|
+
if (value.trim() === "") return void 0;
|
|
6233
|
+
if (type === "text") {
|
|
6234
|
+
return new TextEncoder().encode(value).length > 28 ? "The memo text can be at most 28 bytes." : { type, value };
|
|
6235
|
+
}
|
|
6236
|
+
if (!/^\d+$/.test(value) || BigInt(value) > MAX_MEMO_ID) return "The memo ID must be a whole number up to 2^64 - 1.";
|
|
6237
|
+
return { type, value };
|
|
6238
|
+
}
|
|
5615
6239
|
function assetParam(record) {
|
|
5616
6240
|
if (record.type === "native") return { type: "native" };
|
|
5617
6241
|
if (record.type === "credit_alphanum4") {
|
|
@@ -5636,6 +6260,8 @@ function SendModal({ onClose }) {
|
|
|
5636
6260
|
const [step, setStep] = react.useState("form");
|
|
5637
6261
|
const [amount, setAmount] = react.useState("");
|
|
5638
6262
|
const [destination, setDestination] = react.useState("");
|
|
6263
|
+
const [memo, setMemo] = react.useState("");
|
|
6264
|
+
const [memoType, setMemoType] = react.useState("text");
|
|
5639
6265
|
const [selectedAsset, setSelectedAsset] = react.useState(null);
|
|
5640
6266
|
const [showXdr, setShowXdr] = react.useState(false);
|
|
5641
6267
|
const [copied, setCopied] = react.useState(false);
|
|
@@ -5646,9 +6272,10 @@ function SendModal({ onClose }) {
|
|
|
5646
6272
|
react.useEffect(() => {
|
|
5647
6273
|
if (selectedChain === null && chains.length > 0) setSelectedChain(chains[0]);
|
|
5648
6274
|
}, [chains, selectedChain]);
|
|
5649
|
-
const canSendOnChain = selectedChain === "STELLAR" || selectedChain === "SOLANA";
|
|
6275
|
+
const canSendOnChain = selectedChain === "STELLAR" || selectedChain === "SOLANA" || selectedChain === "POLYGON";
|
|
5650
6276
|
const notReadyReason = walletNotReadyReason(wallet, selectedChain);
|
|
5651
|
-
const isBaseUnitChain = selectedChain === "SOLANA";
|
|
6277
|
+
const isBaseUnitChain = selectedChain === "SOLANA" || selectedChain === "POLYGON";
|
|
6278
|
+
const nativeDecimals = selectedChain === "POLYGON" ? 18 : 9;
|
|
5652
6279
|
react.useEffect(() => {
|
|
5653
6280
|
void refreshWalletBalance();
|
|
5654
6281
|
}, [refreshWalletBalance]);
|
|
@@ -5676,7 +6303,7 @@ function SendModal({ onClose }) {
|
|
|
5676
6303
|
const hash = transaction.step === "success" ? transaction.hash : null;
|
|
5677
6304
|
const buildData = "buildData" in transaction ? transaction.buildData : null;
|
|
5678
6305
|
const explorerNetwork = buildData?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : buildData ? "public" : network === "testnet" ? "testnet" : "public";
|
|
5679
|
-
const explorerUrl = !hash ? null : selectedChain === "SOLANA" ? `https://explorer.solana.com/tx/${hash}${explorerNetwork === "testnet" ? "?cluster=devnet" : ""}` : `https://stellar.expert/explorer/${explorerNetwork}/tx/${hash}`;
|
|
6306
|
+
const explorerUrl = !hash ? null : selectedChain === "SOLANA" ? `https://explorer.solana.com/tx/${hash}${explorerNetwork === "testnet" ? "?cluster=devnet" : ""}` : selectedChain === "POLYGON" ? `https://${explorerNetwork === "testnet" ? "amoy." : ""}polygonscan.com/tx/${hash}` : `https://stellar.expert/explorer/${explorerNetwork}/tx/${hash}`;
|
|
5680
6307
|
const IN_FLIGHT_STEPS3 = [
|
|
5681
6308
|
"building",
|
|
5682
6309
|
"signing",
|
|
@@ -5715,33 +6342,42 @@ function SendModal({ onClose }) {
|
|
|
5715
6342
|
setFormError("Enter a destination address");
|
|
5716
6343
|
return;
|
|
5717
6344
|
}
|
|
6345
|
+
const parsedMemo = selectedChain === "STELLAR" ? parseMemo(memoType, memo) : void 0;
|
|
6346
|
+
if (typeof parsedMemo === "string") {
|
|
6347
|
+
setFormError(parsedMemo);
|
|
6348
|
+
return;
|
|
6349
|
+
}
|
|
5718
6350
|
const isNativeAsset = selectedAsset.type === "native";
|
|
5719
6351
|
if (isBaseUnitChain && !isNativeAsset && (!selectedAsset.issuer || selectedAsset.decimals === void 0)) {
|
|
5720
|
-
setFormError("This token is missing its
|
|
6352
|
+
setFormError("This token is missing its contract or decimals and cannot be sent.");
|
|
5721
6353
|
return;
|
|
5722
6354
|
}
|
|
5723
6355
|
let sendAmount = amount;
|
|
5724
6356
|
if (isBaseUnitChain) {
|
|
5725
6357
|
try {
|
|
5726
|
-
sendAmount = core.toBaseUnits(amount, selectedAsset.decimals ??
|
|
6358
|
+
sendAmount = core.toBaseUnits(amount, selectedAsset.decimals ?? nativeDecimals);
|
|
5727
6359
|
} catch (e) {
|
|
5728
6360
|
setFormError(e instanceof Error ? e.message : "Invalid amount");
|
|
5729
6361
|
return;
|
|
5730
6362
|
}
|
|
5731
6363
|
}
|
|
5732
6364
|
setStep("tx");
|
|
5733
|
-
if (selectedChain === "SOLANA") {
|
|
6365
|
+
if (selectedChain === "SOLANA" || selectedChain === "POLYGON") {
|
|
5734
6366
|
await sendPayment({
|
|
5735
|
-
chain:
|
|
6367
|
+
chain: selectedChain,
|
|
5736
6368
|
destination: destination.trim(),
|
|
5737
6369
|
amount: sendAmount,
|
|
5738
|
-
//
|
|
5739
|
-
// which the guard above proved is present.
|
|
6370
|
+
// A native coin carries no token id; an SPL mint or ERC-20 contract rides
|
|
6371
|
+
// in `issuer`, which the guard above proved is present.
|
|
5740
6372
|
...isNativeAsset ? {} : { mint: selectedAsset.issuer }
|
|
5741
6373
|
});
|
|
5742
6374
|
return;
|
|
5743
6375
|
}
|
|
5744
|
-
await buildTx(
|
|
6376
|
+
await buildTx(
|
|
6377
|
+
"payment",
|
|
6378
|
+
{ destination: destination.trim(), amount, asset: assetParam(selectedAsset) },
|
|
6379
|
+
parsedMemo ? { memo: parsedMemo } : void 0
|
|
6380
|
+
);
|
|
5745
6381
|
}
|
|
5746
6382
|
function handleSignAndSend() {
|
|
5747
6383
|
if (transaction.step === "built") {
|
|
@@ -5750,7 +6386,15 @@ function SendModal({ onClose }) {
|
|
|
5750
6386
|
}
|
|
5751
6387
|
function handleMax() {
|
|
5752
6388
|
if (selectedAsset?.available !== null && selectedAsset?.available !== void 0) {
|
|
5753
|
-
|
|
6389
|
+
const paysOwnSolFee = selectedChain === "SOLANA" && selectedAsset.type === "native" && selectedAsset.sponsored !== true;
|
|
6390
|
+
let max = selectedAsset.available;
|
|
6391
|
+
if (paysOwnSolFee) {
|
|
6392
|
+
try {
|
|
6393
|
+
max = solanaMaxAfterFee(selectedAsset.available);
|
|
6394
|
+
} catch {
|
|
6395
|
+
}
|
|
6396
|
+
}
|
|
6397
|
+
setAmount(max);
|
|
5754
6398
|
setFormError("");
|
|
5755
6399
|
}
|
|
5756
6400
|
}
|
|
@@ -5826,6 +6470,10 @@ function SendModal({ onClose }) {
|
|
|
5826
6470
|
onMax: handleMax,
|
|
5827
6471
|
onPaste: handlePaste,
|
|
5828
6472
|
onDestinationChange: setDestination,
|
|
6473
|
+
memo,
|
|
6474
|
+
memoType,
|
|
6475
|
+
onMemoChange: setMemo,
|
|
6476
|
+
onMemoTypeChange: setMemoType,
|
|
5829
6477
|
onSubmit: () => void handleSubmit(),
|
|
5830
6478
|
onSignAndSend: handleSignAndSend,
|
|
5831
6479
|
onToggleXdr: () => setShowXdr((v) => !v),
|
|
@@ -6233,7 +6881,7 @@ function SwapModalTemplate({
|
|
|
6233
6881
|
onDone
|
|
6234
6882
|
}
|
|
6235
6883
|
),
|
|
6236
|
-
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {
|
|
6884
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
6237
6885
|
]
|
|
6238
6886
|
}
|
|
6239
6887
|
);
|
|
@@ -6945,9 +7593,12 @@ function EarnModal({ onClose }) {
|
|
|
6945
7593
|
var nonEmpty2 = (value) => typeof value === "string" && !!value.trim();
|
|
6946
7594
|
function requiredCardStep(error) {
|
|
6947
7595
|
if (!error || typeof error !== "object") return null;
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
7596
|
+
if (!("code" in error) || error.code !== "SDK_CARDS_REQUIREMENT_REQUIRED") return null;
|
|
7597
|
+
const body = "body" in error ? error.body : void 0;
|
|
7598
|
+
if (typeof body !== "object" || body === null) return null;
|
|
7599
|
+
const cardProviderId = "cardProviderId" in body ? body.cardProviderId : void 0;
|
|
7600
|
+
const requirementType = "requirementType" in body ? body.requirementType : void 0;
|
|
7601
|
+
const optionId = "optionId" in body ? body.optionId : void 0;
|
|
6951
7602
|
if (!nonEmpty2(cardProviderId) || !nonEmpty2(optionId)) return null;
|
|
6952
7603
|
if (requirementType === "KYC" || requirementType === "FORM" || requirementType === "REGISTRY_CHECK" || requirementType === "PROVIDER_REGISTRATION") {
|
|
6953
7604
|
return { cardProviderId, type: requirementType, optionId };
|
|
@@ -7601,15 +8252,17 @@ function CardModal({ onClose }) {
|
|
|
7601
8252
|
transactions === null && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-note", children: "Loading..." }),
|
|
7602
8253
|
transactions?.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-card-note", children: "No movements yet." }),
|
|
7603
8254
|
transactions?.map((tx) => {
|
|
7604
|
-
const
|
|
7605
|
-
const
|
|
8255
|
+
const localAmount = typeof tx.purchase?.localAmount === "number" ? tx.purchase.localAmount : null;
|
|
8256
|
+
const localCurrency = typeof tx.purchase?.localCurrency === "string" ? tx.purchase.localCurrency : null;
|
|
8257
|
+
const purchaseStatus = typeof tx.purchase?.status === "string" ? tx.purchase.status : null;
|
|
8258
|
+
const local = localAmount && localCurrency && localCurrency !== "USD" ? money(String(localAmount), localCurrency) : null;
|
|
7606
8259
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-tx", children: [
|
|
7607
8260
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
7608
8261
|
tx.merchantName ?? TX_LABELS[tx.type] ?? tx.type,
|
|
7609
8262
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-card-tx-meta", children: [
|
|
7610
8263
|
new Date(tx.occurredAt).toLocaleDateString(),
|
|
7611
8264
|
tx.merchantName ? ` \xB7 ${TX_LABELS[tx.type] ?? tx.type}` : "",
|
|
7612
|
-
|
|
8265
|
+
purchaseStatus && purchaseStatus !== "completed" ? ` \xB7 ${purchaseStatus}` : ""
|
|
7613
8266
|
] })
|
|
7614
8267
|
] }),
|
|
7615
8268
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-card-tx-amount", "data-direction": tx.direction ?? void 0, children: [
|
|
@@ -7979,6 +8632,843 @@ function SessionsModal({ onClose }) {
|
|
|
7979
8632
|
}
|
|
7980
8633
|
) });
|
|
7981
8634
|
}
|
|
8635
|
+
function useCosign() {
|
|
8636
|
+
const { getClient, isAuthenticated } = usePollar();
|
|
8637
|
+
const [state, setState] = react.useState({ pending: [] });
|
|
8638
|
+
const [loaded, setLoaded] = react.useState(false);
|
|
8639
|
+
react.useEffect(() => getClient().onCosignStateChange(setState), [getClient]);
|
|
8640
|
+
const refresh = react.useCallback(async () => {
|
|
8641
|
+
if (!isAuthenticated) return;
|
|
8642
|
+
try {
|
|
8643
|
+
await getClient().cosign.pending();
|
|
8644
|
+
} finally {
|
|
8645
|
+
setLoaded(true);
|
|
8646
|
+
}
|
|
8647
|
+
}, [getClient, isAuthenticated]);
|
|
8648
|
+
react.useEffect(() => {
|
|
8649
|
+
void refresh();
|
|
8650
|
+
}, [refresh]);
|
|
8651
|
+
return {
|
|
8652
|
+
pending: state.pending,
|
|
8653
|
+
...state.lastResolved ? { lastResolved: state.lastResolved } : {},
|
|
8654
|
+
loaded,
|
|
8655
|
+
refresh,
|
|
8656
|
+
approve: react.useCallback((request) => getClient().cosign.approve(request), [getClient]),
|
|
8657
|
+
reject: react.useCallback((request) => getClient().cosign.reject(request), [getClient]),
|
|
8658
|
+
verify: react.useCallback((request) => getClient().cosign.verify(request), [getClient]),
|
|
8659
|
+
inspectQuorum: react.useCallback(() => getClient().cosign.inspectQuorum(), [getClient]),
|
|
8660
|
+
devices: react.useCallback(() => getClient().cosign.devices(), [getClient]),
|
|
8661
|
+
revokeDevice: react.useCallback(
|
|
8662
|
+
(deviceId, options) => getClient().cosign.revokeDevice(deviceId, options),
|
|
8663
|
+
[getClient]
|
|
8664
|
+
),
|
|
8665
|
+
switchCustody: react.useCallback((to) => getClient().cosign.switchCustody(to), [getClient])
|
|
8666
|
+
};
|
|
8667
|
+
}
|
|
8668
|
+
var OPERATION_LABELS = {
|
|
8669
|
+
payment: "Send",
|
|
8670
|
+
path_payment_strict_send: "Swap",
|
|
8671
|
+
change_trust: "Add asset",
|
|
8672
|
+
create_account: "Create account",
|
|
8673
|
+
invoke_contract: "Contract call",
|
|
8674
|
+
manage_data: "Manage data"
|
|
8675
|
+
};
|
|
8676
|
+
function labelOf(request) {
|
|
8677
|
+
const op = request.operation ?? "";
|
|
8678
|
+
return OPERATION_LABELS[op] ?? (op ? op.replace(/_/g, " ") : "Transaction");
|
|
8679
|
+
}
|
|
8680
|
+
function expiresIn(request) {
|
|
8681
|
+
const ms = new Date(request.expiresAt).getTime() - Date.now();
|
|
8682
|
+
if (!Number.isFinite(ms) || ms <= 0) return "expired";
|
|
8683
|
+
const h = Math.floor(ms / 36e5);
|
|
8684
|
+
const m = Math.floor(ms % 36e5 / 6e4);
|
|
8685
|
+
return h > 0 ? `${h}h ${m}m` : `${m}m`;
|
|
8686
|
+
}
|
|
8687
|
+
function readableAmount(details) {
|
|
8688
|
+
const { amount, decimals, symbol } = details;
|
|
8689
|
+
if (typeof amount !== "string" || typeof decimals !== "number" || typeof symbol !== "string") return null;
|
|
8690
|
+
try {
|
|
8691
|
+
return { amount: core.fromBaseUnits(amount, decimals), symbol };
|
|
8692
|
+
} catch {
|
|
8693
|
+
return null;
|
|
8694
|
+
}
|
|
8695
|
+
}
|
|
8696
|
+
function detailRows(request) {
|
|
8697
|
+
const details = request.details ?? {};
|
|
8698
|
+
const rows = [];
|
|
8699
|
+
const push = (label, value) => {
|
|
8700
|
+
if (value === void 0 || value === null || value === "") return;
|
|
8701
|
+
rows.push([
|
|
8702
|
+
label,
|
|
8703
|
+
typeof value === "string" && value.length > 24 && /^[GC][A-Z2-7]{55}$/.test(value) ? cropAddress(value) : String(value)
|
|
8704
|
+
]);
|
|
8705
|
+
};
|
|
8706
|
+
push("Destination", details.destination);
|
|
8707
|
+
const readable = readableAmount(details);
|
|
8708
|
+
push("Amount", readable ? `${readable.amount} ${readable.symbol}` : details.amount);
|
|
8709
|
+
push("Asset", details.asset ?? details.assetCode ?? readable?.symbol);
|
|
8710
|
+
push("Network", request.network);
|
|
8711
|
+
return rows;
|
|
8712
|
+
}
|
|
8713
|
+
function CloseIcon2() {
|
|
8714
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m3 3 8 8M11 3l-8 8", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
|
|
8715
|
+
}
|
|
8716
|
+
function CosignModalTemplate({
|
|
8717
|
+
theme,
|
|
8718
|
+
accentColor,
|
|
8719
|
+
styleOverrides,
|
|
8720
|
+
pending,
|
|
8721
|
+
current,
|
|
8722
|
+
verification,
|
|
8723
|
+
busy,
|
|
8724
|
+
error,
|
|
8725
|
+
approveBlocked = false,
|
|
8726
|
+
lastResolved,
|
|
8727
|
+
explorerUrl,
|
|
8728
|
+
onSelect,
|
|
8729
|
+
onApprove,
|
|
8730
|
+
onReject,
|
|
8731
|
+
onClose
|
|
8732
|
+
}) {
|
|
8733
|
+
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
8734
|
+
const verified = verification?.ok === true;
|
|
8735
|
+
const canVote = !!current && verified && !busy && !approveBlocked;
|
|
8736
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8737
|
+
"div",
|
|
8738
|
+
{
|
|
8739
|
+
className: "pollar-modal-card pollar-cosign-modal",
|
|
8740
|
+
"data-theme": theme,
|
|
8741
|
+
style: cssVars,
|
|
8742
|
+
onClick: (e) => e.stopPropagation(),
|
|
8743
|
+
children: [
|
|
8744
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
8745
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Confirm with your device" }),
|
|
8746
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", title: "Close", children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon2, {}) }) })
|
|
8747
|
+
] }),
|
|
8748
|
+
pending.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-cosign-empty", children: lastResolved ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8749
|
+
lastResolved.status === "APPROVED" && /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "pollar-cosign-approved-icon", width: "44", height: "44", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
|
|
8750
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
|
|
8751
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8752
|
+
"path",
|
|
8753
|
+
{
|
|
8754
|
+
d: "M3.5 7l2.5 2.5 4.5-5",
|
|
8755
|
+
stroke: "white",
|
|
8756
|
+
strokeWidth: "1.2",
|
|
8757
|
+
strokeLinecap: "round",
|
|
8758
|
+
strokeLinejoin: "round"
|
|
8759
|
+
}
|
|
8760
|
+
)
|
|
8761
|
+
] }),
|
|
8762
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-empty-title", children: lastResolved.status === "APPROVED" ? "Approved" : lastResolved.status === "REJECTED" ? "Rejected" : lastResolved.status.toLowerCase() }),
|
|
8763
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: lastResolved.submit?.hash ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8764
|
+
"Sent. Transaction",
|
|
8765
|
+
" ",
|
|
8766
|
+
explorerUrl ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "pollar-cosign-tx-link", href: explorerUrl, target: "_blank", rel: "noopener noreferrer", children: cropAddress(lastResolved.submit.hash) }) : cropAddress(lastResolved.submit.hash)
|
|
8767
|
+
] }) : lastResolved.signedXdr ? "Signed. The app will send it." : "Nothing was signed." })
|
|
8768
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: "Nothing waits for your approval." }) }),
|
|
8769
|
+
pending.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "pollar-cosign-list", children: pending.map((r) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8770
|
+
"button",
|
|
8771
|
+
{
|
|
8772
|
+
type: "button",
|
|
8773
|
+
className: `pollar-cosign-item${current?.id === r.id ? " pollar-cosign-item-active" : ""}`,
|
|
8774
|
+
onClick: () => onSelect(r),
|
|
8775
|
+
children: [
|
|
8776
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: labelOf(r) }),
|
|
8777
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-cosign-muted", children: expiresIn(r) })
|
|
8778
|
+
]
|
|
8779
|
+
}
|
|
8780
|
+
) }, r.id)) }),
|
|
8781
|
+
current && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-detail", children: [
|
|
8782
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-detail-title", children: labelOf(current) }),
|
|
8783
|
+
current.summary && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: current.summary }),
|
|
8784
|
+
/* @__PURE__ */ jsxRuntime.jsxs("dl", { className: "pollar-cosign-rows", children: [
|
|
8785
|
+
detailRows(current).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-row", children: [
|
|
8786
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: k }),
|
|
8787
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: v })
|
|
8788
|
+
] }, k)),
|
|
8789
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-row", children: [
|
|
8790
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Expires in" }),
|
|
8791
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: expiresIn(current) })
|
|
8792
|
+
] })
|
|
8793
|
+
] }),
|
|
8794
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8795
|
+
"div",
|
|
8796
|
+
{
|
|
8797
|
+
className: `pollar-cosign-verify pollar-cosign-verify-${verification ? verification.ok ? "ok" : "bad" : "pending"}`,
|
|
8798
|
+
children: [
|
|
8799
|
+
!verification && "Checking the transaction against Turnkey...",
|
|
8800
|
+
verification?.ok && "Verified: this is exactly what will be signed.",
|
|
8801
|
+
verification && !verification.ok && `Not verified: ${verification.reason}`
|
|
8802
|
+
]
|
|
8803
|
+
}
|
|
8804
|
+
),
|
|
8805
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-cosign-error", children: error }),
|
|
8806
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-actions", children: [
|
|
8807
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8808
|
+
"button",
|
|
8809
|
+
{
|
|
8810
|
+
type: "button",
|
|
8811
|
+
className: "pollar-cosign-btn pollar-cosign-btn-secondary",
|
|
8812
|
+
disabled: !!busy,
|
|
8813
|
+
onClick: () => onReject(current),
|
|
8814
|
+
children: busy === "rejecting" ? "Rejecting..." : "Reject"
|
|
8815
|
+
}
|
|
8816
|
+
),
|
|
8817
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8818
|
+
"button",
|
|
8819
|
+
{
|
|
8820
|
+
type: "button",
|
|
8821
|
+
className: "pollar-cosign-btn pollar-cosign-btn-primary",
|
|
8822
|
+
disabled: !canVote,
|
|
8823
|
+
onClick: () => onApprove(current),
|
|
8824
|
+
children: busy === "approving" ? "Approving..." : "Approve"
|
|
8825
|
+
}
|
|
8826
|
+
)
|
|
8827
|
+
] })
|
|
8828
|
+
] }),
|
|
8829
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
8830
|
+
]
|
|
8831
|
+
}
|
|
8832
|
+
);
|
|
8833
|
+
}
|
|
8834
|
+
function CosignModal({ onClose }) {
|
|
8835
|
+
const { getClient, styles, network } = usePollar();
|
|
8836
|
+
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
8837
|
+
const { pending, lastResolved, approve, reject, verify, inspectQuorum } = useCosign();
|
|
8838
|
+
const [selectedId, setSelectedId] = react.useState(null);
|
|
8839
|
+
const [verification, setVerification] = react.useState(null);
|
|
8840
|
+
const [busy, setBusy] = react.useState(null);
|
|
8841
|
+
const [error, setError] = react.useState(null);
|
|
8842
|
+
const [approveFailedFor, setApproveFailedFor] = react.useState(null);
|
|
8843
|
+
const [quorumFailure, setQuorumFailure] = react.useState(null);
|
|
8844
|
+
react.useEffect(() => {
|
|
8845
|
+
let cancelled = false;
|
|
8846
|
+
inspectQuorum().then((q) => {
|
|
8847
|
+
if (!cancelled && !q.ok) setQuorumFailure(q.reason);
|
|
8848
|
+
}).catch(() => void 0);
|
|
8849
|
+
return () => {
|
|
8850
|
+
cancelled = true;
|
|
8851
|
+
};
|
|
8852
|
+
}, [inspectQuorum]);
|
|
8853
|
+
const current = pending.find((r) => r.id === selectedId) ?? pending[0] ?? null;
|
|
8854
|
+
const currentRef = react.useRef(current);
|
|
8855
|
+
currentRef.current = current;
|
|
8856
|
+
const currentId = current?.id ?? null;
|
|
8857
|
+
react.useEffect(() => {
|
|
8858
|
+
const request = currentRef.current;
|
|
8859
|
+
if (!request) return;
|
|
8860
|
+
setVerification(null);
|
|
8861
|
+
setError(null);
|
|
8862
|
+
setApproveFailedFor(null);
|
|
8863
|
+
let cancelled = false;
|
|
8864
|
+
verify(request).then((v) => {
|
|
8865
|
+
if (!cancelled) setVerification(v);
|
|
8866
|
+
}).catch((err) => {
|
|
8867
|
+
if (!cancelled) setVerification({ ok: false, reason: err instanceof Error ? err.message : String(err) });
|
|
8868
|
+
});
|
|
8869
|
+
return () => {
|
|
8870
|
+
cancelled = true;
|
|
8871
|
+
};
|
|
8872
|
+
}, [currentId, verify]);
|
|
8873
|
+
const onCloseRef = react.useRef(onClose);
|
|
8874
|
+
onCloseRef.current = onClose;
|
|
8875
|
+
react.useEffect(() => {
|
|
8876
|
+
return getClient().onAuthStateChange((authState) => {
|
|
8877
|
+
if (authState.step === "idle") onCloseRef.current();
|
|
8878
|
+
});
|
|
8879
|
+
}, [getClient]);
|
|
8880
|
+
const run = react.useCallback(
|
|
8881
|
+
async (kind, request, action) => {
|
|
8882
|
+
setBusy(kind);
|
|
8883
|
+
setError(null);
|
|
8884
|
+
try {
|
|
8885
|
+
await action(request);
|
|
8886
|
+
} catch (err) {
|
|
8887
|
+
setError(core.transactionErrorMessage(core.isPollarApiError(err) ? err.code : null, err instanceof Error ? err.message : null));
|
|
8888
|
+
if (kind === "approving") setApproveFailedFor(request.id);
|
|
8889
|
+
} finally {
|
|
8890
|
+
setBusy(null);
|
|
8891
|
+
}
|
|
8892
|
+
},
|
|
8893
|
+
[]
|
|
8894
|
+
);
|
|
8895
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8896
|
+
CosignModalTemplate,
|
|
8897
|
+
{
|
|
8898
|
+
theme,
|
|
8899
|
+
accentColor,
|
|
8900
|
+
styleOverrides,
|
|
8901
|
+
pending,
|
|
8902
|
+
current,
|
|
8903
|
+
verification: current ? quorumFailure ? { ok: false, reason: quorumFailure } : verification : null,
|
|
8904
|
+
busy,
|
|
8905
|
+
error,
|
|
8906
|
+
approveBlocked: !!current && approveFailedFor === current.id,
|
|
8907
|
+
...lastResolved ? { lastResolved } : {},
|
|
8908
|
+
explorerUrl: lastResolved?.submit?.hash ? explorerTxUrl(lastResolved.network, lastResolved.submit.hash, network) : null,
|
|
8909
|
+
onSelect: (r) => setSelectedId(r.id),
|
|
8910
|
+
onApprove: (r) => void run("approving", r, approve),
|
|
8911
|
+
onReject: (r) => void run("rejecting", r, reject),
|
|
8912
|
+
onClose
|
|
8913
|
+
}
|
|
8914
|
+
) });
|
|
8915
|
+
}
|
|
8916
|
+
var CHAIN_NAME3 = { STELLAR: "Stellar", SOLANA: "Solana", POLYGON: "Polygon" };
|
|
8917
|
+
var short = (address) => `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
8918
|
+
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.";
|
|
8919
|
+
function CustodyMigrationModalTemplate(p) {
|
|
8920
|
+
const cssVars = buildModalCssVars(p.theme, p.accentColor, p.styleOverrides);
|
|
8921
|
+
const [pick, setPick] = react.useState(p.state.choice ? null : p.state.toCustody);
|
|
8922
|
+
const [risksAccepted, setRisksAccepted] = react.useState(false);
|
|
8923
|
+
const custody = p.state.choice ? pick : p.state.toCustody;
|
|
8924
|
+
const canMove = !!custody && (custody !== "SELF_CUSTODY" || risksAccepted) && !p.busy;
|
|
8925
|
+
const moving = p.state.wallets.filter((w) => w.required);
|
|
8926
|
+
const changing = moving.filter((w) => w.addressChanges);
|
|
8927
|
+
const failed = moving.some((w) => w.status === "FAILED");
|
|
8928
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-card pollar-recovery-modal", "data-theme": p.theme, style: cssVars, children: [
|
|
8929
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header", children: /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Move your wallets to this device" }) }),
|
|
8930
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-body", children: [
|
|
8931
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "Until now Pollar held the keys of your wallets. This app now keeps wallets on its users' devices, so they move here, with everything they hold." }),
|
|
8932
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-recovery-section", children: [
|
|
8933
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: "What moves" }),
|
|
8934
|
+
moving.map((w) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-item", children: [
|
|
8935
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
8936
|
+
CHAIN_NAME3[w.chain] ?? w.chain,
|
|
8937
|
+
" \xB7 ",
|
|
8938
|
+
short(w.address)
|
|
8939
|
+
] }),
|
|
8940
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-recovery-tag", children: w.addressChanges ? "New address" : "Same address" })
|
|
8941
|
+
] }, w.chain))
|
|
8942
|
+
] }),
|
|
8943
|
+
changing.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "alert", children: [
|
|
8944
|
+
"Your ",
|
|
8945
|
+
changing.map((w) => CHAIN_NAME3[w.chain] ?? w.chain).join(" and "),
|
|
8946
|
+
" 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."
|
|
8947
|
+
] }),
|
|
8948
|
+
p.state.choice && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-recovery-section", children: [
|
|
8949
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Choose how your wallet signs" }),
|
|
8950
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-recovery-check", children: [
|
|
8951
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "radio", name: "custody", checked: pick === "COSIGNED", onChange: () => setPick("COSIGNED") }),
|
|
8952
|
+
" ",
|
|
8953
|
+
"Co-signed: you and the app approve every signature together, and the wallet can be recovered with help."
|
|
8954
|
+
] }),
|
|
8955
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-recovery-check", children: [
|
|
8956
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "radio", name: "custody", checked: pick === "SELF_CUSTODY", onChange: () => setPick("SELF_CUSTODY") }),
|
|
8957
|
+
" ",
|
|
8958
|
+
"Self-custody: only your device signs. Nobody else can move or recover your funds."
|
|
8959
|
+
] })
|
|
8960
|
+
] }),
|
|
8961
|
+
custody === "SELF_CUSTODY" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
8962
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "alert", children: SELF_CUSTODY_RISKS }),
|
|
8963
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-recovery-check", children: [
|
|
8964
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: risksAccepted, onChange: (e) => setRisksAccepted(e.target.checked) }),
|
|
8965
|
+
" I understand and accept these risks"
|
|
8966
|
+
] })
|
|
8967
|
+
] }),
|
|
8968
|
+
failed && !p.error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-error", role: "alert", children: "The last attempt did not finish. What did not move is still where it was; try again." }),
|
|
8969
|
+
p.blockedReasons && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "alert", children: [
|
|
8970
|
+
"A wallet cannot move while something still uses it: ",
|
|
8971
|
+
p.blockedReasons.join(", "),
|
|
8972
|
+
". Let it finish and try again."
|
|
8973
|
+
] }),
|
|
8974
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8975
|
+
"button",
|
|
8976
|
+
{
|
|
8977
|
+
type: "button",
|
|
8978
|
+
className: "pollar-recovery-btn pollar-recovery-btn-primary",
|
|
8979
|
+
onClick: () => custody && p.onMove(p.state.choice ? custody : void 0),
|
|
8980
|
+
disabled: !canMove,
|
|
8981
|
+
children: p.busy ? "Moving your wallets..." : "Move my wallets"
|
|
8982
|
+
}
|
|
8983
|
+
),
|
|
8984
|
+
p.blockedReasons && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-recovery-btn pollar-recovery-btn-quiet", onClick: p.onLater, disabled: p.busy, children: "Continue for now" }),
|
|
8985
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-recovery-btn pollar-recovery-btn-quiet", onClick: p.onLogout, disabled: p.busy, children: "Log out" }),
|
|
8986
|
+
p.error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-error", role: "alert", children: p.error })
|
|
8987
|
+
] }),
|
|
8988
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
8989
|
+
] });
|
|
8990
|
+
}
|
|
8991
|
+
function CustodyMigrationModal({ state, onMoved, onLater }) {
|
|
8992
|
+
const { getClient, styles } = usePollar();
|
|
8993
|
+
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
8994
|
+
const [busy, setBusy] = react.useState(false);
|
|
8995
|
+
const [error, setError] = react.useState(null);
|
|
8996
|
+
const [blockedReasons, setBlockedReasons] = react.useState(null);
|
|
8997
|
+
async function move(custody) {
|
|
8998
|
+
setBusy(true);
|
|
8999
|
+
setError(null);
|
|
9000
|
+
setBlockedReasons(null);
|
|
9001
|
+
try {
|
|
9002
|
+
await getClient().cosign.migrateWallets(custody);
|
|
9003
|
+
onMoved();
|
|
9004
|
+
} catch (err) {
|
|
9005
|
+
if (core.isPollarApiError(err) && err.code === "SDK_CUSTODY_MIGRATION_BLOCKED") {
|
|
9006
|
+
const reasons = err.body.reasons;
|
|
9007
|
+
setBlockedReasons(Array.isArray(reasons) ? reasons.map(String) : []);
|
|
9008
|
+
return;
|
|
9009
|
+
}
|
|
9010
|
+
setError(core.transactionErrorMessage(core.isPollarApiError(err) ? err.code : null, err instanceof Error ? err.message : null));
|
|
9011
|
+
} finally {
|
|
9012
|
+
setBusy(false);
|
|
9013
|
+
}
|
|
9014
|
+
}
|
|
9015
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9016
|
+
CustodyMigrationModalTemplate,
|
|
9017
|
+
{
|
|
9018
|
+
theme,
|
|
9019
|
+
accentColor,
|
|
9020
|
+
styleOverrides,
|
|
9021
|
+
state,
|
|
9022
|
+
busy,
|
|
9023
|
+
error,
|
|
9024
|
+
blockedReasons,
|
|
9025
|
+
onMove: (custody) => void move(custody),
|
|
9026
|
+
onLater,
|
|
9027
|
+
onLogout: () => void getClient().logout()
|
|
9028
|
+
}
|
|
9029
|
+
) });
|
|
9030
|
+
}
|
|
9031
|
+
function CloseIcon3() {
|
|
9032
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m3 3 8 8M11 3l-8 8", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
|
|
9033
|
+
}
|
|
9034
|
+
var shortKey = (key) => `${key.slice(0, 6)}...${key.slice(-4)}`;
|
|
9035
|
+
function Button(props) {
|
|
9036
|
+
const running = props.busy === props.id;
|
|
9037
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9038
|
+
"button",
|
|
9039
|
+
{
|
|
9040
|
+
type: "button",
|
|
9041
|
+
className: `pollar-recovery-btn pollar-recovery-btn-${props.kind ?? "quiet"}`,
|
|
9042
|
+
onClick: props.onClick,
|
|
9043
|
+
disabled: props.disabled || props.busy !== null,
|
|
9044
|
+
children: running ? props.busyLabel ?? "Working..." : props.label
|
|
9045
|
+
}
|
|
9046
|
+
);
|
|
9047
|
+
}
|
|
9048
|
+
function CodeForm(props) {
|
|
9049
|
+
const [code, setCode] = react.useState("");
|
|
9050
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9051
|
+
"form",
|
|
9052
|
+
{
|
|
9053
|
+
className: "pollar-recovery-row",
|
|
9054
|
+
onSubmit: (e) => {
|
|
9055
|
+
e.preventDefault();
|
|
9056
|
+
if (code.trim()) props.onSubmit(code);
|
|
9057
|
+
},
|
|
9058
|
+
children: [
|
|
9059
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9060
|
+
"input",
|
|
9061
|
+
{
|
|
9062
|
+
className: "pollar-recovery-input",
|
|
9063
|
+
value: code,
|
|
9064
|
+
onChange: (e) => setCode(e.target.value),
|
|
9065
|
+
placeholder: "Code from the email",
|
|
9066
|
+
autoComplete: "one-time-code",
|
|
9067
|
+
"aria-label": "Code from the email"
|
|
9068
|
+
}
|
|
9069
|
+
),
|
|
9070
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9071
|
+
Button,
|
|
9072
|
+
{
|
|
9073
|
+
busy: props.busy,
|
|
9074
|
+
id: props.id,
|
|
9075
|
+
label: props.label,
|
|
9076
|
+
kind: "primary",
|
|
9077
|
+
onClick: () => code.trim() && props.onSubmit(code)
|
|
9078
|
+
}
|
|
9079
|
+
)
|
|
9080
|
+
]
|
|
9081
|
+
}
|
|
9082
|
+
);
|
|
9083
|
+
}
|
|
9084
|
+
function RecoveryModalTemplate(p) {
|
|
9085
|
+
const cssVars = buildModalCssVars(p.theme, p.accentColor, p.styleOverrides);
|
|
9086
|
+
const [exportAccepted, setExportAccepted] = react.useState(false);
|
|
9087
|
+
const [risksAccepted, setRisksAccepted] = react.useState(false);
|
|
9088
|
+
const state = p.state;
|
|
9089
|
+
const locked = !!state && state.required && !state.configured;
|
|
9090
|
+
const risksPending = locked && p.selfCustodyRisks && !risksAccepted;
|
|
9091
|
+
const lastMethod = !!state && state.passkeys.length + (state.email.verified ? 1 : 0) + (state.devices.length >= 2 ? 1 : 0) <= 1;
|
|
9092
|
+
let body;
|
|
9093
|
+
if (!state) {
|
|
9094
|
+
body = /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "Loading your wallet's recovery methods..." });
|
|
9095
|
+
} else if (!state.required) {
|
|
9096
|
+
body = /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "This wallet doesn't need recovery methods: it isn't secured by your device." });
|
|
9097
|
+
} else if (!p.thisDeviceEnrolled && p.view !== "recover-email") {
|
|
9098
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9099
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "status", children: "This device isn't part of your wallet yet. Get back in with one of your recovery methods, or ask a device that already has the wallet to add this one." }),
|
|
9100
|
+
state.passkeys.length > 0 && p.passkeyAvailable && /* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "recover-passkey", label: "Use a passkey", kind: "primary", onClick: p.onRecoverWithPasskey }),
|
|
9101
|
+
state.email.verified && /* @__PURE__ */ jsxRuntime.jsx(
|
|
9102
|
+
Button,
|
|
9103
|
+
{
|
|
9104
|
+
busy: p.busy,
|
|
9105
|
+
id: "recover-send",
|
|
9106
|
+
label: `Email a code to ${state.email.address ?? "your email"}`,
|
|
9107
|
+
onClick: () => p.onView("recover-email")
|
|
9108
|
+
}
|
|
9109
|
+
),
|
|
9110
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "enroll", label: "Ask another device to add this one", onClick: p.onRequestEnrollment })
|
|
9111
|
+
] });
|
|
9112
|
+
} else if (risksPending && p.view === "overview") {
|
|
9113
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9114
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "alert", children: "This is a self-custody wallet: only your device can sign. If you lose this device and every recovery method, nobody can recover the wallet or its funds, not the app and not Pollar. Nobody can undo or freeze a transaction you sign." }),
|
|
9115
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9116
|
+
Button,
|
|
9117
|
+
{
|
|
9118
|
+
busy: p.busy,
|
|
9119
|
+
id: "accept-risks",
|
|
9120
|
+
label: "I understand and accept these risks",
|
|
9121
|
+
kind: "primary",
|
|
9122
|
+
onClick: () => setRisksAccepted(true)
|
|
9123
|
+
}
|
|
9124
|
+
)
|
|
9125
|
+
] });
|
|
9126
|
+
} else if (p.view === "recover-email") {
|
|
9127
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9128
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "pollar-recovery-muted", children: [
|
|
9129
|
+
"We'll email a code to ",
|
|
9130
|
+
state.email.address,
|
|
9131
|
+
". The code goes straight to the wallet provider, encrypted on this device."
|
|
9132
|
+
] }),
|
|
9133
|
+
!p.codeSent ? /* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "recover-send", label: "Send code", kind: "primary", onClick: p.onSendRecoveryCode }) : /* @__PURE__ */ jsxRuntime.jsx(CodeForm, { busy: p.busy, id: "recover-code", label: "Recover", onSubmit: p.onRecoverWithCode }),
|
|
9134
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "back", label: "Back", onClick: () => p.onView("overview") })
|
|
9135
|
+
] });
|
|
9136
|
+
} else if (p.view === "email") {
|
|
9137
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9138
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "Confirm an email you control. If you lose this device, a code sent there lets you add a new one. Anyone who controls this inbox could do the same, so use one that is well protected." }),
|
|
9139
|
+
!p.codeSent ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9140
|
+
"form",
|
|
9141
|
+
{
|
|
9142
|
+
className: "pollar-recovery-row",
|
|
9143
|
+
onSubmit: (e) => {
|
|
9144
|
+
e.preventDefault();
|
|
9145
|
+
p.onSendEmailCode();
|
|
9146
|
+
},
|
|
9147
|
+
children: [
|
|
9148
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9149
|
+
"input",
|
|
9150
|
+
{
|
|
9151
|
+
className: "pollar-recovery-input",
|
|
9152
|
+
type: "email",
|
|
9153
|
+
value: p.emailDraft,
|
|
9154
|
+
onChange: (e) => p.onEmailDraft(e.target.value),
|
|
9155
|
+
placeholder: "you@example.com",
|
|
9156
|
+
"aria-label": "Email"
|
|
9157
|
+
}
|
|
9158
|
+
),
|
|
9159
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9160
|
+
Button,
|
|
9161
|
+
{
|
|
9162
|
+
busy: p.busy,
|
|
9163
|
+
id: "email-send",
|
|
9164
|
+
label: "Send code",
|
|
9165
|
+
kind: "primary",
|
|
9166
|
+
onClick: p.onSendEmailCode,
|
|
9167
|
+
disabled: !p.emailDraft.trim()
|
|
9168
|
+
}
|
|
9169
|
+
)
|
|
9170
|
+
]
|
|
9171
|
+
}
|
|
9172
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(CodeForm, { busy: p.busy, id: "email-confirm", label: "Confirm", onSubmit: p.onConfirmEmail }),
|
|
9173
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "back", label: "Back", onClick: () => p.onView("overview") })
|
|
9174
|
+
] });
|
|
9175
|
+
} else if (p.view === "export") {
|
|
9176
|
+
body = p.phrase ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9177
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "alert", children: "Anyone with these words controls every account in this wallet. Write them down offline and never share them." }),
|
|
9178
|
+
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "pollar-recovery-phrase", children: p.phrase }),
|
|
9179
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "hide", label: "Hide", kind: "primary", onClick: () => p.onView("overview") })
|
|
9180
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9181
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "Your recovery phrase lets you take this wallet to another app. It is decrypted only on this device; the app and Pollar never see it." }),
|
|
9182
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-recovery-check", children: [
|
|
9183
|
+
/* @__PURE__ */ jsxRuntime.jsx("input", { type: "checkbox", checked: exportAccepted, onChange: (e) => setExportAccepted(e.target.checked) }),
|
|
9184
|
+
" I understand that whoever sees the phrase controls the wallet"
|
|
9185
|
+
] }),
|
|
9186
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9187
|
+
Button,
|
|
9188
|
+
{
|
|
9189
|
+
busy: p.busy,
|
|
9190
|
+
id: "export",
|
|
9191
|
+
label: "Show recovery phrase",
|
|
9192
|
+
kind: "danger",
|
|
9193
|
+
onClick: p.onExport,
|
|
9194
|
+
disabled: !exportAccepted
|
|
9195
|
+
}
|
|
9196
|
+
),
|
|
9197
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "back", label: "Back", onClick: () => p.onView("overview") })
|
|
9198
|
+
] });
|
|
9199
|
+
} else {
|
|
9200
|
+
const enrollments = p.devices?.enrollments ?? [];
|
|
9201
|
+
body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9202
|
+
locked ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-recovery-banner pollar-recovery-banner-warn", role: "alert", children: "Your wallet is locked until you add a way to recover it. Without one, losing this device means losing the funds, and nobody can get them back, not the app and not Pollar. Add a passkey, a second device or your email." }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-recovery-banner pollar-recovery-banner-ok", role: "status", children: "Your wallet can be recovered if you lose this device." }),
|
|
9203
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-recovery-section", children: [
|
|
9204
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Passkeys" }),
|
|
9205
|
+
state.passkeys.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "No passkey yet." }),
|
|
9206
|
+
state.passkeys.map((pk) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-item", children: [
|
|
9207
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: pk.name }),
|
|
9208
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9209
|
+
Button,
|
|
9210
|
+
{
|
|
9211
|
+
busy: p.busy,
|
|
9212
|
+
id: `passkey:${pk.authenticatorId}`,
|
|
9213
|
+
label: "Remove",
|
|
9214
|
+
kind: "danger",
|
|
9215
|
+
onClick: () => p.onRemovePasskey(pk.authenticatorId),
|
|
9216
|
+
disabled: lastMethod
|
|
9217
|
+
}
|
|
9218
|
+
)
|
|
9219
|
+
] }, pk.authenticatorId)),
|
|
9220
|
+
p.passkeyAvailable ? /* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "passkey", label: "Add a passkey", onClick: p.onAddPasskey }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: "Passkeys aren't available on this device." })
|
|
9221
|
+
] }),
|
|
9222
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-recovery-section", children: [
|
|
9223
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Email" }),
|
|
9224
|
+
state.email.verified ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-item", children: [
|
|
9225
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: state.email.address }),
|
|
9226
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-recovery-tag", children: "Confirmed" })
|
|
9227
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "email", label: "Confirm an email", onClick: () => p.onView("email") })
|
|
9228
|
+
] }),
|
|
9229
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-recovery-section", children: [
|
|
9230
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Devices" }),
|
|
9231
|
+
(p.devices?.devices ?? []).map((d) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-item", children: [
|
|
9232
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: d.label ?? shortKey(d.publicKey) }),
|
|
9233
|
+
d.publicKey.toLowerCase() === p.thisDeviceKey && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-recovery-tag", children: "This device" })
|
|
9234
|
+
] }, d.id)),
|
|
9235
|
+
enrollments.map((e) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-item pollar-recovery-item-pending", children: [
|
|
9236
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
9237
|
+
e.label ?? "A device",
|
|
9238
|
+
" wants to join (",
|
|
9239
|
+
shortKey(e.publicKey),
|
|
9240
|
+
")"
|
|
9241
|
+
] }),
|
|
9242
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-recovery-actions", children: [
|
|
9243
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9244
|
+
Button,
|
|
9245
|
+
{
|
|
9246
|
+
busy: p.busy,
|
|
9247
|
+
id: `approve:${e.id}`,
|
|
9248
|
+
label: "Approve",
|
|
9249
|
+
kind: "primary",
|
|
9250
|
+
onClick: () => p.onApproveDevice(e.id)
|
|
9251
|
+
}
|
|
9252
|
+
),
|
|
9253
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: `reject:${e.id}`, label: "Reject", onClick: () => p.onRejectDevice(e.id) })
|
|
9254
|
+
] })
|
|
9255
|
+
] }, e.id)),
|
|
9256
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-muted", children: 'To add another device, sign in there and choose "Ask another device to add this one"; it shows up here to approve. Only approve a device you are holding.' })
|
|
9257
|
+
] }),
|
|
9258
|
+
/* @__PURE__ */ jsxRuntime.jsxs("section", { className: "pollar-recovery-section", children: [
|
|
9259
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { children: "Recovery phrase" }),
|
|
9260
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { busy: p.busy, id: "export", label: "Export recovery phrase", onClick: () => p.onView("export") })
|
|
9261
|
+
] })
|
|
9262
|
+
] });
|
|
9263
|
+
}
|
|
9264
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9265
|
+
"div",
|
|
9266
|
+
{
|
|
9267
|
+
className: "pollar-modal-card pollar-recovery-modal",
|
|
9268
|
+
"data-theme": p.theme,
|
|
9269
|
+
style: cssVars,
|
|
9270
|
+
onClick: (e) => e.stopPropagation(),
|
|
9271
|
+
children: [
|
|
9272
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
9273
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Wallet recovery" }),
|
|
9274
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: p.onClose, "aria-label": "Close", title: "Close", children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon3, {}) }) })
|
|
9275
|
+
] }),
|
|
9276
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-recovery-body", children: [
|
|
9277
|
+
body,
|
|
9278
|
+
p.notice && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-notice", role: "status", children: p.notice }),
|
|
9279
|
+
p.error && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-recovery-error", role: "alert", children: p.error })
|
|
9280
|
+
] }),
|
|
9281
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
9282
|
+
]
|
|
9283
|
+
}
|
|
9284
|
+
);
|
|
9285
|
+
}
|
|
9286
|
+
function errorText2(err) {
|
|
9287
|
+
return core.transactionErrorMessage(core.isPollarApiError(err) ? err.code : null, err instanceof Error ? err.message : null);
|
|
9288
|
+
}
|
|
9289
|
+
function RecoveryModal({ onClose }) {
|
|
9290
|
+
const { getClient, styles, refreshRecovery, appConfig } = usePollar();
|
|
9291
|
+
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
9292
|
+
const recovery = getClient().cosign.recovery;
|
|
9293
|
+
const [state, setState] = react.useState(null);
|
|
9294
|
+
const [devices, setDevices] = react.useState(null);
|
|
9295
|
+
const [thisDeviceKey, setThisDeviceKey] = react.useState(null);
|
|
9296
|
+
const [view, setView] = react.useState("overview");
|
|
9297
|
+
const [busy, setBusy] = react.useState(null);
|
|
9298
|
+
const [error, setError] = react.useState(null);
|
|
9299
|
+
const [notice, setNotice] = react.useState(null);
|
|
9300
|
+
const [emailDraft, setEmailDraft] = react.useState("");
|
|
9301
|
+
const [codeSent, setCodeSent] = react.useState(false);
|
|
9302
|
+
const [phrase, setPhrase] = react.useState(null);
|
|
9303
|
+
const load = react.useCallback(async () => {
|
|
9304
|
+
const client = getClient();
|
|
9305
|
+
const [nextState, nextDevices, key] = await Promise.all([
|
|
9306
|
+
client.cosign.recovery.status(),
|
|
9307
|
+
client.cosign.devices(),
|
|
9308
|
+
client.cosign.publicKeyHex()
|
|
9309
|
+
]);
|
|
9310
|
+
setState(nextState);
|
|
9311
|
+
setDevices(nextDevices);
|
|
9312
|
+
setThisDeviceKey(key.toLowerCase());
|
|
9313
|
+
if (nextState.email.address) setEmailDraft((d) => d || nextState.email.address);
|
|
9314
|
+
refreshRecovery();
|
|
9315
|
+
}, [getClient, refreshRecovery]);
|
|
9316
|
+
react.useEffect(() => {
|
|
9317
|
+
load().catch((err) => setError(errorText2(err)));
|
|
9318
|
+
}, [load]);
|
|
9319
|
+
const onCloseRef = react.useRef(onClose);
|
|
9320
|
+
onCloseRef.current = onClose;
|
|
9321
|
+
react.useEffect(
|
|
9322
|
+
() => getClient().onAuthStateChange((authState) => {
|
|
9323
|
+
if (authState.step === "idle") onCloseRef.current();
|
|
9324
|
+
}),
|
|
9325
|
+
[getClient]
|
|
9326
|
+
);
|
|
9327
|
+
const run = react.useCallback(
|
|
9328
|
+
async (key, action, after) => {
|
|
9329
|
+
setBusy(key);
|
|
9330
|
+
setError(null);
|
|
9331
|
+
setNotice(null);
|
|
9332
|
+
try {
|
|
9333
|
+
await action();
|
|
9334
|
+
await load();
|
|
9335
|
+
if (after?.notice) setNotice(after.notice);
|
|
9336
|
+
if (after?.view) setView(after.view);
|
|
9337
|
+
} catch (err) {
|
|
9338
|
+
setError(errorText2(err));
|
|
9339
|
+
} finally {
|
|
9340
|
+
setBusy(null);
|
|
9341
|
+
}
|
|
9342
|
+
},
|
|
9343
|
+
[load]
|
|
9344
|
+
);
|
|
9345
|
+
const enrolled = !!thisDeviceKey && !!devices?.devices.some((d) => d.publicKey.toLowerCase() === thisDeviceKey);
|
|
9346
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9347
|
+
RecoveryModalTemplate,
|
|
9348
|
+
{
|
|
9349
|
+
theme,
|
|
9350
|
+
accentColor,
|
|
9351
|
+
styleOverrides,
|
|
9352
|
+
state,
|
|
9353
|
+
devices,
|
|
9354
|
+
thisDeviceKey,
|
|
9355
|
+
thisDeviceEnrolled: enrolled,
|
|
9356
|
+
passkeyAvailable: recovery.passkeyAvailable,
|
|
9357
|
+
selfCustodyRisks: appConfig.application?.walletCustodyMode === "SELF_CUSTODY" && devices?.custody === "SELF_CUSTODY",
|
|
9358
|
+
view,
|
|
9359
|
+
busy,
|
|
9360
|
+
error,
|
|
9361
|
+
notice,
|
|
9362
|
+
emailDraft,
|
|
9363
|
+
codeSent,
|
|
9364
|
+
phrase,
|
|
9365
|
+
onView: (next) => {
|
|
9366
|
+
setError(null);
|
|
9367
|
+
setNotice(null);
|
|
9368
|
+
setCodeSent(false);
|
|
9369
|
+
if (next !== "export") setPhrase(null);
|
|
9370
|
+
setView(next);
|
|
9371
|
+
},
|
|
9372
|
+
onEmailDraft: setEmailDraft,
|
|
9373
|
+
onAddPasskey: () => void run("passkey", () => recovery.addPasskey(), { notice: "Passkey added." }),
|
|
9374
|
+
onRemovePasskey: (id) => void run(`passkey:${id}`, () => recovery.removePasskey(id)),
|
|
9375
|
+
onSendEmailCode: () => void run("email-send", async () => {
|
|
9376
|
+
await recovery.startEmail(emailDraft.trim());
|
|
9377
|
+
setCodeSent(true);
|
|
9378
|
+
}),
|
|
9379
|
+
onConfirmEmail: (code) => void run("email-confirm", () => recovery.confirmEmail(code.trim()), { notice: "Email confirmed.", view: "overview" }),
|
|
9380
|
+
onApproveDevice: (id) => void run(`approve:${id}`, () => recovery.approveDevice(id), { notice: "Device added." }),
|
|
9381
|
+
onRejectDevice: (id) => void run(`reject:${id}`, () => recovery.rejectDevice(id)),
|
|
9382
|
+
onRequestEnrollment: () => void run("enroll", () => recovery.requestDeviceEnrollment(), {
|
|
9383
|
+
notice: "Request sent. Approve it from a device that already has this wallet within 15 minutes."
|
|
9384
|
+
}),
|
|
9385
|
+
onRecoverWithPasskey: () => void run("recover-passkey", () => recovery.recoverWithPasskey(), {
|
|
9386
|
+
notice: "This device is part of your wallet again."
|
|
9387
|
+
}),
|
|
9388
|
+
onSendRecoveryCode: () => void run("recover-send", async () => {
|
|
9389
|
+
await recovery.startEmailRecovery();
|
|
9390
|
+
setCodeSent(true);
|
|
9391
|
+
}),
|
|
9392
|
+
onRecoverWithCode: (code) => void run("recover-code", () => recovery.recoverWithEmailCode(code.trim()), {
|
|
9393
|
+
notice: "This device is part of your wallet again.",
|
|
9394
|
+
view: "overview"
|
|
9395
|
+
}),
|
|
9396
|
+
onExport: () => void run("export", async () => {
|
|
9397
|
+
setPhrase(await recovery.exportWallet());
|
|
9398
|
+
}),
|
|
9399
|
+
onClose
|
|
9400
|
+
}
|
|
9401
|
+
) });
|
|
9402
|
+
}
|
|
9403
|
+
var OPERATION_LABELS2 = {
|
|
9404
|
+
payment: "Send",
|
|
9405
|
+
path_payment_strict_send: "Swap",
|
|
9406
|
+
change_trust: "Add asset",
|
|
9407
|
+
create_account: "Create account",
|
|
9408
|
+
invoke_contract: "Contract call",
|
|
9409
|
+
manage_data: "Manage data"
|
|
9410
|
+
};
|
|
9411
|
+
function labelOf2(confirmation) {
|
|
9412
|
+
const op = confirmation.operation ?? "";
|
|
9413
|
+
return OPERATION_LABELS2[op] ?? (op ? op.replace(/_/g, " ") : "Transaction");
|
|
9414
|
+
}
|
|
9415
|
+
function detailRows2(confirmation) {
|
|
9416
|
+
const details = confirmation.details ?? {};
|
|
9417
|
+
const rows = [];
|
|
9418
|
+
const push = (label, value) => {
|
|
9419
|
+
if (value === void 0 || value === null || value === "") return;
|
|
9420
|
+
const text = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
9421
|
+
rows.push([label, /^[GC][A-Z2-7]{55}$/.test(text) ? cropAddress(text) : text]);
|
|
9422
|
+
};
|
|
9423
|
+
push("Destination", details.destination);
|
|
9424
|
+
push("Amount", details.amount);
|
|
9425
|
+
push("Asset", details.asset ?? details.assetCode ?? details.mint);
|
|
9426
|
+
push("Network", confirmation.network);
|
|
9427
|
+
return rows;
|
|
9428
|
+
}
|
|
9429
|
+
function CloseIcon4() {
|
|
9430
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m3 3 8 8M11 3l-8 8", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
|
|
9431
|
+
}
|
|
9432
|
+
function ConfirmModal({ confirmation }) {
|
|
9433
|
+
const { getClient, styles } = usePollar();
|
|
9434
|
+
const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
|
|
9435
|
+
const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
|
|
9436
|
+
const rejectRef = react.useRef(confirmation.reject);
|
|
9437
|
+
rejectRef.current = confirmation.reject;
|
|
9438
|
+
react.useEffect(() => {
|
|
9439
|
+
return getClient().onAuthStateChange((authState) => {
|
|
9440
|
+
if (authState.step === "idle") rejectRef.current();
|
|
9441
|
+
});
|
|
9442
|
+
}, [getClient]);
|
|
9443
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: confirmation.reject, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
9444
|
+
"div",
|
|
9445
|
+
{
|
|
9446
|
+
className: "pollar-modal-card pollar-cosign-modal",
|
|
9447
|
+
"data-theme": theme,
|
|
9448
|
+
style: cssVars,
|
|
9449
|
+
onClick: (e) => e.stopPropagation(),
|
|
9450
|
+
children: [
|
|
9451
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
|
|
9452
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Confirm transaction" }),
|
|
9453
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: confirmation.reject, "aria-label": "Close", title: "Close", children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon4, {}) }) })
|
|
9454
|
+
] }),
|
|
9455
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-detail", children: [
|
|
9456
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-detail-title", children: labelOf2(confirmation) }),
|
|
9457
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: "The app asks you to sign this transaction with your wallet." }),
|
|
9458
|
+
/* @__PURE__ */ jsxRuntime.jsx("dl", { className: "pollar-cosign-rows", children: detailRows2(confirmation).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-row", children: [
|
|
9459
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: k }),
|
|
9460
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: v })
|
|
9461
|
+
] }, k)) }),
|
|
9462
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-actions", children: [
|
|
9463
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-cosign-btn pollar-cosign-btn-secondary", onClick: confirmation.reject, children: "Cancel" }),
|
|
9464
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-cosign-btn pollar-cosign-btn-primary", onClick: confirmation.confirm, children: "Confirm" })
|
|
9465
|
+
] })
|
|
9466
|
+
] }),
|
|
9467
|
+
/* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
|
|
9468
|
+
]
|
|
9469
|
+
}
|
|
9470
|
+
) });
|
|
9471
|
+
}
|
|
7982
9472
|
function TransactionModalTemplate({
|
|
7983
9473
|
theme,
|
|
7984
9474
|
accentColor,
|
|
@@ -8088,12 +9578,6 @@ function TransactionModal({ onClose }) {
|
|
|
8088
9578
|
) });
|
|
8089
9579
|
}
|
|
8090
9580
|
var PAGE_SIZE = 10;
|
|
8091
|
-
function explorerUrlFor(chain, hash, network) {
|
|
8092
|
-
if (chain === "SOLANA") {
|
|
8093
|
-
return `https://explorer.solana.com/tx/${hash}${network === "testnet" ? "?cluster=devnet" : ""}`;
|
|
8094
|
-
}
|
|
8095
|
-
return `https://stellar.expert/explorer/${network === "testnet" ? "testnet" : "public"}/tx/${hash}`;
|
|
8096
|
-
}
|
|
8097
9581
|
function StatusBadge({ status }) {
|
|
8098
9582
|
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-hist-item-badge", "data-status": status, children: status });
|
|
8099
9583
|
}
|
|
@@ -8103,6 +9587,25 @@ function formatDate(iso) {
|
|
|
8103
9587
|
function truncateMiddle(value, head = 4, tail = 4) {
|
|
8104
9588
|
return value.length <= head + tail + 1 ? value : `${value.slice(0, head)}\u2026${value.slice(-tail)}`;
|
|
8105
9589
|
}
|
|
9590
|
+
function formatFee(fee) {
|
|
9591
|
+
if (fee.unit === "lamports") {
|
|
9592
|
+
try {
|
|
9593
|
+
return `${core.fromBaseUnits(fee.amount, 9)} SOL`;
|
|
9594
|
+
} catch {
|
|
9595
|
+
}
|
|
9596
|
+
}
|
|
9597
|
+
return `${fee.amount} ${fee.unit}`;
|
|
9598
|
+
}
|
|
9599
|
+
function formatAmount4(details) {
|
|
9600
|
+
const { amount, decimals, symbol } = details ?? {};
|
|
9601
|
+
if (typeof amount !== "string" || typeof decimals !== "number") return null;
|
|
9602
|
+
try {
|
|
9603
|
+
const value = core.fromBaseUnits(amount, decimals);
|
|
9604
|
+
return typeof symbol === "string" ? `${value} ${symbol}` : value;
|
|
9605
|
+
} catch {
|
|
9606
|
+
return null;
|
|
9607
|
+
}
|
|
9608
|
+
}
|
|
8106
9609
|
var STELLAR_ADDRESS = /\b[GC][A-Z2-7]{55}\b/g;
|
|
8107
9610
|
function AddressChip({ value, label }) {
|
|
8108
9611
|
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-hist-item-issuer", children: [
|
|
@@ -8210,7 +9713,7 @@ function TxHistoryModalTemplate({
|
|
|
8210
9713
|
txHistory.step === "loaded" && records.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No transactions yet." }),
|
|
8211
9714
|
records.map((record) => {
|
|
8212
9715
|
const hash = typeof record.hash === "string" && record.hash.length > 0 ? record.hash : void 0;
|
|
8213
|
-
const explorerUrl = hash ?
|
|
9716
|
+
const explorerUrl = hash ? explorerTxUrl(record.chain, hash, record.network) : void 0;
|
|
8214
9717
|
const asset = typeof record.details?.asset === "string" ? record.details.asset : void 0;
|
|
8215
9718
|
const colon = asset ? asset.indexOf(":") : -1;
|
|
8216
9719
|
const trustline = record.operation === "change_trust" && asset && colon > 0 ? {
|
|
@@ -8240,15 +9743,17 @@ function TxHistoryModalTemplate({
|
|
|
8240
9743
|
] }),
|
|
8241
9744
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-hist-item-meta", children: [
|
|
8242
9745
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: record.operation }),
|
|
9746
|
+
record.chain !== "STELLAR" && formatAmount4(record.details) && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
9747
|
+
"\xB7 ",
|
|
9748
|
+
formatAmount4(record.details)
|
|
9749
|
+
] }),
|
|
8243
9750
|
typeof record.details?.sponsored === "boolean" && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
8244
9751
|
"\xB7 ",
|
|
8245
9752
|
record.details.sponsored ? "Sponsored" : "Self-paid"
|
|
8246
9753
|
] }),
|
|
8247
9754
|
record.fee && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
8248
9755
|
"\xB7 ",
|
|
8249
|
-
record.fee
|
|
8250
|
-
" ",
|
|
8251
|
-
record.fee.unit
|
|
9756
|
+
formatFee(record.fee)
|
|
8252
9757
|
] })
|
|
8253
9758
|
] }),
|
|
8254
9759
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-hist-item-footer", children: [
|
|
@@ -8559,6 +10064,48 @@ var browserPasskeySigner = async ({ credentialId, challenge }) => {
|
|
|
8559
10064
|
signature: response.signature
|
|
8560
10065
|
};
|
|
8561
10066
|
};
|
|
10067
|
+
var browserRecoveryPasskey = {
|
|
10068
|
+
async create({ challenge, userName }) {
|
|
10069
|
+
const rpId = window.location.hostname;
|
|
10070
|
+
const response = await browser.startRegistration({
|
|
10071
|
+
optionsJSON: {
|
|
10072
|
+
challenge,
|
|
10073
|
+
rp: { id: rpId, name: rpId },
|
|
10074
|
+
user: { id: randomUserId(), name: userName, displayName: userName },
|
|
10075
|
+
pubKeyCredParams: [
|
|
10076
|
+
{ type: "public-key", alg: -7 },
|
|
10077
|
+
{ type: "public-key", alg: -257 }
|
|
10078
|
+
],
|
|
10079
|
+
authenticatorSelection: { residentKey: "preferred", userVerification: "preferred" },
|
|
10080
|
+
attestation: "none",
|
|
10081
|
+
timeout: 6e4
|
|
10082
|
+
}
|
|
10083
|
+
});
|
|
10084
|
+
return {
|
|
10085
|
+
credentialId: response.id,
|
|
10086
|
+
clientDataJson: response.response.clientDataJSON,
|
|
10087
|
+
attestationObject: response.response.attestationObject,
|
|
10088
|
+
transports: response.response.transports ?? []
|
|
10089
|
+
};
|
|
10090
|
+
},
|
|
10091
|
+
async get({ challenge, allowCredentials }) {
|
|
10092
|
+
const rpId = window.location.hostname;
|
|
10093
|
+
const response = await browser.startAuthentication({
|
|
10094
|
+
optionsJSON: {
|
|
10095
|
+
challenge,
|
|
10096
|
+
rpId,
|
|
10097
|
+
allowCredentials: allowCredentials.map((id) => ({ id, type: "public-key" })),
|
|
10098
|
+
userVerification: "preferred"
|
|
10099
|
+
}
|
|
10100
|
+
});
|
|
10101
|
+
return {
|
|
10102
|
+
credentialId: response.id,
|
|
10103
|
+
authenticatorData: response.response.authenticatorData,
|
|
10104
|
+
clientDataJson: response.response.clientDataJSON,
|
|
10105
|
+
signature: response.response.signature
|
|
10106
|
+
};
|
|
10107
|
+
}
|
|
10108
|
+
};
|
|
8562
10109
|
var DEFAULT_APP_CONFIG = {
|
|
8563
10110
|
application: { name: "", network: "testnet", chains: [] },
|
|
8564
10111
|
styles: {}
|
|
@@ -8583,7 +10130,11 @@ function PollarProvider({
|
|
|
8583
10130
|
}) {
|
|
8584
10131
|
const [pollarClient] = react.useState(() => {
|
|
8585
10132
|
if (core.isPollarClient(client)) {
|
|
8586
|
-
client.setPasskeyDefaults({
|
|
10133
|
+
client.setPasskeyDefaults({
|
|
10134
|
+
passkey: browserPasskeyCeremony,
|
|
10135
|
+
passkeySign: browserPasskeySigner,
|
|
10136
|
+
recoveryPasskey: browserRecoveryPasskey
|
|
10137
|
+
});
|
|
8587
10138
|
return client;
|
|
8588
10139
|
}
|
|
8589
10140
|
const alreadyBuilt = clientByConfig.get(client);
|
|
@@ -8591,7 +10142,8 @@ function PollarProvider({
|
|
|
8591
10142
|
const built = new core.PollarClient({
|
|
8592
10143
|
...client,
|
|
8593
10144
|
passkey: client.passkey ?? browserPasskeyCeremony,
|
|
8594
|
-
passkeySign: client.passkeySign ?? browserPasskeySigner
|
|
10145
|
+
passkeySign: client.passkeySign ?? browserPasskeySigner,
|
|
10146
|
+
recoveryPasskey: client.recoveryPasskey ?? browserRecoveryPasskey
|
|
8595
10147
|
});
|
|
8596
10148
|
clientByConfig.set(client, built);
|
|
8597
10149
|
return built;
|
|
@@ -8619,6 +10171,9 @@ function PollarProvider({
|
|
|
8619
10171
|
const [transaction, setTransaction] = react.useState({ step: "idle" });
|
|
8620
10172
|
const [txHistory, setTxHistory] = react.useState({ step: "idle" });
|
|
8621
10173
|
const [sessions, setSessions] = react.useState({ step: "idle" });
|
|
10174
|
+
const [cosign, setCosign] = react.useState({ pending: [] });
|
|
10175
|
+
const [confirmations, setConfirmations] = react.useState([]);
|
|
10176
|
+
const firstConfirmation = confirmations[0] ?? null;
|
|
8622
10177
|
const [walletBalance, setWalletBalance] = react.useState({ step: "idle" });
|
|
8623
10178
|
const [enabledAssets, setEnabledAssets] = react.useState({ step: "idle" });
|
|
8624
10179
|
const [resolvedConfig, setResolvedConfig] = react.useState(() => appConfigProp ?? DEFAULT_APP_CONFIG);
|
|
@@ -8636,6 +10191,12 @@ function PollarProvider({
|
|
|
8636
10191
|
react.useEffect(() => {
|
|
8637
10192
|
return pollarClient.onTxHistoryStateChange(setTxHistory);
|
|
8638
10193
|
}, [pollarClient]);
|
|
10194
|
+
react.useEffect(() => {
|
|
10195
|
+
return pollarClient.onCosignStateChange(setCosign);
|
|
10196
|
+
}, [pollarClient]);
|
|
10197
|
+
react.useEffect(() => {
|
|
10198
|
+
return pollarClient.onConfirmationRequest(setConfirmations);
|
|
10199
|
+
}, [pollarClient]);
|
|
8639
10200
|
react.useEffect(() => {
|
|
8640
10201
|
return pollarClient.onSessionsStateChange(setSessions);
|
|
8641
10202
|
}, [pollarClient]);
|
|
@@ -8736,6 +10297,13 @@ function PollarProvider({
|
|
|
8736
10297
|
const [cardModalKey, setCardModalKey] = react.useState(0);
|
|
8737
10298
|
const [receiveModalOpen, setReceiveModalOpen] = react.useState(false);
|
|
8738
10299
|
const [sessionsModalOpen, setSessionsModalOpen] = react.useState(false);
|
|
10300
|
+
const [cosignModalOpen, setCosignModalOpen] = react.useState(false);
|
|
10301
|
+
const [recoveryModalOpen, setRecoveryModalOpen] = react.useState(false);
|
|
10302
|
+
const cosignPendingCount = react.useRef(0);
|
|
10303
|
+
react.useEffect(() => {
|
|
10304
|
+
if (cosign.pending.length > cosignPendingCount.current) setCosignModalOpen(true);
|
|
10305
|
+
cosignPendingCount.current = cosign.pending.length;
|
|
10306
|
+
}, [cosign.pending.length]);
|
|
8739
10307
|
const [distributionRulesModalOpen, setDistributionRulesModalOpen] = react.useState(false);
|
|
8740
10308
|
react.useEffect(
|
|
8741
10309
|
() => pollarClient.onAuthStateChange((authState) => {
|
|
@@ -8752,6 +10320,8 @@ function PollarProvider({
|
|
|
8752
10320
|
setCardModalOpen(false);
|
|
8753
10321
|
setReceiveModalOpen(false);
|
|
8754
10322
|
setSessionsModalOpen(false);
|
|
10323
|
+
setCosignModalOpen(false);
|
|
10324
|
+
setRecoveryModalOpen(false);
|
|
8755
10325
|
setDistributionRulesModalOpen(false);
|
|
8756
10326
|
}),
|
|
8757
10327
|
[pollarClient]
|
|
@@ -8760,6 +10330,45 @@ function PollarProvider({
|
|
|
8760
10330
|
const walletProvisioning = sessionState?.wallet?.provisioning;
|
|
8761
10331
|
const hasSession = sessionState !== null;
|
|
8762
10332
|
const getClient = react.useCallback(() => pollarClient, [pollarClient]);
|
|
10333
|
+
const [recovery, setRecovery] = react.useState(null);
|
|
10334
|
+
const [recoveryTick, setRecoveryTick] = react.useState(0);
|
|
10335
|
+
const refreshRecovery = react.useCallback(() => setRecoveryTick((t) => t + 1), []);
|
|
10336
|
+
react.useEffect(() => {
|
|
10337
|
+
if (!hasSession) {
|
|
10338
|
+
setRecovery(null);
|
|
10339
|
+
return;
|
|
10340
|
+
}
|
|
10341
|
+
let cancelled = false;
|
|
10342
|
+
pollarClient.cosign.recovery.status().then((next) => {
|
|
10343
|
+
if (!cancelled) setRecovery(next);
|
|
10344
|
+
}).catch(() => {
|
|
10345
|
+
if (!cancelled) setRecovery(null);
|
|
10346
|
+
});
|
|
10347
|
+
return () => {
|
|
10348
|
+
cancelled = true;
|
|
10349
|
+
};
|
|
10350
|
+
}, [pollarClient, hasSession, walletAddress, recoveryTick]);
|
|
10351
|
+
const recoveryLocked = !!recovery && recovery.required && !recovery.configured;
|
|
10352
|
+
const [custodyMigration, setCustodyMigration] = react.useState(null);
|
|
10353
|
+
const [custodyMigrationTick, setCustodyMigrationTick] = react.useState(0);
|
|
10354
|
+
const refreshCustodyMigration = react.useCallback(() => setCustodyMigrationTick((t) => t + 1), []);
|
|
10355
|
+
const [custodyMigrationLater, setCustodyMigrationLater] = react.useState(false);
|
|
10356
|
+
react.useEffect(() => {
|
|
10357
|
+
if (!hasSession) {
|
|
10358
|
+
setCustodyMigration(null);
|
|
10359
|
+
setCustodyMigrationLater(false);
|
|
10360
|
+
return;
|
|
10361
|
+
}
|
|
10362
|
+
let cancelled = false;
|
|
10363
|
+
pollarClient.cosign.custodyMigration().then((next) => {
|
|
10364
|
+
if (!cancelled) setCustodyMigration(next);
|
|
10365
|
+
}).catch(() => {
|
|
10366
|
+
if (!cancelled) setCustodyMigration(null);
|
|
10367
|
+
});
|
|
10368
|
+
return () => {
|
|
10369
|
+
cancelled = true;
|
|
10370
|
+
};
|
|
10371
|
+
}, [pollarClient, hasSession, walletAddress, custodyMigrationTick]);
|
|
8763
10372
|
const refreshWalletBalance = react.useCallback(() => pollarClient.refreshBalance(), [pollarClient, walletAddress]);
|
|
8764
10373
|
const refreshAssets = react.useCallback(() => pollarClient.refreshAssets(), [pollarClient, walletAddress]);
|
|
8765
10374
|
const contextValue = react.useMemo(() => {
|
|
@@ -8770,7 +10379,7 @@ function PollarProvider({
|
|
|
8770
10379
|
wallets: pollarClient.getWallets(),
|
|
8771
10380
|
isAuthenticated: hasSession,
|
|
8772
10381
|
hasWallet: pollarClient.hasWallet(),
|
|
8773
|
-
createWallet: () => pollarClient.createWallet(),
|
|
10382
|
+
createWallet: (options) => pollarClient.createWallet(options),
|
|
8774
10383
|
verified,
|
|
8775
10384
|
// client
|
|
8776
10385
|
getClient,
|
|
@@ -8836,6 +10445,16 @@ function PollarProvider({
|
|
|
8836
10445
|
// sessions
|
|
8837
10446
|
sessions,
|
|
8838
10447
|
openSessionsModal: () => setSessionsModalOpen(true),
|
|
10448
|
+
// cosign
|
|
10449
|
+
cosign,
|
|
10450
|
+
openCosignModal: () => setCosignModalOpen(true),
|
|
10451
|
+
recovery,
|
|
10452
|
+
recoveryLocked,
|
|
10453
|
+
refreshRecovery,
|
|
10454
|
+
openRecoveryModal: () => setRecoveryModalOpen(true),
|
|
10455
|
+
custodyMigration,
|
|
10456
|
+
refreshCustodyMigration,
|
|
10457
|
+
confirmations,
|
|
8839
10458
|
// distribution
|
|
8840
10459
|
openDistributionRulesModal: () => setDistributionRulesModalOpen(true),
|
|
8841
10460
|
// network
|
|
@@ -8858,6 +10477,11 @@ function PollarProvider({
|
|
|
8858
10477
|
}, [
|
|
8859
10478
|
walletAddress,
|
|
8860
10479
|
walletProvisioning,
|
|
10480
|
+
recovery,
|
|
10481
|
+
recoveryLocked,
|
|
10482
|
+
refreshRecovery,
|
|
10483
|
+
custodyMigration,
|
|
10484
|
+
refreshCustodyMigration,
|
|
8861
10485
|
hasSession,
|
|
8862
10486
|
verified,
|
|
8863
10487
|
pollarClient,
|
|
@@ -8865,6 +10489,8 @@ function PollarProvider({
|
|
|
8865
10489
|
transaction,
|
|
8866
10490
|
txHistory,
|
|
8867
10491
|
sessions,
|
|
10492
|
+
cosign,
|
|
10493
|
+
confirmations,
|
|
8868
10494
|
walletBalance,
|
|
8869
10495
|
refreshWalletBalance,
|
|
8870
10496
|
enabledAssets,
|
|
@@ -8912,6 +10538,25 @@ function PollarProvider({
|
|
|
8912
10538
|
/* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setCardModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(CardModal, { onClose: () => setCardModalOpen(false) }) }, `${cardModalKey}:${walletAddress}`),
|
|
8913
10539
|
receiveModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setReceiveModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(ReceiveModal, { onClose: () => setReceiveModalOpen(false) }) }),
|
|
8914
10540
|
sessionsModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSessionsModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SessionsModal, { onClose: () => setSessionsModalOpen(false) }) }),
|
|
10541
|
+
cosignModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setCosignModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(CosignModal, { onClose: () => setCosignModalOpen(false) }) }),
|
|
10542
|
+
custodyMigration?.required && !custodyMigrationLater && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: refreshCustodyMigration, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10543
|
+
CustodyMigrationModal,
|
|
10544
|
+
{
|
|
10545
|
+
state: custodyMigration,
|
|
10546
|
+
onMoved: () => {
|
|
10547
|
+
refreshCustodyMigration();
|
|
10548
|
+
refreshRecovery();
|
|
10549
|
+
setRecoveryModalOpen(true);
|
|
10550
|
+
},
|
|
10551
|
+
onLater: () => {
|
|
10552
|
+
setCustodyMigrationLater(true);
|
|
10553
|
+
refreshCustodyMigration();
|
|
10554
|
+
refreshRecovery();
|
|
10555
|
+
}
|
|
10556
|
+
}
|
|
10557
|
+
) }),
|
|
10558
|
+
recoveryModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setRecoveryModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(RecoveryModal, { onClose: () => setRecoveryModalOpen(false) }) }),
|
|
10559
|
+
firstConfirmation && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: firstConfirmation.reject, children: /* @__PURE__ */ jsxRuntime.jsx(ConfirmModal, { confirmation: firstConfirmation }, firstConfirmation.id) }),
|
|
8915
10560
|
distributionRulesModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setDistributionRulesModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(DistributionRulesModal, { onClose: () => setDistributionRulesModalOpen(false) }) })
|
|
8916
10561
|
] });
|
|
8917
10562
|
}
|
|
@@ -8961,6 +10606,8 @@ function WalletButtonTemplate({
|
|
|
8961
10606
|
isInProgress,
|
|
8962
10607
|
showCreateAccount,
|
|
8963
10608
|
notReadyReason,
|
|
10609
|
+
recoveryLocked,
|
|
10610
|
+
onRecovery,
|
|
8964
10611
|
creatingAccount,
|
|
8965
10612
|
onToggleOpen,
|
|
8966
10613
|
onCreateAccount,
|
|
@@ -8978,8 +10625,11 @@ function WalletButtonTemplate({
|
|
|
8978
10625
|
signedIn,
|
|
8979
10626
|
creatingWallet,
|
|
8980
10627
|
createWalletError,
|
|
10628
|
+
custodyChoice,
|
|
8981
10629
|
onCreateWallet
|
|
8982
10630
|
}) {
|
|
10631
|
+
const [selfCustodyNotice, setSelfCustodyNotice] = react.useState(false);
|
|
10632
|
+
const [risksAccepted, setRisksAccepted] = react.useState(false);
|
|
8983
10633
|
if (!walletAddress && signedIn) {
|
|
8984
10634
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-wrapper", ref: wrapperRef, children: [
|
|
8985
10635
|
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-btn", style: { backgroundColor: accentColor }, onClick: onToggleOpen, children: [
|
|
@@ -9003,19 +10653,84 @@ function WalletButtonTemplate({
|
|
|
9003
10653
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice", style: { color: itemColor }, role: "status", children: createWalletError }),
|
|
9004
10654
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
9005
10655
|
] }),
|
|
9006
|
-
onCreateWallet && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10656
|
+
onCreateWallet && !custodyChoice && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9007
10657
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9008
10658
|
"button",
|
|
9009
10659
|
{
|
|
9010
10660
|
className: "pollar-wallet-dropdown-item",
|
|
9011
10661
|
style: { color: itemColor },
|
|
9012
|
-
onClick: onCreateWallet,
|
|
10662
|
+
onClick: () => onCreateWallet(),
|
|
9013
10663
|
disabled: creatingWallet,
|
|
9014
10664
|
children: creatingWallet ? "Creating wallet\u2026" : "Create wallet"
|
|
9015
10665
|
}
|
|
9016
10666
|
),
|
|
9017
10667
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
9018
10668
|
] }),
|
|
10669
|
+
onCreateWallet && custodyChoice && !selfCustodyNotice && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10670
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10671
|
+
"button",
|
|
10672
|
+
{
|
|
10673
|
+
className: "pollar-wallet-dropdown-item",
|
|
10674
|
+
style: { color: itemColor },
|
|
10675
|
+
onClick: () => onCreateWallet("COSIGNED"),
|
|
10676
|
+
disabled: creatingWallet,
|
|
10677
|
+
children: creatingWallet ? "Creating wallet\u2026" : "Create co-signed wallet"
|
|
10678
|
+
}
|
|
10679
|
+
),
|
|
10680
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice", style: { color: itemColor }, children: "You and the app approve every signature together. Your wallet can be recovered with help." }),
|
|
10681
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10682
|
+
"button",
|
|
10683
|
+
{
|
|
10684
|
+
className: "pollar-wallet-dropdown-item",
|
|
10685
|
+
style: { color: itemColor },
|
|
10686
|
+
onClick: () => setSelfCustodyNotice(true),
|
|
10687
|
+
disabled: creatingWallet,
|
|
10688
|
+
children: "Create self-custody wallet"
|
|
10689
|
+
}
|
|
10690
|
+
),
|
|
10691
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice", style: { color: itemColor }, children: "Only your device signs. Nobody else can move or recover your funds." }),
|
|
10692
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
10693
|
+
] }),
|
|
10694
|
+
onCreateWallet && custodyChoice && selfCustodyNotice && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10695
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice", style: { color: itemColor }, 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." }),
|
|
10696
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-wallet-dropdown-notice", style: { color: itemColor }, children: [
|
|
10697
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10698
|
+
"input",
|
|
10699
|
+
{
|
|
10700
|
+
type: "checkbox",
|
|
10701
|
+
checked: risksAccepted,
|
|
10702
|
+
onChange: (e) => setRisksAccepted(e.target.checked),
|
|
10703
|
+
disabled: creatingWallet
|
|
10704
|
+
}
|
|
10705
|
+
),
|
|
10706
|
+
" ",
|
|
10707
|
+
"I understand and accept these risks"
|
|
10708
|
+
] }),
|
|
10709
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10710
|
+
"button",
|
|
10711
|
+
{
|
|
10712
|
+
className: "pollar-wallet-dropdown-item",
|
|
10713
|
+
style: { color: itemColor },
|
|
10714
|
+
onClick: () => onCreateWallet("SELF_CUSTODY"),
|
|
10715
|
+
disabled: creatingWallet || !risksAccepted,
|
|
10716
|
+
children: creatingWallet ? "Creating wallet\u2026" : "Create self-custody wallet"
|
|
10717
|
+
}
|
|
10718
|
+
),
|
|
10719
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10720
|
+
"button",
|
|
10721
|
+
{
|
|
10722
|
+
className: "pollar-wallet-dropdown-item",
|
|
10723
|
+
style: { color: itemColor },
|
|
10724
|
+
onClick: () => {
|
|
10725
|
+
setSelfCustodyNotice(false);
|
|
10726
|
+
setRisksAccepted(false);
|
|
10727
|
+
},
|
|
10728
|
+
disabled: creatingWallet,
|
|
10729
|
+
children: "Back"
|
|
10730
|
+
}
|
|
10731
|
+
),
|
|
10732
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
10733
|
+
] }),
|
|
9019
10734
|
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-wallet-dropdown-item", style: { color: itemColor }, onClick: onSessions, children: "Active sessions" }),
|
|
9020
10735
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" }),
|
|
9021
10736
|
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-wallet-dropdown-item pollar-danger", onClick: onLogout, children: "Log out" })
|
|
@@ -9071,6 +10786,10 @@ function WalletButtonTemplate({
|
|
|
9071
10786
|
}
|
|
9072
10787
|
),
|
|
9073
10788
|
open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-dropdown", style: { backgroundColor: dropdownBg, borderColor: dropdownBorder }, children: [
|
|
10789
|
+
recoveryLocked && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10790
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice pollar-danger", role: "alert", children: "Locked: add a way to recover this wallet before sending or receiving. If you lose this device without one, the funds are lost." }),
|
|
10791
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
10792
|
+
] }),
|
|
9074
10793
|
notReadyReason && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
9075
10794
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice", style: { color: itemColor }, role: "status", children: notReadyReason }),
|
|
9076
10795
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
|
|
@@ -9303,6 +11022,31 @@ function WalletButtonTemplate({
|
|
|
9303
11022
|
),
|
|
9304
11023
|
"Active sessions"
|
|
9305
11024
|
] }),
|
|
11025
|
+
onRecovery && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11026
|
+
"button",
|
|
11027
|
+
{
|
|
11028
|
+
className: `pollar-wallet-dropdown-item${recoveryLocked ? " pollar-danger" : ""}`,
|
|
11029
|
+
style: recoveryLocked ? void 0 : { color: itemColor },
|
|
11030
|
+
onClick: onRecovery,
|
|
11031
|
+
children: [
|
|
11032
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11033
|
+
"svg",
|
|
11034
|
+
{
|
|
11035
|
+
width: "14",
|
|
11036
|
+
height: "14",
|
|
11037
|
+
viewBox: "0 0 24 24",
|
|
11038
|
+
fill: "none",
|
|
11039
|
+
stroke: "currentColor",
|
|
11040
|
+
strokeWidth: "2",
|
|
11041
|
+
strokeLinecap: "round",
|
|
11042
|
+
strokeLinejoin: "round",
|
|
11043
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2 4 5v6c0 5 3.4 9.3 8 11 4.6-1.7 8-6 8-11V5l-8-3z" })
|
|
11044
|
+
}
|
|
11045
|
+
),
|
|
11046
|
+
recoveryLocked ? "Set up wallet recovery" : "Wallet recovery"
|
|
11047
|
+
]
|
|
11048
|
+
}
|
|
11049
|
+
),
|
|
9306
11050
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" }),
|
|
9307
11051
|
/* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-dropdown-item pollar-danger", onClick: onLogout, children: [
|
|
9308
11052
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -9345,7 +11089,10 @@ function WalletButton() {
|
|
|
9345
11089
|
tx: transaction,
|
|
9346
11090
|
isAuthenticated,
|
|
9347
11091
|
createWallet,
|
|
9348
|
-
appConfig
|
|
11092
|
+
appConfig,
|
|
11093
|
+
recovery,
|
|
11094
|
+
recoveryLocked,
|
|
11095
|
+
openRecoveryModal
|
|
9349
11096
|
} = usePollar();
|
|
9350
11097
|
const { primaryChain, primaryAddress } = useChains();
|
|
9351
11098
|
const walletAddress = primaryAddress || (wallet?.address ?? "");
|
|
@@ -9408,12 +11155,12 @@ function WalletButton() {
|
|
|
9408
11155
|
setCreating(false);
|
|
9409
11156
|
}
|
|
9410
11157
|
}
|
|
9411
|
-
async function handleCreateWallet() {
|
|
11158
|
+
async function handleCreateWallet(custody) {
|
|
9412
11159
|
if (creatingWallet) return;
|
|
9413
11160
|
setCreatingWallet(true);
|
|
9414
11161
|
setCreateWalletError(null);
|
|
9415
11162
|
try {
|
|
9416
|
-
await createWallet();
|
|
11163
|
+
await createWallet(custody ? { custody } : void 0);
|
|
9417
11164
|
setOpen(false);
|
|
9418
11165
|
} catch (err) {
|
|
9419
11166
|
setCreateWalletError(
|
|
@@ -9443,6 +11190,10 @@ function WalletButton() {
|
|
|
9443
11190
|
setOpen(false);
|
|
9444
11191
|
openSessionsModal();
|
|
9445
11192
|
}
|
|
11193
|
+
function handleRecovery() {
|
|
11194
|
+
setOpen(false);
|
|
11195
|
+
openRecoveryModal();
|
|
11196
|
+
}
|
|
9446
11197
|
function handleKyc() {
|
|
9447
11198
|
setOpen(false);
|
|
9448
11199
|
openKycModal();
|
|
@@ -9471,6 +11222,7 @@ function WalletButton() {
|
|
|
9471
11222
|
signedIn: isAuthenticated,
|
|
9472
11223
|
creatingWallet,
|
|
9473
11224
|
createWalletError,
|
|
11225
|
+
custodyChoice: appConfig.application?.walletCustodyMode === "USER_CHOICE",
|
|
9474
11226
|
...appConfig.application?.walletProvisioning === "NONE" ? {} : { onCreateWallet: handleCreateWallet },
|
|
9475
11227
|
notReadyReason,
|
|
9476
11228
|
creatingAccount: creating,
|
|
@@ -9482,6 +11234,8 @@ function WalletButton() {
|
|
|
9482
11234
|
onSend: handleSend,
|
|
9483
11235
|
onReceive: handleReceive,
|
|
9484
11236
|
onSessions: handleSessions,
|
|
11237
|
+
recoveryLocked,
|
|
11238
|
+
...recovery?.required ? { onRecovery: handleRecovery } : {},
|
|
9485
11239
|
onKyc: handleKyc,
|
|
9486
11240
|
onRamp: handleRamp,
|
|
9487
11241
|
onDistributionRules: handleDistributionRules,
|
|
@@ -9493,6 +11247,10 @@ function WalletButton() {
|
|
|
9493
11247
|
|
|
9494
11248
|
exports.CardModal = CardModal;
|
|
9495
11249
|
exports.ChainSelect = ChainSelect;
|
|
11250
|
+
exports.CosignModal = CosignModal;
|
|
11251
|
+
exports.CosignModalTemplate = CosignModalTemplate;
|
|
11252
|
+
exports.CustodyMigrationModal = CustodyMigrationModal;
|
|
11253
|
+
exports.CustodyMigrationModalTemplate = CustodyMigrationModalTemplate;
|
|
9496
11254
|
exports.DistributionRulesModal = DistributionRulesModal;
|
|
9497
11255
|
exports.DistributionRulesModalTemplate = DistributionRulesModalTemplate;
|
|
9498
11256
|
exports.EarnModal = EarnModal;
|
|
@@ -9506,8 +11264,11 @@ exports.PollarProvider = PollarProvider;
|
|
|
9506
11264
|
exports.ProviderRegistrationModal = ProviderRegistrationModal;
|
|
9507
11265
|
exports.RampWidget = RampWidget;
|
|
9508
11266
|
exports.RampWidgetTemplate = RampWidgetTemplate;
|
|
11267
|
+
exports.RampWorkflow = RampWorkflow;
|
|
9509
11268
|
exports.ReceiveModal = ReceiveModal;
|
|
9510
11269
|
exports.ReceiveModalTemplate = ReceiveModalTemplate;
|
|
11270
|
+
exports.RecoveryModal = RecoveryModal;
|
|
11271
|
+
exports.RecoveryModalTemplate = RecoveryModalTemplate;
|
|
9511
11272
|
exports.RegistryCheckModal = RegistryCheckModal;
|
|
9512
11273
|
exports.RequirementFormModal = RequirementFormModal;
|
|
9513
11274
|
exports.RouteDisplay = RouteDisplay;
|
|
@@ -9527,6 +11288,7 @@ exports.WalletButtonTemplate = WalletButtonTemplate;
|
|
|
9527
11288
|
exports.addressForChain = addressForChain;
|
|
9528
11289
|
exports.browserPasskeyCeremony = browserPasskeyCeremony;
|
|
9529
11290
|
exports.browserPasskeySigner = browserPasskeySigner;
|
|
11291
|
+
exports.browserRecoveryPasskey = browserRecoveryPasskey;
|
|
9530
11292
|
exports.buildModalCssVars = buildModalCssVars;
|
|
9531
11293
|
exports.chainsOf = chainsOf;
|
|
9532
11294
|
exports.createPollarAdapterHook = createPollarAdapterHook;
|
|
@@ -9534,6 +11296,7 @@ exports.modalChrome = modalChrome;
|
|
|
9534
11296
|
exports.readableTextOn = readableTextOn;
|
|
9535
11297
|
exports.resolveChain = resolveChain;
|
|
9536
11298
|
exports.useChains = useChains;
|
|
11299
|
+
exports.useCosign = useCosign;
|
|
9537
11300
|
exports.usePollar = usePollar;
|
|
9538
11301
|
exports.walletNotReadyReason = walletNotReadyReason;
|
|
9539
11302
|
//# sourceMappingURL=index.js.map
|