@pollar/react 0.11.4-rc.4 → 0.11.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/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 = ({ shield = false }) => {
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.jsxs("div", { className: "pollar-footer-brand", children: [
1034
- shield ? /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: "pollar-footer-shield", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, children: [
1035
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 3.2 19 6v5.3c0 4.4-2.9 7.8-7 9.5-4.1-1.7-7-5.1-7-9.5V6l7-2.8Z", fill: "var(--pollar-accent)" }),
1036
- /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m8.5 12 2.2 2.2 4.8-5", stroke: "white", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" })
1037
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR, alt: "Pollar", className: "pollar-footer-logo" }),
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-rc.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.11.5"
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",
@@ -2264,15 +2274,35 @@ function initialValues(fields, answers) {
2264
2274
  return values;
2265
2275
  }
2266
2276
  var DATE = /^\d{4}-\d{2}-\d{2}$/;
2277
+ function localFieldError(field, value) {
2278
+ if (typeof value !== "string" || !value.trim()) return null;
2279
+ const text = value.trim();
2280
+ const rules = field.validation ?? {};
2281
+ if (field.type === "number") {
2282
+ const number = Number(text);
2283
+ if (!Number.isFinite(number)) return "invalid_type";
2284
+ if (rules.min !== void 0 && number < rules.min) return "too_small";
2285
+ if (rules.max !== void 0 && number > rules.max) return "too_large";
2286
+ return null;
2287
+ }
2288
+ if (field.type === "date") {
2289
+ return DATE.test(text) && !Number.isNaN(Date.parse(`${text}T00:00:00Z`)) ? null : "invalid_format";
2290
+ }
2291
+ if (field.type === "select" || field.type === "multiselect" || field.type === "checkbox") return null;
2292
+ if (rules.maxLength !== void 0 && text.length > rules.maxLength) return "too_long";
2293
+ if (rules.pattern) {
2294
+ try {
2295
+ if (!new RegExp(rules.pattern).test(text)) return "pattern";
2296
+ } catch {
2297
+ }
2298
+ }
2299
+ return null;
2300
+ }
2267
2301
  function localFieldErrors(fields, values) {
2268
2302
  const errors = {};
2269
2303
  for (const field of fields) {
2270
- const value = values[field.key];
2271
- if (typeof value !== "string" || !value.trim()) continue;
2272
- if (field.type === "number" && !Number.isFinite(Number(value))) errors[field.key] = "invalid_type";
2273
- if (field.type === "date" && (!DATE.test(value.trim()) || Number.isNaN(Date.parse(`${value.trim()}T00:00:00Z`)))) {
2274
- errors[field.key] = "invalid_format";
2275
- }
2304
+ const error = localFieldError(field, values[field.key]);
2305
+ if (error) errors[field.key] = error;
2276
2306
  }
2277
2307
  return errors;
2278
2308
  }
@@ -2352,7 +2382,8 @@ function FieldInput({
2352
2382
  value,
2353
2383
  language,
2354
2384
  disabled,
2355
- onChange
2385
+ onChange,
2386
+ onBlur
2356
2387
  }) {
2357
2388
  const id = `pollar-form-${field.key}`;
2358
2389
  const text = typeof value === "string" ? value : "";
@@ -2386,7 +2417,8 @@ function FieldInput({
2386
2417
  value: text,
2387
2418
  disabled,
2388
2419
  maxLength: field.validation?.maxLength,
2389
- onChange: (e) => onChange(e.target.value)
2420
+ onChange: (e) => onChange(e.target.value),
2421
+ onBlur
2390
2422
  }
2391
2423
  );
2392
2424
  default:
@@ -2402,7 +2434,8 @@ function FieldInput({
2402
2434
  min: field.validation?.min,
2403
2435
  max: field.validation?.max,
2404
2436
  maxLength: field.validation?.maxLength,
2405
- onChange: (e) => onChange(e.target.value)
2437
+ onChange: (e) => onChange(e.target.value),
2438
+ onBlur
2406
2439
  }
2407
2440
  );
2408
2441
  }
@@ -2433,6 +2466,24 @@ function RequirementFormModal({ formId, progress, onClose, onSubmitted }) {
2433
2466
  setValues(initialValues(loaded.fields, loaded.answers));
2434
2467
  }).catch(() => mounted.current && setError(copy.loadError));
2435
2468
  }, [formId]);
2469
+ function recheck(field, value, onlyIfShown) {
2470
+ if (typeof value === "string" && !value.trim()) return;
2471
+ setFieldErrors((errors) => {
2472
+ if (onlyIfShown && !(field.key in errors)) return errors;
2473
+ const next = { ...errors };
2474
+ const error2 = localFieldError(field, value);
2475
+ if (error2) next[field.key] = error2;
2476
+ else delete next[field.key];
2477
+ return next;
2478
+ });
2479
+ }
2480
+ function change(field, value) {
2481
+ setValues((v) => ({ ...v, [field.key]: value }));
2482
+ recheck(field, value, true);
2483
+ }
2484
+ function blur(field) {
2485
+ recheck(field, values[field.key], false);
2486
+ }
2436
2487
  async function submit() {
2437
2488
  if (!form) return;
2438
2489
  setError(null);
@@ -2512,7 +2563,8 @@ function RequirementFormModal({ formId, progress, onClose, onSubmitted }) {
2512
2563
  value: values[field.key] ?? "",
2513
2564
  language,
2514
2565
  disabled: submitting,
2515
- onChange: (value) => setValues((v) => ({ ...v, [field.key]: value }))
2566
+ onChange: (value) => change(field, value),
2567
+ onBlur: () => blur(field)
2516
2568
  }
2517
2569
  )
2518
2570
  ] }),
@@ -3197,7 +3249,11 @@ function LoginModal({ onClose }) {
3197
3249
  const [email, setEmail] = react.useState("");
3198
3250
  const { getClient, styles, appConfig: config, configStatus, retryConfig } = usePollar();
3199
3251
  const [authState, setAuthState] = react.useState(() => getClient().getAuthState());
3200
- const walletAdapters = react.useMemo(() => getClient().listWalletAdapters(), [getClient]);
3252
+ const servedChains = config?.application?.chains;
3253
+ const walletAdapters = react.useMemo(
3254
+ () => getClient().listWalletAdapters().filter((a) => !servedChains || servedChains.includes(a.chain)),
3255
+ [getClient, servedChains]
3256
+ );
3201
3257
  const [codeInputKey, setCodeInputKey] = react.useState(0);
3202
3258
  const pendingEmail = react.useRef(null);
3203
3259
  const [interactiveAdapter, setInteractiveAdapter] = react.useState(null);
@@ -3482,6 +3538,8 @@ function placeholderFor(field, fields, values) {
3482
3538
  }
3483
3539
  return field.placeholder;
3484
3540
  }
3541
+ var CHAIN_NAME = { STELLAR: "Stellar", POLYGON: "Polygon", SOLANA: "Solana" };
3542
+ var EXPLORER_NAME = { STELLAR: "Stellar Expert", POLYGON: "Polygonscan", SOLANA: "Solana Explorer" };
3485
3543
  var LOADING_STEPS = ["Detecting your country\u2026", "Consulting providers\u2026", "Route found!"];
3486
3544
  function flagEmoji(code) {
3487
3545
  const cc = code.trim().toUpperCase();
@@ -3528,7 +3586,12 @@ function RampWidgetTemplate({
3528
3586
  onboardingStatus,
3529
3587
  kycJustApproved,
3530
3588
  stellarTxHash,
3589
+ txHash,
3590
+ txChain,
3531
3591
  explorerUrl,
3592
+ fundsInTransit = false,
3593
+ retrying = false,
3594
+ onRetryTransit,
3532
3595
  depositInstructions,
3533
3596
  canComplete,
3534
3597
  completing,
@@ -3550,6 +3613,8 @@ function RampWidgetTemplate({
3550
3613
  onRefresh,
3551
3614
  onClose
3552
3615
  }) {
3616
+ const settledHash = txHash ?? stellarTxHash;
3617
+ const chainName = CHAIN_NAME[txChain ?? "STELLAR"];
3553
3618
  const cssVars = buildModalCssVars(theme, accentColor, styleOverrides, "hero");
3554
3619
  const stepTitle = {
3555
3620
  input: direction === "onramp" ? "Buy crypto" : "Sell crypto",
@@ -3782,15 +3847,23 @@ function RampWidgetTemplate({
3782
3847
  txStatus !== "completed" && txStatus !== "failed" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-spinner pollar-spinner-sm", "aria-label": "Checking status" })
3783
3848
  ] })
3784
3849
  ] }),
3785
- stellarTxHash && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
3786
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "Stellar tx" }),
3850
+ fundsInTransit && txStatus !== "completed" && txStatus !== "failed" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
3851
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-ramp-payment-label", children: "Funds in transit" }),
3852
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-ramp-payment-note", children: "Your money is safe in your own wallet, waiting for the next step of the transfer." }),
3853
+ onRetryTransit && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onRetryTransit, disabled: retrying, children: retrying ? "Retrying..." : "Retry now" })
3854
+ ] }),
3855
+ settledHash && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-field", children: [
3856
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "pollar-ramp-payment-label", children: [
3857
+ chainName,
3858
+ " tx"
3859
+ ] }),
3787
3860
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-ramp-payment-value", style: { display: "flex", alignItems: "center", gap: 6 }, children: [
3788
3861
  /* @__PURE__ */ jsxRuntime.jsxs("code", { style: { flex: 1, wordBreak: "break-all" }, children: [
3789
- stellarTxHash.slice(0, 8),
3862
+ settledHash.slice(0, 8),
3790
3863
  "\u2026",
3791
- stellarTxHash.slice(-8)
3864
+ settledHash.slice(-8)
3792
3865
  ] }),
3793
- /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: stellarTxHash, label: "Copy transaction hash" }),
3866
+ /* @__PURE__ */ jsxRuntime.jsx(CopyButton, { value: settledHash, label: "Copy transaction hash" }),
3794
3867
  explorerUrl && /* @__PURE__ */ jsxRuntime.jsx(
3795
3868
  "a",
3796
3869
  {
@@ -3798,8 +3871,8 @@ function RampWidgetTemplate({
3798
3871
  target: "_blank",
3799
3872
  rel: "noopener noreferrer",
3800
3873
  className: "pollar-copy-btn",
3801
- "aria-label": "View on Stellar Expert",
3802
- title: "View on Stellar Expert",
3874
+ "aria-label": `View on ${EXPLORER_NAME[txChain ?? "STELLAR"]}`,
3875
+ title: `View on ${EXPLORER_NAME[txChain ?? "STELLAR"]}`,
3803
3876
  children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "13", height: "13", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
3804
3877
  /* @__PURE__ */ jsxRuntime.jsx(
3805
3878
  "path",
@@ -3971,6 +4044,7 @@ var REGISTRATION_COPY = {
3971
4044
  incomplete: "Your registration with the provider did not finish. Register again to complete it.",
3972
4045
  providerDown: "The provider is not responding right now. Please try again in a few minutes.",
3973
4046
  ipNotSupported: "The provider cannot accept your current connection (IPv6). Please try again from another network, for example Wi-Fi.",
4047
+ emailTaken: "This email is already registered with the provider through another app. Use a different email to register here.",
3974
4048
  loadError: "Could not load the registration. Please try again.",
3975
4049
  submitError: "Could not register you. Please try again.",
3976
4050
  step: "Step {n} of {total}",
@@ -3990,6 +4064,7 @@ var REGISTRATION_COPY = {
3990
4064
  incomplete: "Tu registro con el proveedor no se complet\xF3. Reg\xEDstrate de nuevo para terminarlo.",
3991
4065
  providerDown: "El proveedor no responde en este momento. Intenta de nuevo en unos minutos.",
3992
4066
  ipNotSupported: "El proveedor no acepta tu conexi\xF3n actual (IPv6). Intenta desde otra red, por ejemplo Wi-Fi.",
4067
+ emailTaken: "Este email ya est\xE1 registrado con el proveedor desde otra app. Usa otro email para registrarte aqu\xED.",
3993
4068
  loadError: "No se pudo cargar el registro. Intenta de nuevo.",
3994
4069
  submitError: "No se pudo completar el registro. Intenta de nuevo.",
3995
4070
  step: "Paso {n} de {total}",
@@ -4312,6 +4387,7 @@ function ProviderRegistrationModal({
4312
4387
  } else if (code === "KYC_REGISTRATION_STEPS_PENDING") setError(copy.notReady);
4313
4388
  else if (code === "SDK_CARDS_PROVIDER_ERROR") setError(copy.providerDown);
4314
4389
  else if (code === "SDK_CARDS_IP_NOT_SUPPORTED") setError(copy.ipNotSupported);
4390
+ else if (code === "SDK_CARDS_PROVIDER_USER_TAKEN") setError(copy.emailTaken);
4315
4391
  else setError(copy.submitError);
4316
4392
  } finally {
4317
4393
  if (mounted.current) setSubmitting(false);
@@ -4440,6 +4516,13 @@ function rampErrorMessage(e, fallback) {
4440
4516
  }
4441
4517
  return RAMP_ERROR_MESSAGES[code] ?? (e instanceof Error ? e.message : fallback);
4442
4518
  }
4519
+ function explorerTxUrl2(chain, hash, network) {
4520
+ if (!hash) return null;
4521
+ const testnet = network === "testnet";
4522
+ if (chain === "SOLANA") return `https://explorer.solana.com/tx/${hash}${testnet ? "?cluster=devnet" : ""}`;
4523
+ if (chain === "POLYGON") return `https://${testnet ? "amoy." : ""}polygonscan.com/tx/${hash}`;
4524
+ return `https://stellar.expert/explorer/${testnet ? "testnet" : "public"}/tx/${hash}`;
4525
+ }
4443
4526
  function RampWidget({ onClose }) {
4444
4527
  const { getClient, signTx, wallet, styles, network } = usePollar();
4445
4528
  const walletAddress = wallet?.address ?? "";
@@ -4477,11 +4560,36 @@ function RampWidget({ onClose }) {
4477
4560
  const [onboardingStatus, setOnboardingStatus] = react.useState(void 0);
4478
4561
  const [txStatus, setTxStatus] = react.useState(null);
4479
4562
  const [stellarTxHash, setStellarTxHash] = react.useState(null);
4563
+ const [txHash, setTxHash] = react.useState(null);
4564
+ const [txChain, setTxChain] = react.useState(null);
4565
+ const [fundsInTransit, setFundsInTransit] = react.useState(false);
4566
+ const [retrying, setRetrying] = react.useState(false);
4480
4567
  const [depositInstructions, setDepositInstructions] = react.useState(null);
4481
4568
  const [completing, setCompleting] = react.useState(false);
4482
4569
  const [errorMsg, setErrorMsg] = react.useState(null);
4570
+ const signingRef = react.useRef(false);
4483
4571
  const directionRef = react.useRef(direction);
4484
4572
  directionRef.current = direction;
4573
+ function applySettlement(tx) {
4574
+ if (tx.stellarTxHash) setStellarTxHash(tx.stellarTxHash);
4575
+ if (tx.txHash) setTxHash(tx.txHash);
4576
+ if (tx.chain) setTxChain(tx.chain);
4577
+ setFundsInTransit(tx.fundsInTransit === true);
4578
+ }
4579
+ async function handleRetryTransit() {
4580
+ if (!txId || retrying) return;
4581
+ setRetrying(true);
4582
+ setErrorMsg(null);
4583
+ try {
4584
+ const tx = await client.retryRampTransaction(txId);
4585
+ setTxStatus(tx.status);
4586
+ applySettlement(tx);
4587
+ } catch (e) {
4588
+ setErrorMsg(e instanceof Error && e.message ? e.message : "Could not retry the transfer. Try again in a moment.");
4589
+ } finally {
4590
+ setRetrying(false);
4591
+ }
4592
+ }
4485
4593
  react.useEffect(() => {
4486
4594
  if (step !== "status" || !txId) return;
4487
4595
  if (txStatus && TERMINAL.includes(txStatus)) return;
@@ -4491,7 +4599,14 @@ function RampWidget({ onClose }) {
4491
4599
  const tx = await client.getRampTransaction(txId);
4492
4600
  if (!active) return;
4493
4601
  setTxStatus(tx.status);
4494
- if (tx.stellarTxHash) setStellarTxHash(tx.stellarTxHash);
4602
+ applySettlement(tx);
4603
+ const pending = tx.pendingSignature;
4604
+ if (pending && !signingRef.current) {
4605
+ signingRef.current = true;
4606
+ void resumeRef.current(txId, pending).finally(() => {
4607
+ signingRef.current = false;
4608
+ });
4609
+ }
4495
4610
  if (tx.kycUrl) setKycUrl(tx.kycUrl);
4496
4611
  if (tx.depositInstructions) setDepositInstructions(tx.depositInstructions);
4497
4612
  if (TERMINAL.includes(tx.status)) clearInterval(id);
@@ -4558,7 +4673,7 @@ function RampWidget({ onClose }) {
4558
4673
  } else if (step === "status" && txId) {
4559
4674
  const tx = await client.getRampTransaction(txId);
4560
4675
  setTxStatus(tx.status);
4561
- if (tx.stellarTxHash) setStellarTxHash(tx.stellarTxHash);
4676
+ applySettlement(tx);
4562
4677
  if (tx.kycUrl) setKycUrl(tx.kycUrl);
4563
4678
  if (tx.depositInstructions) setDepositInstructions(tx.depositInstructions);
4564
4679
  }
@@ -4579,6 +4694,9 @@ function RampWidget({ onClose }) {
4579
4694
  setTosUrl(null);
4580
4695
  setTxStatus(null);
4581
4696
  setStellarTxHash(null);
4697
+ setTxHash(null);
4698
+ setTxChain(null);
4699
+ setFundsInTransit(false);
4582
4700
  setDepositInstructions(null);
4583
4701
  setKycPending(false);
4584
4702
  setKycApproved(false);
@@ -4587,6 +4705,11 @@ function RampWidget({ onClose }) {
4587
4705
  }
4588
4706
  async function resumeWithSignature(id, ps) {
4589
4707
  const outcome = await signTx(ps.unsignedXdr);
4708
+ if (outcome.status === "cosign_pending") {
4709
+ setErrorMsg("Approve the signature on your device, then resume.");
4710
+ setStep("error");
4711
+ return;
4712
+ }
4590
4713
  if (outcome.status !== "signed") {
4591
4714
  setErrorMsg(outcome.message ?? outcome.details ?? "Signing was cancelled.");
4592
4715
  setStep("error");
@@ -4594,10 +4717,13 @@ function RampWidget({ onClose }) {
4594
4717
  }
4595
4718
  const result = await client.submitRampSignature(id, {
4596
4719
  signedXdr: outcome.signedXdr,
4720
+ // The CCTP actions are not in the generated schema until it is regenerated.
4597
4721
  action: ps.action
4598
4722
  });
4599
4723
  await applyResult(result);
4600
4724
  }
4725
+ const resumeRef = react.useRef(resumeWithSignature);
4726
+ resumeRef.current = resumeWithSignature;
4601
4727
  async function applyResult(result) {
4602
4728
  setTxId(result.txId);
4603
4729
  setProvider(result.provider);
@@ -4753,7 +4879,7 @@ function RampWidget({ onClose }) {
4753
4879
  }
4754
4880
  }
4755
4881
  const kycBlocking = kycPending && !kycApproved;
4756
- const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash && !kycPending;
4882
+ const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash && !txHash && !kycPending;
4757
4883
  const flowSteps = flowStepsOf(quotes, selectedQuote);
4758
4884
  const flowStepIndex = flowSteps.indexOf(STEP_LABEL[step] ?? "");
4759
4885
  if (pendingKyc?.type === "FORM") {
@@ -4838,7 +4964,12 @@ function RampWidget({ onClose }) {
4838
4964
  onboardingStatus: onboardingStatus ?? null,
4839
4965
  kycJustApproved: kycPending && kycApproved,
4840
4966
  stellarTxHash,
4841
- explorerUrl: stellarTxHash ? `https://stellar.expert/explorer/${network === "mainnet" ? "public" : "testnet"}/tx/${stellarTxHash}` : null,
4967
+ txHash,
4968
+ txChain,
4969
+ explorerUrl: explorerTxUrl2(txChain ?? "STELLAR", txHash ?? stellarTxHash, network),
4970
+ fundsInTransit,
4971
+ retrying,
4972
+ onRetryTransit: handleRetryTransit,
4842
4973
  depositInstructions,
4843
4974
  canComplete,
4844
4975
  completing,
@@ -4945,7 +5076,7 @@ function PollarLogo(props) {
4945
5076
  )
4946
5077
  ] });
4947
5078
  }
4948
- var CHAIN_NAME = {
5079
+ var CHAIN_NAME2 = {
4949
5080
  STELLAR: "Stellar",
4950
5081
  POLYGON: "Polygon",
4951
5082
  SOLANA: "Solana"
@@ -4964,7 +5095,7 @@ function ReceiveModalTemplate({
4964
5095
  onClose
4965
5096
  }) {
4966
5097
  const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
4967
- const chainName = selectedChain ? CHAIN_NAME[selectedChain] ?? selectedChain : "wallet";
5098
+ const chainName = selectedChain ? CHAIN_NAME2[selectedChain] ?? selectedChain : "wallet";
4968
5099
  return /* @__PURE__ */ jsxRuntime.jsxs(
4969
5100
  "div",
4970
5101
  {
@@ -5046,7 +5177,7 @@ function ReceiveModalTemplate({
5046
5177
  ] })
5047
5178
  ] })
5048
5179
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No wallet connected." }),
5049
- /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, { shield: true })
5180
+ /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
5050
5181
  ]
5051
5182
  }
5052
5183
  );
@@ -5109,6 +5240,7 @@ var STATUS_MESSAGES = {
5109
5240
  submitting: "Submitting transaction\u2026",
5110
5241
  submitted: "Submitted \u2014 waiting for confirmation\u2026",
5111
5242
  "signing-submitting": "Signing and submitting transaction\u2026",
5243
+ awaiting_cosign: "Waiting for your approval on this device\u2026",
5112
5244
  "building-signing-submitting": "Processing transaction\u2026",
5113
5245
  success: "Transaction sent successfully",
5114
5246
  error: "Transaction failed"
@@ -5144,14 +5276,22 @@ function TxStatusView({
5144
5276
  }) {
5145
5277
  const buildData = "buildData" in transaction ? transaction.buildData : null;
5146
5278
  const hash = transaction.step === "success" ? transaction.hash : null;
5147
- const errorDetails = transaction.step === "error" ? transaction.details ?? null : null;
5279
+ const errorDetails = transaction.step === "error" ? core.transactionErrorMessage(transaction.code, transaction.details) : null;
5148
5280
  const isBuilt = transaction.step === "built";
5149
5281
  const isInFlight = IN_FLIGHT_STEPS.has(transaction.step);
5150
5282
  const isSuccess = transaction.step === "success";
5151
5283
  const isError = transaction.step === "error";
5152
5284
  const showDetails = buildData !== null && SHOW_DETAILS_STEPS.has(transaction.step);
5153
- const walletImg = walletType === core.WalletType.FREIGHTER ? LOGO_FREIGHTER : walletType === core.WalletType.ALBEDO ? LOGO_ALBEDO : LOGO_POLLAR;
5285
+ const walletImg = walletType === core.WalletType.FREIGHTER ? LOGO_FREIGHTER : walletType === core.WalletType.ALBEDO ? LOGO_ALBEDO : null;
5154
5286
  const walletAlt = walletType === core.WalletType.FREIGHTER ? "Freighter" : walletType === core.WalletType.ALBEDO ? "Albedo" : "Pollar";
5287
+ const statusBanner = /* @__PURE__ */ jsxRuntime.jsx(
5288
+ ModalStatusBanner,
5289
+ {
5290
+ message: STATUS_MESSAGES[transaction.step],
5291
+ status: isError ? "ERROR" : isInFlight ? "LOADING" : isSuccess ? "SUCCESS" : "NONE"
5292
+ }
5293
+ );
5294
+ const showSpinner = isInFlight || isSuccess || isError;
5155
5295
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5156
5296
  showDetails && buildData && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5157
5297
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-summary", children: [
@@ -5192,7 +5332,7 @@ function TxStatusView({
5192
5332
  /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "pollar-tx-error-details-content", children: errorDetails })
5193
5333
  ] }),
5194
5334
  isBuilt && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-primary pollar-tx-sign-btn", onClick: onSignAndSend, children: "Sign & Send" }),
5195
- (isInFlight || isSuccess || isError) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-wallet-spinner", children: [
5335
+ showSpinner && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-wallet-spinner", children: [
5196
5336
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-tx-spinner-ring", children: [
5197
5337
  /* @__PURE__ */ jsxRuntime.jsxs(
5198
5338
  "svg",
@@ -5222,8 +5362,12 @@ function TxStatusView({
5222
5362
  ]
5223
5363
  }
5224
5364
  ),
5225
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-tx-wallet-icon", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: walletImg, alt: walletAlt, className: "pollar-tx-wallet-img" }) })
5365
+ /* @__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: [
5366
+ /* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR_MARK_ON_LIGHT, alt: walletAlt, className: "pollar-tx-wallet-img pollar-logo-on-light" }),
5367
+ /* @__PURE__ */ jsxRuntime.jsx("img", { src: LOGO_POLLAR_MARK_ON_DARK, alt: walletAlt, className: "pollar-tx-wallet-img pollar-logo-on-dark" })
5368
+ ] }) })
5226
5369
  ] }),
5370
+ statusBanner,
5227
5371
  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" }),
5228
5372
  isError && onRetry && "buildData" in transaction && transaction.buildData && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-secondary pollar-tx-retry-btn", onClick: onRetry, children: "Try again" })
5229
5373
  ] }),
@@ -5288,13 +5432,7 @@ function TxStatusView({
5288
5432
  ] })
5289
5433
  ] }),
5290
5434
  isSuccess && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-primary pollar-tx-sign-btn", onClick: onDone, children: "Done" }),
5291
- /* @__PURE__ */ jsxRuntime.jsx(
5292
- ModalStatusBanner,
5293
- {
5294
- message: STATUS_MESSAGES[transaction.step],
5295
- status: isError ? "ERROR" : isInFlight ? "LOADING" : isSuccess ? "SUCCESS" : "NONE"
5296
- }
5297
- )
5435
+ !showSpinner && statusBanner
5298
5436
  ] });
5299
5437
  }
5300
5438
  function formatBalance(balance) {
@@ -5311,6 +5449,11 @@ function chainLabel(chain) {
5311
5449
  if (chain === "POLYGON") return "Polygon";
5312
5450
  return "network";
5313
5451
  }
5452
+ function destinationPlaceholder(chain) {
5453
+ if (chain === "SOLANA") return "Solana address";
5454
+ if (chain === "POLYGON") return "0x\u2026";
5455
+ return "G\u2026";
5456
+ }
5314
5457
  function AssetIcon({ code }) {
5315
5458
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-asset-icon", "aria-hidden": true, children: code.slice(0, 2).toUpperCase() });
5316
5459
  }
@@ -5428,6 +5571,10 @@ function SendModalTemplate({
5428
5571
  onMax,
5429
5572
  onPaste,
5430
5573
  onDestinationChange,
5574
+ memo = "",
5575
+ memoType = "text",
5576
+ onMemoChange,
5577
+ onMemoTypeChange,
5431
5578
  onSubmit,
5432
5579
  onSignAndSend,
5433
5580
  onToggleXdr,
@@ -5535,7 +5682,7 @@ function SendModalTemplate({
5535
5682
  {
5536
5683
  className: "pollar-input pollar-send-destination-input",
5537
5684
  type: "text",
5538
- placeholder: "G\u2026",
5685
+ placeholder: destinationPlaceholder(selectedChain),
5539
5686
  value: destination,
5540
5687
  onChange: (e) => onDestinationChange(e.target.value),
5541
5688
  "aria-label": "Destination wallet"
@@ -5544,6 +5691,39 @@ function SendModalTemplate({
5544
5691
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-send-inline-action", onClick: onPaste, children: "Paste" })
5545
5692
  ] })
5546
5693
  ] }),
5694
+ selectedChain === "STELLAR" && onMemoChange && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-field", children: [
5695
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "pollar-send-label", htmlFor: "pollar-send-memo", children: [
5696
+ "Memo ",
5697
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-send-label-optional", children: "(optional)" })
5698
+ ] }),
5699
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-send-memo-row", children: [
5700
+ /* @__PURE__ */ jsxRuntime.jsxs(
5701
+ "select",
5702
+ {
5703
+ className: "pollar-input pollar-send-memo-type",
5704
+ value: memoType,
5705
+ onChange: (e) => onMemoTypeChange?.(e.target.value),
5706
+ "aria-label": "Memo type",
5707
+ children: [
5708
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "text", children: "Text" }),
5709
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "id", children: "ID" })
5710
+ ]
5711
+ }
5712
+ ),
5713
+ /* @__PURE__ */ jsxRuntime.jsx(
5714
+ "input",
5715
+ {
5716
+ id: "pollar-send-memo",
5717
+ className: "pollar-input pollar-send-memo-input",
5718
+ type: "text",
5719
+ inputMode: memoType === "id" ? "numeric" : "text",
5720
+ placeholder: memoType === "id" ? "123456789" : "Up to 28 characters",
5721
+ value: memo,
5722
+ onChange: (e) => onMemoChange(e.target.value)
5723
+ }
5724
+ )
5725
+ ] })
5726
+ ] }),
5547
5727
  formError && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-error", children: formError }),
5548
5728
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-btn-primary", onClick: onSubmit, disabled: !canSubmit, children: "Continue" }) })
5549
5729
  ] }),
@@ -5567,6 +5747,16 @@ function SendModalTemplate({
5567
5747
  }
5568
5748
  );
5569
5749
  }
5750
+ var MAX_MEMO_ID = 18446744073709551615n;
5751
+ function parseMemo(type, raw) {
5752
+ const value = type === "id" ? raw.trim() : raw;
5753
+ if (value.trim() === "") return void 0;
5754
+ if (type === "text") {
5755
+ return new TextEncoder().encode(value).length > 28 ? "The memo text can be at most 28 bytes." : { type, value };
5756
+ }
5757
+ if (!/^\d+$/.test(value) || BigInt(value) > MAX_MEMO_ID) return "The memo ID must be a whole number up to 2^64 - 1.";
5758
+ return { type, value };
5759
+ }
5570
5760
  function assetParam(record) {
5571
5761
  if (record.type === "native") return { type: "native" };
5572
5762
  if (record.type === "credit_alphanum4") {
@@ -5591,6 +5781,8 @@ function SendModal({ onClose }) {
5591
5781
  const [step, setStep] = react.useState("form");
5592
5782
  const [amount, setAmount] = react.useState("");
5593
5783
  const [destination, setDestination] = react.useState("");
5784
+ const [memo, setMemo] = react.useState("");
5785
+ const [memoType, setMemoType] = react.useState("text");
5594
5786
  const [selectedAsset, setSelectedAsset] = react.useState(null);
5595
5787
  const [showXdr, setShowXdr] = react.useState(false);
5596
5788
  const [copied, setCopied] = react.useState(false);
@@ -5601,9 +5793,10 @@ function SendModal({ onClose }) {
5601
5793
  react.useEffect(() => {
5602
5794
  if (selectedChain === null && chains.length > 0) setSelectedChain(chains[0]);
5603
5795
  }, [chains, selectedChain]);
5604
- const canSendOnChain = selectedChain === "STELLAR" || selectedChain === "SOLANA";
5796
+ const canSendOnChain = selectedChain === "STELLAR" || selectedChain === "SOLANA" || selectedChain === "POLYGON";
5605
5797
  const notReadyReason = walletNotReadyReason(wallet, selectedChain);
5606
- const isBaseUnitChain = selectedChain === "SOLANA";
5798
+ const isBaseUnitChain = selectedChain === "SOLANA" || selectedChain === "POLYGON";
5799
+ const nativeDecimals = selectedChain === "POLYGON" ? 18 : 9;
5607
5800
  react.useEffect(() => {
5608
5801
  void refreshWalletBalance();
5609
5802
  }, [refreshWalletBalance]);
@@ -5631,7 +5824,7 @@ function SendModal({ onClose }) {
5631
5824
  const hash = transaction.step === "success" ? transaction.hash : null;
5632
5825
  const buildData = "buildData" in transaction ? transaction.buildData : null;
5633
5826
  const explorerNetwork = buildData?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : buildData ? "public" : network === "testnet" ? "testnet" : "public";
5634
- const explorerUrl = !hash ? null : selectedChain === "SOLANA" ? `https://explorer.solana.com/tx/${hash}${explorerNetwork === "testnet" ? "?cluster=devnet" : ""}` : `https://stellar.expert/explorer/${explorerNetwork}/tx/${hash}`;
5827
+ 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}`;
5635
5828
  const IN_FLIGHT_STEPS3 = [
5636
5829
  "building",
5637
5830
  "signing",
@@ -5670,33 +5863,42 @@ function SendModal({ onClose }) {
5670
5863
  setFormError("Enter a destination address");
5671
5864
  return;
5672
5865
  }
5866
+ const parsedMemo = selectedChain === "STELLAR" ? parseMemo(memoType, memo) : void 0;
5867
+ if (typeof parsedMemo === "string") {
5868
+ setFormError(parsedMemo);
5869
+ return;
5870
+ }
5673
5871
  const isNativeAsset = selectedAsset.type === "native";
5674
5872
  if (isBaseUnitChain && !isNativeAsset && (!selectedAsset.issuer || selectedAsset.decimals === void 0)) {
5675
- setFormError("This token is missing its mint or decimals and cannot be sent.");
5873
+ setFormError("This token is missing its contract or decimals and cannot be sent.");
5676
5874
  return;
5677
5875
  }
5678
5876
  let sendAmount = amount;
5679
5877
  if (isBaseUnitChain) {
5680
5878
  try {
5681
- sendAmount = core.toBaseUnits(amount, selectedAsset.decimals ?? 9);
5879
+ sendAmount = core.toBaseUnits(amount, selectedAsset.decimals ?? nativeDecimals);
5682
5880
  } catch (e) {
5683
5881
  setFormError(e instanceof Error ? e.message : "Invalid amount");
5684
5882
  return;
5685
5883
  }
5686
5884
  }
5687
5885
  setStep("tx");
5688
- if (selectedChain === "SOLANA") {
5886
+ if (selectedChain === "SOLANA" || selectedChain === "POLYGON") {
5689
5887
  await sendPayment({
5690
- chain: "SOLANA",
5888
+ chain: selectedChain,
5691
5889
  destination: destination.trim(),
5692
5890
  amount: sendAmount,
5693
- // Native SOL carries no mint; an SPL token's mint rides in `issuer`,
5694
- // which the guard above proved is present.
5891
+ // A native coin carries no token id; an SPL mint or ERC-20 contract rides
5892
+ // in `issuer`, which the guard above proved is present.
5695
5893
  ...isNativeAsset ? {} : { mint: selectedAsset.issuer }
5696
5894
  });
5697
5895
  return;
5698
5896
  }
5699
- await buildTx("payment", { destination: destination.trim(), amount, asset: assetParam(selectedAsset) });
5897
+ await buildTx(
5898
+ "payment",
5899
+ { destination: destination.trim(), amount, asset: assetParam(selectedAsset) },
5900
+ parsedMemo ? { memo: parsedMemo } : void 0
5901
+ );
5700
5902
  }
5701
5903
  function handleSignAndSend() {
5702
5904
  if (transaction.step === "built") {
@@ -5781,6 +5983,10 @@ function SendModal({ onClose }) {
5781
5983
  onMax: handleMax,
5782
5984
  onPaste: handlePaste,
5783
5985
  onDestinationChange: setDestination,
5986
+ memo,
5987
+ memoType,
5988
+ onMemoChange: setMemo,
5989
+ onMemoTypeChange: setMemoType,
5784
5990
  onSubmit: () => void handleSubmit(),
5785
5991
  onSignAndSend: handleSignAndSend,
5786
5992
  onToggleXdr: () => setShowXdr((v) => !v),
@@ -6188,7 +6394,7 @@ function SwapModalTemplate({
6188
6394
  onDone
6189
6395
  }
6190
6396
  ),
6191
- /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, { shield: true })
6397
+ /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
6192
6398
  ]
6193
6399
  }
6194
6400
  );
@@ -7017,7 +7223,8 @@ function groupPan(pan) {
7017
7223
  }
7018
7224
  var CARD_ERROR_COPY = {
7019
7225
  SDK_CARDS_PROVIDER_ERROR: "The card provider is not responding right now. Please try again in a few minutes.",
7020
- SDK_CARDS_IP_NOT_SUPPORTED: "The card provider cannot accept your current connection (IPv6). Please try again from another network, for example Wi-Fi."
7226
+ SDK_CARDS_IP_NOT_SUPPORTED: "The card provider cannot accept your current connection (IPv6). Please try again from another network, for example Wi-Fi.",
7227
+ SDK_CARDS_PROVIDER_USER_TAKEN: "This email is already registered with the card provider through another app. Use a different email to get a card here."
7021
7228
  };
7022
7229
  function errorText(e, fallback) {
7023
7230
  if (core.isPollarApiError(e)) {
@@ -7933,6 +8140,362 @@ function SessionsModal({ onClose }) {
7933
8140
  }
7934
8141
  ) });
7935
8142
  }
8143
+ function useCosign() {
8144
+ const { getClient, isAuthenticated } = usePollar();
8145
+ const [state, setState] = react.useState({ pending: [] });
8146
+ const [loaded, setLoaded] = react.useState(false);
8147
+ react.useEffect(() => getClient().onCosignStateChange(setState), [getClient]);
8148
+ const refresh = react.useCallback(async () => {
8149
+ if (!isAuthenticated) return;
8150
+ try {
8151
+ await getClient().cosign.pending();
8152
+ } finally {
8153
+ setLoaded(true);
8154
+ }
8155
+ }, [getClient, isAuthenticated]);
8156
+ react.useEffect(() => {
8157
+ void refresh();
8158
+ }, [refresh]);
8159
+ return {
8160
+ pending: state.pending,
8161
+ ...state.lastResolved ? { lastResolved: state.lastResolved } : {},
8162
+ loaded,
8163
+ refresh,
8164
+ approve: react.useCallback((request) => getClient().cosign.approve(request), [getClient]),
8165
+ reject: react.useCallback((request) => getClient().cosign.reject(request), [getClient]),
8166
+ verify: react.useCallback((request) => getClient().cosign.verify(request), [getClient]),
8167
+ inspectQuorum: react.useCallback(() => getClient().cosign.inspectQuorum(), [getClient]),
8168
+ devices: react.useCallback(() => getClient().cosign.devices(), [getClient]),
8169
+ revokeDevice: react.useCallback(
8170
+ (deviceId, options) => getClient().cosign.revokeDevice(deviceId, options),
8171
+ [getClient]
8172
+ )
8173
+ };
8174
+ }
8175
+ var OPERATION_LABELS = {
8176
+ payment: "Send",
8177
+ path_payment_strict_send: "Swap",
8178
+ change_trust: "Add asset",
8179
+ create_account: "Create account",
8180
+ invoke_contract: "Contract call",
8181
+ manage_data: "Manage data"
8182
+ };
8183
+ function labelOf(request) {
8184
+ const op = request.operation ?? "";
8185
+ return OPERATION_LABELS[op] ?? (op ? op.replace(/_/g, " ") : "Transaction");
8186
+ }
8187
+ function expiresIn(request) {
8188
+ const ms = new Date(request.expiresAt).getTime() - Date.now();
8189
+ if (!Number.isFinite(ms) || ms <= 0) return "expired";
8190
+ const h = Math.floor(ms / 36e5);
8191
+ const m = Math.floor(ms % 36e5 / 6e4);
8192
+ return h > 0 ? `${h}h ${m}m` : `${m}m`;
8193
+ }
8194
+ function detailRows(request) {
8195
+ const details = request.details ?? {};
8196
+ const rows = [];
8197
+ const push = (label, value) => {
8198
+ if (value === void 0 || value === null || value === "") return;
8199
+ rows.push([
8200
+ label,
8201
+ typeof value === "string" && value.length > 24 && /^[GC][A-Z2-7]{55}$/.test(value) ? cropAddress(value) : String(value)
8202
+ ]);
8203
+ };
8204
+ push("Destination", details.destination);
8205
+ push("Amount", details.amount);
8206
+ push("Asset", details.asset ?? details.assetCode);
8207
+ push("Network", request.network);
8208
+ return rows;
8209
+ }
8210
+ function CloseIcon2() {
8211
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m3 3 8 8M11 3l-8 8", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
8212
+ }
8213
+ function CosignModalTemplate({
8214
+ theme,
8215
+ accentColor,
8216
+ styleOverrides,
8217
+ pending,
8218
+ current,
8219
+ verification,
8220
+ busy,
8221
+ error,
8222
+ approveBlocked = false,
8223
+ lastResolved,
8224
+ explorerUrl,
8225
+ onSelect,
8226
+ onApprove,
8227
+ onReject,
8228
+ onClose
8229
+ }) {
8230
+ const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
8231
+ const verified = verification?.ok === true;
8232
+ const canVote = !!current && verified && !busy && !approveBlocked;
8233
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8234
+ "div",
8235
+ {
8236
+ className: "pollar-modal-card pollar-cosign-modal",
8237
+ "data-theme": theme,
8238
+ style: cssVars,
8239
+ onClick: (e) => e.stopPropagation(),
8240
+ children: [
8241
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
8242
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Confirm with your device" }),
8243
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", title: "Close", children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon2, {}) }) })
8244
+ ] }),
8245
+ pending.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-cosign-empty", children: lastResolved ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8246
+ 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: [
8247
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
8248
+ /* @__PURE__ */ jsxRuntime.jsx(
8249
+ "path",
8250
+ {
8251
+ d: "M3.5 7l2.5 2.5 4.5-5",
8252
+ stroke: "white",
8253
+ strokeWidth: "1.2",
8254
+ strokeLinecap: "round",
8255
+ strokeLinejoin: "round"
8256
+ }
8257
+ )
8258
+ ] }),
8259
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-empty-title", children: lastResolved.status === "APPROVED" ? "Approved" : lastResolved.status === "REJECTED" ? "Rejected" : lastResolved.status.toLowerCase() }),
8260
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: lastResolved.submit?.hash ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8261
+ "Sent. Transaction",
8262
+ " ",
8263
+ 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)
8264
+ ] }) : lastResolved.signedXdr ? "Signed. The app will send it." : "Nothing was signed." })
8265
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: "Nothing waits for your approval." }) }),
8266
+ pending.length > 1 && /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "pollar-cosign-list", children: pending.map((r) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsxs(
8267
+ "button",
8268
+ {
8269
+ type: "button",
8270
+ className: `pollar-cosign-item${current?.id === r.id ? " pollar-cosign-item-active" : ""}`,
8271
+ onClick: () => onSelect(r),
8272
+ children: [
8273
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: labelOf(r) }),
8274
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-cosign-muted", children: expiresIn(r) })
8275
+ ]
8276
+ }
8277
+ ) }, r.id)) }),
8278
+ current && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-detail", children: [
8279
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-detail-title", children: labelOf(current) }),
8280
+ current.summary && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: current.summary }),
8281
+ /* @__PURE__ */ jsxRuntime.jsx(GroupSteps, { request: current }),
8282
+ /* @__PURE__ */ jsxRuntime.jsxs("dl", { className: "pollar-cosign-rows", children: [
8283
+ detailRows(current).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-row", children: [
8284
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: k }),
8285
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: v })
8286
+ ] }, k)),
8287
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-row", children: [
8288
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: "Expires in" }),
8289
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: expiresIn(current) })
8290
+ ] })
8291
+ ] }),
8292
+ /* @__PURE__ */ jsxRuntime.jsxs(
8293
+ "div",
8294
+ {
8295
+ className: `pollar-cosign-verify pollar-cosign-verify-${verification ? verification.ok ? "ok" : "bad" : "pending"}`,
8296
+ children: [
8297
+ !verification && "Checking the transaction against Turnkey...",
8298
+ verification?.ok && "Verified: this is exactly what will be signed.",
8299
+ verification && !verification.ok && `Not verified: ${verification.reason}`
8300
+ ]
8301
+ }
8302
+ ),
8303
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-cosign-error", children: error }),
8304
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-actions", children: [
8305
+ /* @__PURE__ */ jsxRuntime.jsx(
8306
+ "button",
8307
+ {
8308
+ type: "button",
8309
+ className: "pollar-cosign-btn pollar-cosign-btn-secondary",
8310
+ disabled: !!busy,
8311
+ onClick: () => onReject(current),
8312
+ children: busy === "rejecting" ? "Rejecting..." : "Reject"
8313
+ }
8314
+ ),
8315
+ /* @__PURE__ */ jsxRuntime.jsx(
8316
+ "button",
8317
+ {
8318
+ type: "button",
8319
+ className: "pollar-cosign-btn pollar-cosign-btn-primary",
8320
+ disabled: !canVote,
8321
+ onClick: () => onApprove(current),
8322
+ children: busy === "approving" ? "Approving..." : "Approve"
8323
+ }
8324
+ )
8325
+ ] })
8326
+ ] }),
8327
+ /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
8328
+ ]
8329
+ }
8330
+ );
8331
+ }
8332
+ function GroupSteps({ request }) {
8333
+ const group = core.cosignGroupOf(request);
8334
+ if (!group || group.steps.length < 2) return null;
8335
+ const stepKey = core.cosignStepKeyOf(request);
8336
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-group", children: [
8337
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-group-title", children: group.title }),
8338
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: "Approving covers these steps; each one is checked before it is signed." }),
8339
+ /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "pollar-cosign-group-steps", children: group.steps.map((step) => {
8340
+ const isThis = stepKey !== null && core.stepInGroup({ steps: [step] }, stepKey);
8341
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: isThis ? "pollar-cosign-group-step-current" : void 0, children: [
8342
+ step.label,
8343
+ isThis && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-cosign-muted", children: " (this one)" })
8344
+ ] }, step.key);
8345
+ }) })
8346
+ ] });
8347
+ }
8348
+ function CosignModal({ onClose }) {
8349
+ const { getClient, styles, network } = usePollar();
8350
+ const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
8351
+ const { pending, lastResolved, approve, reject, verify, inspectQuorum } = useCosign();
8352
+ const [selectedId, setSelectedId] = react.useState(null);
8353
+ const [verification, setVerification] = react.useState(null);
8354
+ const [busy, setBusy] = react.useState(null);
8355
+ const [error, setError] = react.useState(null);
8356
+ const [approveFailedFor, setApproveFailedFor] = react.useState(null);
8357
+ const [quorumFailure, setQuorumFailure] = react.useState(null);
8358
+ react.useEffect(() => {
8359
+ let cancelled = false;
8360
+ inspectQuorum().then((q) => {
8361
+ if (!cancelled && !q.ok) setQuorumFailure(q.reason);
8362
+ }).catch(() => void 0);
8363
+ return () => {
8364
+ cancelled = true;
8365
+ };
8366
+ }, [inspectQuorum]);
8367
+ const current = pending.find((r) => r.id === selectedId) ?? pending[0] ?? null;
8368
+ const currentRef = react.useRef(current);
8369
+ currentRef.current = current;
8370
+ const currentId = current?.id ?? null;
8371
+ react.useEffect(() => {
8372
+ const request = currentRef.current;
8373
+ if (!request) return;
8374
+ setVerification(null);
8375
+ setError(null);
8376
+ setApproveFailedFor(null);
8377
+ let cancelled = false;
8378
+ verify(request).then((v) => {
8379
+ if (!cancelled) setVerification(v);
8380
+ }).catch((err) => {
8381
+ if (!cancelled) setVerification({ ok: false, reason: err instanceof Error ? err.message : String(err) });
8382
+ });
8383
+ return () => {
8384
+ cancelled = true;
8385
+ };
8386
+ }, [currentId, verify]);
8387
+ const onCloseRef = react.useRef(onClose);
8388
+ onCloseRef.current = onClose;
8389
+ react.useEffect(() => {
8390
+ return getClient().onAuthStateChange((authState) => {
8391
+ if (authState.step === "idle") onCloseRef.current();
8392
+ });
8393
+ }, [getClient]);
8394
+ const run = react.useCallback(
8395
+ async (kind, request, action) => {
8396
+ setBusy(kind);
8397
+ setError(null);
8398
+ try {
8399
+ await action(request);
8400
+ } catch (err) {
8401
+ setError(core.transactionErrorMessage(core.isPollarApiError(err) ? err.code : null, err instanceof Error ? err.message : null));
8402
+ if (kind === "approving") setApproveFailedFor(request.id);
8403
+ } finally {
8404
+ setBusy(null);
8405
+ }
8406
+ },
8407
+ []
8408
+ );
8409
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsx(
8410
+ CosignModalTemplate,
8411
+ {
8412
+ theme,
8413
+ accentColor,
8414
+ styleOverrides,
8415
+ pending,
8416
+ current,
8417
+ verification: current ? quorumFailure ? { ok: false, reason: quorumFailure } : verification : null,
8418
+ busy,
8419
+ error,
8420
+ approveBlocked: !!current && approveFailedFor === current.id,
8421
+ ...lastResolved ? { lastResolved } : {},
8422
+ explorerUrl: lastResolved?.submit?.hash ? explorerTxUrl(lastResolved.network, lastResolved.submit.hash, network) : null,
8423
+ onSelect: (r) => setSelectedId(r.id),
8424
+ onApprove: (r) => void run("approving", r, approve),
8425
+ onReject: (r) => void run("rejecting", r, reject),
8426
+ onClose
8427
+ }
8428
+ ) });
8429
+ }
8430
+ var OPERATION_LABELS2 = {
8431
+ payment: "Send",
8432
+ path_payment_strict_send: "Swap",
8433
+ change_trust: "Add asset",
8434
+ create_account: "Create account",
8435
+ invoke_contract: "Contract call",
8436
+ manage_data: "Manage data"
8437
+ };
8438
+ function labelOf2(confirmation) {
8439
+ const op = confirmation.operation ?? "";
8440
+ return OPERATION_LABELS2[op] ?? (op ? op.replace(/_/g, " ") : "Transaction");
8441
+ }
8442
+ function detailRows2(confirmation) {
8443
+ const details = confirmation.details ?? {};
8444
+ const rows = [];
8445
+ const push = (label, value) => {
8446
+ if (value === void 0 || value === null || value === "") return;
8447
+ const text = typeof value === "object" ? JSON.stringify(value) : String(value);
8448
+ rows.push([label, /^[GC][A-Z2-7]{55}$/.test(text) ? cropAddress(text) : text]);
8449
+ };
8450
+ push("Destination", details.destination);
8451
+ push("Amount", details.amount);
8452
+ push("Asset", details.asset ?? details.assetCode ?? details.mint);
8453
+ push("Network", confirmation.network);
8454
+ return rows;
8455
+ }
8456
+ function CloseIcon3() {
8457
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m3 3 8 8M11 3l-8 8", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
8458
+ }
8459
+ function ConfirmModal({ confirmation }) {
8460
+ const { getClient, styles } = usePollar();
8461
+ const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
8462
+ const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
8463
+ const rejectRef = react.useRef(confirmation.reject);
8464
+ rejectRef.current = confirmation.reject;
8465
+ react.useEffect(() => {
8466
+ return getClient().onAuthStateChange((authState) => {
8467
+ if (authState.step === "idle") rejectRef.current();
8468
+ });
8469
+ }, [getClient]);
8470
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: confirmation.reject, children: /* @__PURE__ */ jsxRuntime.jsxs(
8471
+ "div",
8472
+ {
8473
+ className: "pollar-modal-card pollar-cosign-modal",
8474
+ "data-theme": theme,
8475
+ style: cssVars,
8476
+ onClick: (e) => e.stopPropagation(),
8477
+ children: [
8478
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-modal-header", children: [
8479
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "pollar-modal-title", children: "Confirm transaction" }),
8480
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-modal-close", onClick: confirmation.reject, "aria-label": "Close", title: "Close", children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon3, {}) }) })
8481
+ ] }),
8482
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-detail", children: [
8483
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-detail-title", children: labelOf2(confirmation) }),
8484
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "pollar-cosign-muted", children: "The app asks you to sign this transaction with your wallet." }),
8485
+ /* @__PURE__ */ jsxRuntime.jsx("dl", { className: "pollar-cosign-rows", children: detailRows2(confirmation).map(([k, v]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-row", children: [
8486
+ /* @__PURE__ */ jsxRuntime.jsx("dt", { children: k }),
8487
+ /* @__PURE__ */ jsxRuntime.jsx("dd", { children: v })
8488
+ ] }, k)) }),
8489
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-cosign-actions", children: [
8490
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-cosign-btn pollar-cosign-btn-secondary", onClick: confirmation.reject, children: "Cancel" }),
8491
+ /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "pollar-cosign-btn pollar-cosign-btn-primary", onClick: confirmation.confirm, children: "Confirm" })
8492
+ ] })
8493
+ ] }),
8494
+ /* @__PURE__ */ jsxRuntime.jsx(PollarModalFooter, {})
8495
+ ]
8496
+ }
8497
+ ) });
8498
+ }
7936
8499
  function TransactionModalTemplate({
7937
8500
  theme,
7938
8501
  accentColor,
@@ -8042,12 +8605,6 @@ function TransactionModal({ onClose }) {
8042
8605
  ) });
8043
8606
  }
8044
8607
  var PAGE_SIZE = 10;
8045
- function explorerUrlFor(chain, hash, network) {
8046
- if (chain === "SOLANA") {
8047
- return `https://explorer.solana.com/tx/${hash}${network === "testnet" ? "?cluster=devnet" : ""}`;
8048
- }
8049
- return `https://stellar.expert/explorer/${network === "testnet" ? "testnet" : "public"}/tx/${hash}`;
8050
- }
8051
8608
  function StatusBadge({ status }) {
8052
8609
  return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-hist-item-badge", "data-status": status, children: status });
8053
8610
  }
@@ -8164,7 +8721,7 @@ function TxHistoryModalTemplate({
8164
8721
  txHistory.step === "loaded" && records.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-modal-empty", children: "No transactions yet." }),
8165
8722
  records.map((record) => {
8166
8723
  const hash = typeof record.hash === "string" && record.hash.length > 0 ? record.hash : void 0;
8167
- const explorerUrl = hash ? explorerUrlFor(record.chain, hash, record.network) : void 0;
8724
+ const explorerUrl = hash ? explorerTxUrl(record.chain, hash, record.network) : void 0;
8168
8725
  const asset = typeof record.details?.asset === "string" ? record.details.asset : void 0;
8169
8726
  const colon = asset ? asset.indexOf(":") : -1;
8170
8727
  const trustline = record.operation === "change_trust" && asset && colon > 0 ? {
@@ -8573,6 +9130,9 @@ function PollarProvider({
8573
9130
  const [transaction, setTransaction] = react.useState({ step: "idle" });
8574
9131
  const [txHistory, setTxHistory] = react.useState({ step: "idle" });
8575
9132
  const [sessions, setSessions] = react.useState({ step: "idle" });
9133
+ const [cosign, setCosign] = react.useState({ pending: [] });
9134
+ const [confirmations, setConfirmations] = react.useState([]);
9135
+ const firstConfirmation = confirmations[0] ?? null;
8576
9136
  const [walletBalance, setWalletBalance] = react.useState({ step: "idle" });
8577
9137
  const [enabledAssets, setEnabledAssets] = react.useState({ step: "idle" });
8578
9138
  const [resolvedConfig, setResolvedConfig] = react.useState(() => appConfigProp ?? DEFAULT_APP_CONFIG);
@@ -8590,6 +9150,12 @@ function PollarProvider({
8590
9150
  react.useEffect(() => {
8591
9151
  return pollarClient.onTxHistoryStateChange(setTxHistory);
8592
9152
  }, [pollarClient]);
9153
+ react.useEffect(() => {
9154
+ return pollarClient.onCosignStateChange(setCosign);
9155
+ }, [pollarClient]);
9156
+ react.useEffect(() => {
9157
+ return pollarClient.onConfirmationRequest(setConfirmations);
9158
+ }, [pollarClient]);
8593
9159
  react.useEffect(() => {
8594
9160
  return pollarClient.onSessionsStateChange(setSessions);
8595
9161
  }, [pollarClient]);
@@ -8633,7 +9199,7 @@ function PollarProvider({
8633
9199
  triggered = false;
8634
9200
  return;
8635
9201
  }
8636
- if (triggered || sessionRef.current?.wallet?.address) return;
9202
+ if (triggered || sessionRef.current) return;
8637
9203
  triggered = true;
8638
9204
  pollarClient.login({ provider: id });
8639
9205
  })
@@ -8690,6 +9256,12 @@ function PollarProvider({
8690
9256
  const [cardModalKey, setCardModalKey] = react.useState(0);
8691
9257
  const [receiveModalOpen, setReceiveModalOpen] = react.useState(false);
8692
9258
  const [sessionsModalOpen, setSessionsModalOpen] = react.useState(false);
9259
+ const [cosignModalOpen, setCosignModalOpen] = react.useState(false);
9260
+ const cosignPendingCount = react.useRef(0);
9261
+ react.useEffect(() => {
9262
+ if (cosign.pending.length > cosignPendingCount.current) setCosignModalOpen(true);
9263
+ cosignPendingCount.current = cosign.pending.length;
9264
+ }, [cosign.pending.length]);
8693
9265
  const [distributionRulesModalOpen, setDistributionRulesModalOpen] = react.useState(false);
8694
9266
  react.useEffect(
8695
9267
  () => pollarClient.onAuthStateChange((authState) => {
@@ -8706,12 +9278,14 @@ function PollarProvider({
8706
9278
  setCardModalOpen(false);
8707
9279
  setReceiveModalOpen(false);
8708
9280
  setSessionsModalOpen(false);
9281
+ setCosignModalOpen(false);
8709
9282
  setDistributionRulesModalOpen(false);
8710
9283
  }),
8711
9284
  [pollarClient]
8712
9285
  );
8713
9286
  const walletAddress = sessionState?.wallet?.address || "";
8714
9287
  const walletProvisioning = sessionState?.wallet?.provisioning;
9288
+ const hasSession = sessionState !== null;
8715
9289
  const getClient = react.useCallback(() => pollarClient, [pollarClient]);
8716
9290
  const refreshWalletBalance = react.useCallback(() => pollarClient.refreshBalance(), [pollarClient, walletAddress]);
8717
9291
  const refreshAssets = react.useCallback(() => pollarClient.refreshAssets(), [pollarClient, walletAddress]);
@@ -8721,7 +9295,9 @@ function PollarProvider({
8721
9295
  // session
8722
9296
  wallet: pollarClient.getWallet(),
8723
9297
  wallets: pollarClient.getWallets(),
8724
- isAuthenticated: !!walletAddress,
9298
+ isAuthenticated: hasSession,
9299
+ hasWallet: pollarClient.hasWallet(),
9300
+ createWallet: () => pollarClient.createWallet(),
8725
9301
  verified,
8726
9302
  // client
8727
9303
  getClient,
@@ -8787,6 +9363,10 @@ function PollarProvider({
8787
9363
  // sessions
8788
9364
  sessions,
8789
9365
  openSessionsModal: () => setSessionsModalOpen(true),
9366
+ // cosign
9367
+ cosign,
9368
+ openCosignModal: () => setCosignModalOpen(true),
9369
+ confirmations,
8790
9370
  // distribution
8791
9371
  openDistributionRulesModal: () => setDistributionRulesModalOpen(true),
8792
9372
  // network
@@ -8809,12 +9389,15 @@ function PollarProvider({
8809
9389
  }, [
8810
9390
  walletAddress,
8811
9391
  walletProvisioning,
9392
+ hasSession,
8812
9393
  verified,
8813
9394
  pollarClient,
8814
9395
  getClient,
8815
9396
  transaction,
8816
9397
  txHistory,
8817
9398
  sessions,
9399
+ cosign,
9400
+ confirmations,
8818
9401
  walletBalance,
8819
9402
  refreshWalletBalance,
8820
9403
  enabledAssets,
@@ -8862,6 +9445,8 @@ function PollarProvider({
8862
9445
  /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setCardModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(CardModal, { onClose: () => setCardModalOpen(false) }) }, `${cardModalKey}:${walletAddress}`),
8863
9446
  receiveModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setReceiveModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(ReceiveModal, { onClose: () => setReceiveModalOpen(false) }) }),
8864
9447
  sessionsModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setSessionsModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(SessionsModal, { onClose: () => setSessionsModalOpen(false) }) }),
9448
+ cosignModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setCosignModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(CosignModal, { onClose: () => setCosignModalOpen(false) }) }),
9449
+ firstConfirmation && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: firstConfirmation.reject, children: /* @__PURE__ */ jsxRuntime.jsx(ConfirmModal, { confirmation: firstConfirmation }, firstConfirmation.id) }),
8865
9450
  distributionRulesModalOpen && /* @__PURE__ */ jsxRuntime.jsx(ModalErrorBoundary, { onClose: () => setDistributionRulesModalOpen(false), children: /* @__PURE__ */ jsxRuntime.jsx(DistributionRulesModal, { onClose: () => setDistributionRulesModalOpen(false) }) })
8866
9451
  ] });
8867
9452
  }
@@ -8924,8 +9509,54 @@ function WalletButtonTemplate({
8924
9509
  onRamp,
8925
9510
  onDistributionRules,
8926
9511
  onLogout,
8927
- onLogin
9512
+ onLogin,
9513
+ signedIn,
9514
+ creatingWallet,
9515
+ createWalletError,
9516
+ onCreateWallet
8928
9517
  }) {
9518
+ if (!walletAddress && signedIn) {
9519
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-wrapper", ref: wrapperRef, children: [
9520
+ /* @__PURE__ */ jsxRuntime.jsxs("button", { className: "pollar-wallet-btn", style: { backgroundColor: accentColor }, onClick: onToggleOpen, children: [
9521
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pollar-wallet-btn-label", children: onCreateWallet ? "No wallet" : "Signed in" }),
9522
+ /* @__PURE__ */ jsxRuntime.jsx(
9523
+ "svg",
9524
+ {
9525
+ className: `pollar-wallet-chevron${open ? " pollar-open" : ""}`,
9526
+ viewBox: "0 0 12 12",
9527
+ fill: "none",
9528
+ stroke: "currentColor",
9529
+ strokeWidth: "2",
9530
+ strokeLinecap: "round",
9531
+ strokeLinejoin: "round",
9532
+ children: /* @__PURE__ */ jsxRuntime.jsx("polyline", { points: "2,4 6,8 10,4" })
9533
+ }
9534
+ )
9535
+ ] }),
9536
+ open && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pollar-wallet-dropdown", style: { backgroundColor: dropdownBg, borderColor: dropdownBorder }, children: [
9537
+ createWalletError && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9538
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-notice", style: { color: itemColor }, role: "status", children: createWalletError }),
9539
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
9540
+ ] }),
9541
+ onCreateWallet && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
9542
+ /* @__PURE__ */ jsxRuntime.jsx(
9543
+ "button",
9544
+ {
9545
+ className: "pollar-wallet-dropdown-item",
9546
+ style: { color: itemColor },
9547
+ onClick: onCreateWallet,
9548
+ disabled: creatingWallet,
9549
+ children: creatingWallet ? "Creating wallet\u2026" : "Create wallet"
9550
+ }
9551
+ ),
9552
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" })
9553
+ ] }),
9554
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-wallet-dropdown-item", style: { color: itemColor }, onClick: onSessions, children: "Active sessions" }),
9555
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pollar-wallet-dropdown-divider" }),
9556
+ /* @__PURE__ */ jsxRuntime.jsx("button", { className: "pollar-wallet-dropdown-item pollar-danger", onClick: onLogout, children: "Log out" })
9557
+ ] })
9558
+ ] });
9559
+ }
8929
9560
  if (!walletAddress) {
8930
9561
  return /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "pollar-wallet-login-btn", style: { backgroundColor: accentColor }, onClick: onLogin, children: [
8931
9562
  /* @__PURE__ */ jsxRuntime.jsx(ButtonLogo, {}),
@@ -9246,7 +9877,10 @@ function WalletButton() {
9246
9877
  openKycModal,
9247
9878
  openRampModal,
9248
9879
  openDistributionRulesModal,
9249
- tx: transaction
9880
+ tx: transaction,
9881
+ isAuthenticated,
9882
+ createWallet,
9883
+ appConfig
9250
9884
  } = usePollar();
9251
9885
  const { primaryChain, primaryAddress } = useChains();
9252
9886
  const walletAddress = primaryAddress || (wallet?.address ?? "");
@@ -9254,6 +9888,8 @@ function WalletButton() {
9254
9888
  const [copied, setCopied] = react.useState(false);
9255
9889
  const [creating, setCreating] = react.useState(false);
9256
9890
  const [created, setCreated] = react.useState(false);
9891
+ const [creatingWallet, setCreatingWallet] = react.useState(false);
9892
+ const [createWalletError, setCreateWalletError] = react.useState(null);
9257
9893
  const wrapperRef = react.useRef(null);
9258
9894
  const copyTimerRef = react.useRef(null);
9259
9895
  const isInProgress = transaction.step === "building" || transaction.step === "signing";
@@ -9307,6 +9943,21 @@ function WalletButton() {
9307
9943
  setCreating(false);
9308
9944
  }
9309
9945
  }
9946
+ async function handleCreateWallet() {
9947
+ if (creatingWallet) return;
9948
+ setCreatingWallet(true);
9949
+ setCreateWalletError(null);
9950
+ try {
9951
+ await createWallet();
9952
+ setOpen(false);
9953
+ } catch (err) {
9954
+ setCreateWalletError(
9955
+ core.isPollarApiError(err) && err.code === "SDK_WALLET_PROVISIONING_DISABLED" ? "This app does not create wallets." : "Could not create the wallet. Try again."
9956
+ );
9957
+ } finally {
9958
+ setCreatingWallet(false);
9959
+ }
9960
+ }
9310
9961
  function handleWalletBalance() {
9311
9962
  setOpen(false);
9312
9963
  openWalletBalanceModal();
@@ -9352,6 +10003,10 @@ function WalletButton() {
9352
10003
  wrapperRef,
9353
10004
  isInProgress,
9354
10005
  showCreateAccount: canCreateAccount,
10006
+ signedIn: isAuthenticated,
10007
+ creatingWallet,
10008
+ createWalletError,
10009
+ ...appConfig.application?.walletProvisioning === "NONE" ? {} : { onCreateWallet: handleCreateWallet },
9355
10010
  notReadyReason,
9356
10011
  creatingAccount: creating,
9357
10012
  onToggleOpen: () => setOpen((v) => !v),
@@ -9373,6 +10028,8 @@ function WalletButton() {
9373
10028
 
9374
10029
  exports.CardModal = CardModal;
9375
10030
  exports.ChainSelect = ChainSelect;
10031
+ exports.CosignModal = CosignModal;
10032
+ exports.CosignModalTemplate = CosignModalTemplate;
9376
10033
  exports.DistributionRulesModal = DistributionRulesModal;
9377
10034
  exports.DistributionRulesModalTemplate = DistributionRulesModalTemplate;
9378
10035
  exports.EarnModal = EarnModal;
@@ -9414,6 +10071,7 @@ exports.modalChrome = modalChrome;
9414
10071
  exports.readableTextOn = readableTextOn;
9415
10072
  exports.resolveChain = resolveChain;
9416
10073
  exports.useChains = useChains;
10074
+ exports.useCosign = useCosign;
9417
10075
  exports.usePollar = usePollar;
9418
10076
  exports.walletNotReadyReason = walletNotReadyReason;
9419
10077
  //# sourceMappingURL=index.js.map