@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.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { AUTH_ERROR_CODES, WalletType, isPollarClient, PollarClient, isInteractiveAuthAdapter, isPollarApiError, toBaseUnits } from '@pollar/core';
2
+ import { AUTH_ERROR_CODES, transactionErrorMessage, WalletType, cosignGroupOf, cosignStepKeyOf, stepInGroup, isPollarApiError, isPollarClient, PollarClient, isInteractiveAuthAdapter, toBaseUnits } from '@pollar/core';
3
3
  import { forwardRef, createContext, useState, useCallback, useEffect, useMemo, useRef, useContext, Component } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
  import { startAuthentication, startRegistration } from '@simplewebauthn/browser';
@@ -1000,6 +1000,10 @@ var require_QRCode = __commonJS({
1000
1000
 
1001
1001
  // src/constants.ts
1002
1002
  var LOGO_POLLAR = "https://pollar.xyz/assets/logo_pollar.png";
1003
+ var LOGO_POLLAR_WORDMARK_ON_LIGHT = "https://www.pollar.xyz/brandkit/pollar-logo-horizontal-on-light.png";
1004
+ var LOGO_POLLAR_WORDMARK_ON_DARK = "https://www.pollar.xyz/brandkit/pollar-logo-horizontal-on-dark.png";
1005
+ var LOGO_POLLAR_MARK_ON_LIGHT = "https://www.pollar.xyz/brandkit/pollar-mark-on-light.png";
1006
+ var LOGO_POLLAR_MARK_ON_DARK = "https://www.pollar.xyz/brandkit/pollar-mark-on-dark.png";
1003
1007
  var LOGO_FREIGHTER = "https://pollar.xyz/assets/logo_freighter.png";
1004
1008
  var LOGO_ALBEDO = "https://pollar.xyz/assets/logo_albedo.svg";
1005
1009
  var _modalLog = console;
@@ -1025,22 +1029,26 @@ var ModalErrorBoundary = class extends Component {
1025
1029
  return this.props.children;
1026
1030
  }
1027
1031
  };
1028
- var PollarModalFooter = ({ shield = false }) => {
1032
+ var PollarModalFooter = () => {
1029
1033
  return /* @__PURE__ */ jsxs("div", { className: "pollar-footer", children: [
1030
1034
  /* @__PURE__ */ jsx("span", { className: "pollar-footer-protected", children: "Protected by" }),
1031
- /* @__PURE__ */ jsxs("div", { className: "pollar-footer-brand", children: [
1032
- shield ? /* @__PURE__ */ jsxs("svg", { className: "pollar-footer-shield", width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", "aria-hidden": true, children: [
1033
- /* @__PURE__ */ 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)" }),
1034
- /* @__PURE__ */ jsx("path", { d: "m8.5 12 2.2 2.2 4.8-5", stroke: "white", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" })
1035
- ] }) : /* @__PURE__ */ jsx("img", { src: LOGO_POLLAR, alt: "Pollar", className: "pollar-footer-logo" }),
1036
- /* @__PURE__ */ jsx("span", { className: "pollar-footer-name", children: "Pollar" }),
1037
- /* @__PURE__ */ jsxs("span", { className: "pollar-footer-version", children: [
1038
- "v",
1039
- "0.11.4-rc.4"
1040
- ] })
1035
+ /* @__PURE__ */ jsx("img", { src: LOGO_POLLAR_WORDMARK_ON_LIGHT, alt: "Pollar", className: "pollar-footer-logo pollar-logo-on-light" }),
1036
+ /* @__PURE__ */ jsx("img", { src: LOGO_POLLAR_WORDMARK_ON_DARK, alt: "Pollar", className: "pollar-footer-logo pollar-logo-on-dark" }),
1037
+ /* @__PURE__ */ jsxs("span", { className: "pollar-footer-version", children: [
1038
+ "v",
1039
+ "0.11.5"
1041
1040
  ] })
1042
1041
  ] });
1043
1042
  };
1043
+ function explorerTxUrl(chain, hash, network) {
1044
+ if (chain === "SOLANA") {
1045
+ return `https://explorer.solana.com/tx/${hash}${network === "testnet" ? "?cluster=devnet" : ""}`;
1046
+ }
1047
+ if (chain === "POLYGON") {
1048
+ return `https://${network === "testnet" ? "amoy." : ""}polygonscan.com/tx/${hash}`;
1049
+ }
1050
+ return `https://stellar.expert/explorer/${network === "testnet" ? "testnet" : "public"}/tx/${hash}`;
1051
+ }
1044
1052
  function RefreshIcon({ spinning = false, className = "" }) {
1045
1053
  return /* @__PURE__ */ jsxs(
1046
1054
  "svg",
@@ -1232,6 +1240,8 @@ function buildModalCssVars(theme, accentColor, overrides = {}, variant = "compac
1232
1240
  "--pollar-error-border": isDark ? "#7f1d1d" : "#fecaca",
1233
1241
  "--pollar-error-text": isDark ? "#f87171" : "#dc2626",
1234
1242
  "--pollar-success-text": isDark ? "#4ade80" : "#16a34a",
1243
+ "--pollar-logo-on-light-display": isDark ? "none" : "block",
1244
+ "--pollar-logo-on-dark-display": isDark ? "block" : "none",
1235
1245
  "--pollar-modal-border-radius": px(overrides.modalBorderRadius, DEFAULT_MODAL_BORDER_RADIUS),
1236
1246
  "--pollar-buttons-border-radius": px(overrides.buttonBorderRadius, DEFAULT_BUTTON_BORDER_RADIUS),
1237
1247
  "--pollar-buttons-height": "44px",
@@ -2262,15 +2272,35 @@ function initialValues(fields, answers) {
2262
2272
  return values;
2263
2273
  }
2264
2274
  var DATE = /^\d{4}-\d{2}-\d{2}$/;
2275
+ function localFieldError(field, value) {
2276
+ if (typeof value !== "string" || !value.trim()) return null;
2277
+ const text = value.trim();
2278
+ const rules = field.validation ?? {};
2279
+ if (field.type === "number") {
2280
+ const number = Number(text);
2281
+ if (!Number.isFinite(number)) return "invalid_type";
2282
+ if (rules.min !== void 0 && number < rules.min) return "too_small";
2283
+ if (rules.max !== void 0 && number > rules.max) return "too_large";
2284
+ return null;
2285
+ }
2286
+ if (field.type === "date") {
2287
+ return DATE.test(text) && !Number.isNaN(Date.parse(`${text}T00:00:00Z`)) ? null : "invalid_format";
2288
+ }
2289
+ if (field.type === "select" || field.type === "multiselect" || field.type === "checkbox") return null;
2290
+ if (rules.maxLength !== void 0 && text.length > rules.maxLength) return "too_long";
2291
+ if (rules.pattern) {
2292
+ try {
2293
+ if (!new RegExp(rules.pattern).test(text)) return "pattern";
2294
+ } catch {
2295
+ }
2296
+ }
2297
+ return null;
2298
+ }
2265
2299
  function localFieldErrors(fields, values) {
2266
2300
  const errors = {};
2267
2301
  for (const field of fields) {
2268
- const value = values[field.key];
2269
- if (typeof value !== "string" || !value.trim()) continue;
2270
- if (field.type === "number" && !Number.isFinite(Number(value))) errors[field.key] = "invalid_type";
2271
- if (field.type === "date" && (!DATE.test(value.trim()) || Number.isNaN(Date.parse(`${value.trim()}T00:00:00Z`)))) {
2272
- errors[field.key] = "invalid_format";
2273
- }
2302
+ const error = localFieldError(field, values[field.key]);
2303
+ if (error) errors[field.key] = error;
2274
2304
  }
2275
2305
  return errors;
2276
2306
  }
@@ -2350,7 +2380,8 @@ function FieldInput({
2350
2380
  value,
2351
2381
  language,
2352
2382
  disabled,
2353
- onChange
2383
+ onChange,
2384
+ onBlur
2354
2385
  }) {
2355
2386
  const id = `pollar-form-${field.key}`;
2356
2387
  const text = typeof value === "string" ? value : "";
@@ -2384,7 +2415,8 @@ function FieldInput({
2384
2415
  value: text,
2385
2416
  disabled,
2386
2417
  maxLength: field.validation?.maxLength,
2387
- onChange: (e) => onChange(e.target.value)
2418
+ onChange: (e) => onChange(e.target.value),
2419
+ onBlur
2388
2420
  }
2389
2421
  );
2390
2422
  default:
@@ -2400,7 +2432,8 @@ function FieldInput({
2400
2432
  min: field.validation?.min,
2401
2433
  max: field.validation?.max,
2402
2434
  maxLength: field.validation?.maxLength,
2403
- onChange: (e) => onChange(e.target.value)
2435
+ onChange: (e) => onChange(e.target.value),
2436
+ onBlur
2404
2437
  }
2405
2438
  );
2406
2439
  }
@@ -2431,6 +2464,24 @@ function RequirementFormModal({ formId, progress, onClose, onSubmitted }) {
2431
2464
  setValues(initialValues(loaded.fields, loaded.answers));
2432
2465
  }).catch(() => mounted.current && setError(copy.loadError));
2433
2466
  }, [formId]);
2467
+ function recheck(field, value, onlyIfShown) {
2468
+ if (typeof value === "string" && !value.trim()) return;
2469
+ setFieldErrors((errors) => {
2470
+ if (onlyIfShown && !(field.key in errors)) return errors;
2471
+ const next = { ...errors };
2472
+ const error2 = localFieldError(field, value);
2473
+ if (error2) next[field.key] = error2;
2474
+ else delete next[field.key];
2475
+ return next;
2476
+ });
2477
+ }
2478
+ function change(field, value) {
2479
+ setValues((v) => ({ ...v, [field.key]: value }));
2480
+ recheck(field, value, true);
2481
+ }
2482
+ function blur(field) {
2483
+ recheck(field, values[field.key], false);
2484
+ }
2434
2485
  async function submit() {
2435
2486
  if (!form) return;
2436
2487
  setError(null);
@@ -2510,7 +2561,8 @@ function RequirementFormModal({ formId, progress, onClose, onSubmitted }) {
2510
2561
  value: values[field.key] ?? "",
2511
2562
  language,
2512
2563
  disabled: submitting,
2513
- onChange: (value) => setValues((v) => ({ ...v, [field.key]: value }))
2564
+ onChange: (value) => change(field, value),
2565
+ onBlur: () => blur(field)
2514
2566
  }
2515
2567
  )
2516
2568
  ] }),
@@ -3195,7 +3247,11 @@ function LoginModal({ onClose }) {
3195
3247
  const [email, setEmail] = useState("");
3196
3248
  const { getClient, styles, appConfig: config, configStatus, retryConfig } = usePollar();
3197
3249
  const [authState, setAuthState] = useState(() => getClient().getAuthState());
3198
- const walletAdapters = useMemo(() => getClient().listWalletAdapters(), [getClient]);
3250
+ const servedChains = config?.application?.chains;
3251
+ const walletAdapters = useMemo(
3252
+ () => getClient().listWalletAdapters().filter((a) => !servedChains || servedChains.includes(a.chain)),
3253
+ [getClient, servedChains]
3254
+ );
3199
3255
  const [codeInputKey, setCodeInputKey] = useState(0);
3200
3256
  const pendingEmail = useRef(null);
3201
3257
  const [interactiveAdapter, setInteractiveAdapter] = useState(null);
@@ -3480,6 +3536,8 @@ function placeholderFor(field, fields, values) {
3480
3536
  }
3481
3537
  return field.placeholder;
3482
3538
  }
3539
+ var CHAIN_NAME = { STELLAR: "Stellar", POLYGON: "Polygon", SOLANA: "Solana" };
3540
+ var EXPLORER_NAME = { STELLAR: "Stellar Expert", POLYGON: "Polygonscan", SOLANA: "Solana Explorer" };
3483
3541
  var LOADING_STEPS = ["Detecting your country\u2026", "Consulting providers\u2026", "Route found!"];
3484
3542
  function flagEmoji(code) {
3485
3543
  const cc = code.trim().toUpperCase();
@@ -3526,7 +3584,12 @@ function RampWidgetTemplate({
3526
3584
  onboardingStatus,
3527
3585
  kycJustApproved,
3528
3586
  stellarTxHash,
3587
+ txHash,
3588
+ txChain,
3529
3589
  explorerUrl,
3590
+ fundsInTransit = false,
3591
+ retrying = false,
3592
+ onRetryTransit,
3530
3593
  depositInstructions,
3531
3594
  canComplete,
3532
3595
  completing,
@@ -3548,6 +3611,8 @@ function RampWidgetTemplate({
3548
3611
  onRefresh,
3549
3612
  onClose
3550
3613
  }) {
3614
+ const settledHash = txHash ?? stellarTxHash;
3615
+ const chainName = CHAIN_NAME[txChain ?? "STELLAR"];
3551
3616
  const cssVars = buildModalCssVars(theme, accentColor, styleOverrides, "hero");
3552
3617
  const stepTitle = {
3553
3618
  input: direction === "onramp" ? "Buy crypto" : "Sell crypto",
@@ -3780,15 +3845,23 @@ function RampWidgetTemplate({
3780
3845
  txStatus !== "completed" && txStatus !== "failed" && /* @__PURE__ */ jsx("span", { className: "pollar-spinner pollar-spinner-sm", "aria-label": "Checking status" })
3781
3846
  ] })
3782
3847
  ] }),
3783
- stellarTxHash && /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-field", children: [
3784
- /* @__PURE__ */ jsx("span", { className: "pollar-ramp-payment-label", children: "Stellar tx" }),
3848
+ fundsInTransit && txStatus !== "completed" && txStatus !== "failed" && /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-field", children: [
3849
+ /* @__PURE__ */ jsx("span", { className: "pollar-ramp-payment-label", children: "Funds in transit" }),
3850
+ /* @__PURE__ */ jsx("p", { className: "pollar-ramp-payment-note", children: "Your money is safe in your own wallet, waiting for the next step of the transfer." }),
3851
+ onRetryTransit && /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-btn-secondary", onClick: onRetryTransit, disabled: retrying, children: retrying ? "Retrying..." : "Retry now" })
3852
+ ] }),
3853
+ settledHash && /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-field", children: [
3854
+ /* @__PURE__ */ jsxs("span", { className: "pollar-ramp-payment-label", children: [
3855
+ chainName,
3856
+ " tx"
3857
+ ] }),
3785
3858
  /* @__PURE__ */ jsxs("div", { className: "pollar-ramp-payment-value", style: { display: "flex", alignItems: "center", gap: 6 }, children: [
3786
3859
  /* @__PURE__ */ jsxs("code", { style: { flex: 1, wordBreak: "break-all" }, children: [
3787
- stellarTxHash.slice(0, 8),
3860
+ settledHash.slice(0, 8),
3788
3861
  "\u2026",
3789
- stellarTxHash.slice(-8)
3862
+ settledHash.slice(-8)
3790
3863
  ] }),
3791
- /* @__PURE__ */ jsx(CopyButton, { value: stellarTxHash, label: "Copy transaction hash" }),
3864
+ /* @__PURE__ */ jsx(CopyButton, { value: settledHash, label: "Copy transaction hash" }),
3792
3865
  explorerUrl && /* @__PURE__ */ jsx(
3793
3866
  "a",
3794
3867
  {
@@ -3796,8 +3869,8 @@ function RampWidgetTemplate({
3796
3869
  target: "_blank",
3797
3870
  rel: "noopener noreferrer",
3798
3871
  className: "pollar-copy-btn",
3799
- "aria-label": "View on Stellar Expert",
3800
- title: "View on Stellar Expert",
3872
+ "aria-label": `View on ${EXPLORER_NAME[txChain ?? "STELLAR"]}`,
3873
+ title: `View on ${EXPLORER_NAME[txChain ?? "STELLAR"]}`,
3801
3874
  children: /* @__PURE__ */ jsxs("svg", { width: "13", height: "13", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
3802
3875
  /* @__PURE__ */ jsx(
3803
3876
  "path",
@@ -3969,6 +4042,7 @@ var REGISTRATION_COPY = {
3969
4042
  incomplete: "Your registration with the provider did not finish. Register again to complete it.",
3970
4043
  providerDown: "The provider is not responding right now. Please try again in a few minutes.",
3971
4044
  ipNotSupported: "The provider cannot accept your current connection (IPv6). Please try again from another network, for example Wi-Fi.",
4045
+ emailTaken: "This email is already registered with the provider through another app. Use a different email to register here.",
3972
4046
  loadError: "Could not load the registration. Please try again.",
3973
4047
  submitError: "Could not register you. Please try again.",
3974
4048
  step: "Step {n} of {total}",
@@ -3988,6 +4062,7 @@ var REGISTRATION_COPY = {
3988
4062
  incomplete: "Tu registro con el proveedor no se complet\xF3. Reg\xEDstrate de nuevo para terminarlo.",
3989
4063
  providerDown: "El proveedor no responde en este momento. Intenta de nuevo en unos minutos.",
3990
4064
  ipNotSupported: "El proveedor no acepta tu conexi\xF3n actual (IPv6). Intenta desde otra red, por ejemplo Wi-Fi.",
4065
+ emailTaken: "Este email ya est\xE1 registrado con el proveedor desde otra app. Usa otro email para registrarte aqu\xED.",
3991
4066
  loadError: "No se pudo cargar el registro. Intenta de nuevo.",
3992
4067
  submitError: "No se pudo completar el registro. Intenta de nuevo.",
3993
4068
  step: "Paso {n} de {total}",
@@ -4310,6 +4385,7 @@ function ProviderRegistrationModal({
4310
4385
  } else if (code === "KYC_REGISTRATION_STEPS_PENDING") setError(copy.notReady);
4311
4386
  else if (code === "SDK_CARDS_PROVIDER_ERROR") setError(copy.providerDown);
4312
4387
  else if (code === "SDK_CARDS_IP_NOT_SUPPORTED") setError(copy.ipNotSupported);
4388
+ else if (code === "SDK_CARDS_PROVIDER_USER_TAKEN") setError(copy.emailTaken);
4313
4389
  else setError(copy.submitError);
4314
4390
  } finally {
4315
4391
  if (mounted.current) setSubmitting(false);
@@ -4438,6 +4514,13 @@ function rampErrorMessage(e, fallback) {
4438
4514
  }
4439
4515
  return RAMP_ERROR_MESSAGES[code] ?? (e instanceof Error ? e.message : fallback);
4440
4516
  }
4517
+ function explorerTxUrl2(chain, hash, network) {
4518
+ if (!hash) return null;
4519
+ const testnet = network === "testnet";
4520
+ if (chain === "SOLANA") return `https://explorer.solana.com/tx/${hash}${testnet ? "?cluster=devnet" : ""}`;
4521
+ if (chain === "POLYGON") return `https://${testnet ? "amoy." : ""}polygonscan.com/tx/${hash}`;
4522
+ return `https://stellar.expert/explorer/${testnet ? "testnet" : "public"}/tx/${hash}`;
4523
+ }
4441
4524
  function RampWidget({ onClose }) {
4442
4525
  const { getClient, signTx, wallet, styles, network } = usePollar();
4443
4526
  const walletAddress = wallet?.address ?? "";
@@ -4475,11 +4558,36 @@ function RampWidget({ onClose }) {
4475
4558
  const [onboardingStatus, setOnboardingStatus] = useState(void 0);
4476
4559
  const [txStatus, setTxStatus] = useState(null);
4477
4560
  const [stellarTxHash, setStellarTxHash] = useState(null);
4561
+ const [txHash, setTxHash] = useState(null);
4562
+ const [txChain, setTxChain] = useState(null);
4563
+ const [fundsInTransit, setFundsInTransit] = useState(false);
4564
+ const [retrying, setRetrying] = useState(false);
4478
4565
  const [depositInstructions, setDepositInstructions] = useState(null);
4479
4566
  const [completing, setCompleting] = useState(false);
4480
4567
  const [errorMsg, setErrorMsg] = useState(null);
4568
+ const signingRef = useRef(false);
4481
4569
  const directionRef = useRef(direction);
4482
4570
  directionRef.current = direction;
4571
+ function applySettlement(tx) {
4572
+ if (tx.stellarTxHash) setStellarTxHash(tx.stellarTxHash);
4573
+ if (tx.txHash) setTxHash(tx.txHash);
4574
+ if (tx.chain) setTxChain(tx.chain);
4575
+ setFundsInTransit(tx.fundsInTransit === true);
4576
+ }
4577
+ async function handleRetryTransit() {
4578
+ if (!txId || retrying) return;
4579
+ setRetrying(true);
4580
+ setErrorMsg(null);
4581
+ try {
4582
+ const tx = await client.retryRampTransaction(txId);
4583
+ setTxStatus(tx.status);
4584
+ applySettlement(tx);
4585
+ } catch (e) {
4586
+ setErrorMsg(e instanceof Error && e.message ? e.message : "Could not retry the transfer. Try again in a moment.");
4587
+ } finally {
4588
+ setRetrying(false);
4589
+ }
4590
+ }
4483
4591
  useEffect(() => {
4484
4592
  if (step !== "status" || !txId) return;
4485
4593
  if (txStatus && TERMINAL.includes(txStatus)) return;
@@ -4489,7 +4597,14 @@ function RampWidget({ onClose }) {
4489
4597
  const tx = await client.getRampTransaction(txId);
4490
4598
  if (!active) return;
4491
4599
  setTxStatus(tx.status);
4492
- if (tx.stellarTxHash) setStellarTxHash(tx.stellarTxHash);
4600
+ applySettlement(tx);
4601
+ const pending = tx.pendingSignature;
4602
+ if (pending && !signingRef.current) {
4603
+ signingRef.current = true;
4604
+ void resumeRef.current(txId, pending).finally(() => {
4605
+ signingRef.current = false;
4606
+ });
4607
+ }
4493
4608
  if (tx.kycUrl) setKycUrl(tx.kycUrl);
4494
4609
  if (tx.depositInstructions) setDepositInstructions(tx.depositInstructions);
4495
4610
  if (TERMINAL.includes(tx.status)) clearInterval(id);
@@ -4556,7 +4671,7 @@ function RampWidget({ onClose }) {
4556
4671
  } else if (step === "status" && txId) {
4557
4672
  const tx = await client.getRampTransaction(txId);
4558
4673
  setTxStatus(tx.status);
4559
- if (tx.stellarTxHash) setStellarTxHash(tx.stellarTxHash);
4674
+ applySettlement(tx);
4560
4675
  if (tx.kycUrl) setKycUrl(tx.kycUrl);
4561
4676
  if (tx.depositInstructions) setDepositInstructions(tx.depositInstructions);
4562
4677
  }
@@ -4577,6 +4692,9 @@ function RampWidget({ onClose }) {
4577
4692
  setTosUrl(null);
4578
4693
  setTxStatus(null);
4579
4694
  setStellarTxHash(null);
4695
+ setTxHash(null);
4696
+ setTxChain(null);
4697
+ setFundsInTransit(false);
4580
4698
  setDepositInstructions(null);
4581
4699
  setKycPending(false);
4582
4700
  setKycApproved(false);
@@ -4585,6 +4703,11 @@ function RampWidget({ onClose }) {
4585
4703
  }
4586
4704
  async function resumeWithSignature(id, ps) {
4587
4705
  const outcome = await signTx(ps.unsignedXdr);
4706
+ if (outcome.status === "cosign_pending") {
4707
+ setErrorMsg("Approve the signature on your device, then resume.");
4708
+ setStep("error");
4709
+ return;
4710
+ }
4588
4711
  if (outcome.status !== "signed") {
4589
4712
  setErrorMsg(outcome.message ?? outcome.details ?? "Signing was cancelled.");
4590
4713
  setStep("error");
@@ -4592,10 +4715,13 @@ function RampWidget({ onClose }) {
4592
4715
  }
4593
4716
  const result = await client.submitRampSignature(id, {
4594
4717
  signedXdr: outcome.signedXdr,
4718
+ // The CCTP actions are not in the generated schema until it is regenerated.
4595
4719
  action: ps.action
4596
4720
  });
4597
4721
  await applyResult(result);
4598
4722
  }
4723
+ const resumeRef = useRef(resumeWithSignature);
4724
+ resumeRef.current = resumeWithSignature;
4599
4725
  async function applyResult(result) {
4600
4726
  setTxId(result.txId);
4601
4727
  setProvider(result.provider);
@@ -4751,7 +4877,7 @@ function RampWidget({ onClose }) {
4751
4877
  }
4752
4878
  }
4753
4879
  const kycBlocking = kycPending && !kycApproved;
4754
- const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash && !kycPending;
4880
+ const canComplete = direction === "offramp" && step === "status" && txStatus !== "completed" && !stellarTxHash && !txHash && !kycPending;
4755
4881
  const flowSteps = flowStepsOf(quotes, selectedQuote);
4756
4882
  const flowStepIndex = flowSteps.indexOf(STEP_LABEL[step] ?? "");
4757
4883
  if (pendingKyc?.type === "FORM") {
@@ -4836,7 +4962,12 @@ function RampWidget({ onClose }) {
4836
4962
  onboardingStatus: onboardingStatus ?? null,
4837
4963
  kycJustApproved: kycPending && kycApproved,
4838
4964
  stellarTxHash,
4839
- explorerUrl: stellarTxHash ? `https://stellar.expert/explorer/${network === "mainnet" ? "public" : "testnet"}/tx/${stellarTxHash}` : null,
4965
+ txHash,
4966
+ txChain,
4967
+ explorerUrl: explorerTxUrl2(txChain ?? "STELLAR", txHash ?? stellarTxHash, network),
4968
+ fundsInTransit,
4969
+ retrying,
4970
+ onRetryTransit: handleRetryTransit,
4840
4971
  depositInstructions,
4841
4972
  canComplete,
4842
4973
  completing,
@@ -4943,7 +5074,7 @@ function PollarLogo(props) {
4943
5074
  )
4944
5075
  ] });
4945
5076
  }
4946
- var CHAIN_NAME = {
5077
+ var CHAIN_NAME2 = {
4947
5078
  STELLAR: "Stellar",
4948
5079
  POLYGON: "Polygon",
4949
5080
  SOLANA: "Solana"
@@ -4962,7 +5093,7 @@ function ReceiveModalTemplate({
4962
5093
  onClose
4963
5094
  }) {
4964
5095
  const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
4965
- const chainName = selectedChain ? CHAIN_NAME[selectedChain] ?? selectedChain : "wallet";
5096
+ const chainName = selectedChain ? CHAIN_NAME2[selectedChain] ?? selectedChain : "wallet";
4966
5097
  return /* @__PURE__ */ jsxs(
4967
5098
  "div",
4968
5099
  {
@@ -5044,7 +5175,7 @@ function ReceiveModalTemplate({
5044
5175
  ] })
5045
5176
  ] })
5046
5177
  ] }) : /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "No wallet connected." }),
5047
- /* @__PURE__ */ jsx(PollarModalFooter, { shield: true })
5178
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
5048
5179
  ]
5049
5180
  }
5050
5181
  );
@@ -5107,6 +5238,7 @@ var STATUS_MESSAGES = {
5107
5238
  submitting: "Submitting transaction\u2026",
5108
5239
  submitted: "Submitted \u2014 waiting for confirmation\u2026",
5109
5240
  "signing-submitting": "Signing and submitting transaction\u2026",
5241
+ awaiting_cosign: "Waiting for your approval on this device\u2026",
5110
5242
  "building-signing-submitting": "Processing transaction\u2026",
5111
5243
  success: "Transaction sent successfully",
5112
5244
  error: "Transaction failed"
@@ -5142,14 +5274,22 @@ function TxStatusView({
5142
5274
  }) {
5143
5275
  const buildData = "buildData" in transaction ? transaction.buildData : null;
5144
5276
  const hash = transaction.step === "success" ? transaction.hash : null;
5145
- const errorDetails = transaction.step === "error" ? transaction.details ?? null : null;
5277
+ const errorDetails = transaction.step === "error" ? transactionErrorMessage(transaction.code, transaction.details) : null;
5146
5278
  const isBuilt = transaction.step === "built";
5147
5279
  const isInFlight = IN_FLIGHT_STEPS.has(transaction.step);
5148
5280
  const isSuccess = transaction.step === "success";
5149
5281
  const isError = transaction.step === "error";
5150
5282
  const showDetails = buildData !== null && SHOW_DETAILS_STEPS.has(transaction.step);
5151
- const walletImg = walletType === WalletType.FREIGHTER ? LOGO_FREIGHTER : walletType === WalletType.ALBEDO ? LOGO_ALBEDO : LOGO_POLLAR;
5283
+ const walletImg = walletType === WalletType.FREIGHTER ? LOGO_FREIGHTER : walletType === WalletType.ALBEDO ? LOGO_ALBEDO : null;
5152
5284
  const walletAlt = walletType === WalletType.FREIGHTER ? "Freighter" : walletType === WalletType.ALBEDO ? "Albedo" : "Pollar";
5285
+ const statusBanner = /* @__PURE__ */ jsx(
5286
+ ModalStatusBanner,
5287
+ {
5288
+ message: STATUS_MESSAGES[transaction.step],
5289
+ status: isError ? "ERROR" : isInFlight ? "LOADING" : isSuccess ? "SUCCESS" : "NONE"
5290
+ }
5291
+ );
5292
+ const showSpinner = isInFlight || isSuccess || isError;
5153
5293
  return /* @__PURE__ */ jsxs(Fragment, { children: [
5154
5294
  showDetails && buildData && /* @__PURE__ */ jsxs(Fragment, { children: [
5155
5295
  /* @__PURE__ */ jsxs("div", { className: "pollar-tx-summary", children: [
@@ -5190,7 +5330,7 @@ function TxStatusView({
5190
5330
  /* @__PURE__ */ jsx("pre", { className: "pollar-tx-error-details-content", children: errorDetails })
5191
5331
  ] }),
5192
5332
  isBuilt && /* @__PURE__ */ jsx("button", { className: "pollar-btn-primary pollar-tx-sign-btn", onClick: onSignAndSend, children: "Sign & Send" }),
5193
- (isInFlight || isSuccess || isError) && /* @__PURE__ */ jsxs("div", { className: "pollar-tx-wallet-spinner", children: [
5333
+ showSpinner && /* @__PURE__ */ jsxs("div", { className: "pollar-tx-wallet-spinner", children: [
5194
5334
  /* @__PURE__ */ jsxs("div", { className: "pollar-tx-spinner-ring", children: [
5195
5335
  /* @__PURE__ */ jsxs(
5196
5336
  "svg",
@@ -5220,8 +5360,12 @@ function TxStatusView({
5220
5360
  ]
5221
5361
  }
5222
5362
  ),
5223
- /* @__PURE__ */ jsx("div", { className: "pollar-tx-wallet-icon", children: /* @__PURE__ */ jsx("img", { src: walletImg, alt: walletAlt, className: "pollar-tx-wallet-img" }) })
5363
+ /* @__PURE__ */ jsx("div", { className: "pollar-tx-wallet-icon", children: walletImg ? /* @__PURE__ */ jsx("img", { src: walletImg, alt: walletAlt, className: "pollar-tx-wallet-img" }) : /* @__PURE__ */ jsxs(Fragment, { children: [
5364
+ /* @__PURE__ */ jsx("img", { src: LOGO_POLLAR_MARK_ON_LIGHT, alt: walletAlt, className: "pollar-tx-wallet-img pollar-logo-on-light" }),
5365
+ /* @__PURE__ */ jsx("img", { src: LOGO_POLLAR_MARK_ON_DARK, alt: walletAlt, className: "pollar-tx-wallet-img pollar-logo-on-dark" })
5366
+ ] }) })
5224
5367
  ] }),
5368
+ statusBanner,
5225
5369
  isInFlight && /* @__PURE__ */ jsx("p", { className: "pollar-tx-spinner-label", children: walletType === WalletType.FREIGHTER ? "Waiting for Freighter\u2026" : walletType === WalletType.ALBEDO ? "Waiting for Albedo\u2026" : "Signing and sending\u2026" }),
5226
5370
  isError && onRetry && "buildData" in transaction && transaction.buildData && /* @__PURE__ */ jsx("button", { className: "pollar-btn-secondary pollar-tx-retry-btn", onClick: onRetry, children: "Try again" })
5227
5371
  ] }),
@@ -5286,13 +5430,7 @@ function TxStatusView({
5286
5430
  ] })
5287
5431
  ] }),
5288
5432
  isSuccess && /* @__PURE__ */ jsx("button", { className: "pollar-btn-primary pollar-tx-sign-btn", onClick: onDone, children: "Done" }),
5289
- /* @__PURE__ */ jsx(
5290
- ModalStatusBanner,
5291
- {
5292
- message: STATUS_MESSAGES[transaction.step],
5293
- status: isError ? "ERROR" : isInFlight ? "LOADING" : isSuccess ? "SUCCESS" : "NONE"
5294
- }
5295
- )
5433
+ !showSpinner && statusBanner
5296
5434
  ] });
5297
5435
  }
5298
5436
  function formatBalance(balance) {
@@ -5309,6 +5447,11 @@ function chainLabel(chain) {
5309
5447
  if (chain === "POLYGON") return "Polygon";
5310
5448
  return "network";
5311
5449
  }
5450
+ function destinationPlaceholder(chain) {
5451
+ if (chain === "SOLANA") return "Solana address";
5452
+ if (chain === "POLYGON") return "0x\u2026";
5453
+ return "G\u2026";
5454
+ }
5312
5455
  function AssetIcon({ code }) {
5313
5456
  return /* @__PURE__ */ jsx("span", { className: "pollar-send-asset-icon", "aria-hidden": true, children: code.slice(0, 2).toUpperCase() });
5314
5457
  }
@@ -5426,6 +5569,10 @@ function SendModalTemplate({
5426
5569
  onMax,
5427
5570
  onPaste,
5428
5571
  onDestinationChange,
5572
+ memo = "",
5573
+ memoType = "text",
5574
+ onMemoChange,
5575
+ onMemoTypeChange,
5429
5576
  onSubmit,
5430
5577
  onSignAndSend,
5431
5578
  onToggleXdr,
@@ -5533,7 +5680,7 @@ function SendModalTemplate({
5533
5680
  {
5534
5681
  className: "pollar-input pollar-send-destination-input",
5535
5682
  type: "text",
5536
- placeholder: "G\u2026",
5683
+ placeholder: destinationPlaceholder(selectedChain),
5537
5684
  value: destination,
5538
5685
  onChange: (e) => onDestinationChange(e.target.value),
5539
5686
  "aria-label": "Destination wallet"
@@ -5542,6 +5689,39 @@ function SendModalTemplate({
5542
5689
  /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-send-inline-action", onClick: onPaste, children: "Paste" })
5543
5690
  ] })
5544
5691
  ] }),
5692
+ selectedChain === "STELLAR" && onMemoChange && /* @__PURE__ */ jsxs("div", { className: "pollar-send-field", children: [
5693
+ /* @__PURE__ */ jsxs("label", { className: "pollar-send-label", htmlFor: "pollar-send-memo", children: [
5694
+ "Memo ",
5695
+ /* @__PURE__ */ jsx("span", { className: "pollar-send-label-optional", children: "(optional)" })
5696
+ ] }),
5697
+ /* @__PURE__ */ jsxs("div", { className: "pollar-send-memo-row", children: [
5698
+ /* @__PURE__ */ jsxs(
5699
+ "select",
5700
+ {
5701
+ className: "pollar-input pollar-send-memo-type",
5702
+ value: memoType,
5703
+ onChange: (e) => onMemoTypeChange?.(e.target.value),
5704
+ "aria-label": "Memo type",
5705
+ children: [
5706
+ /* @__PURE__ */ jsx("option", { value: "text", children: "Text" }),
5707
+ /* @__PURE__ */ jsx("option", { value: "id", children: "ID" })
5708
+ ]
5709
+ }
5710
+ ),
5711
+ /* @__PURE__ */ jsx(
5712
+ "input",
5713
+ {
5714
+ id: "pollar-send-memo",
5715
+ className: "pollar-input pollar-send-memo-input",
5716
+ type: "text",
5717
+ inputMode: memoType === "id" ? "numeric" : "text",
5718
+ placeholder: memoType === "id" ? "123456789" : "Up to 28 characters",
5719
+ value: memo,
5720
+ onChange: (e) => onMemoChange(e.target.value)
5721
+ }
5722
+ )
5723
+ ] })
5724
+ ] }),
5545
5725
  formError && /* @__PURE__ */ jsx("div", { className: "pollar-modal-error", children: formError }),
5546
5726
  /* @__PURE__ */ jsx("div", { className: "pollar-modal-actions", children: /* @__PURE__ */ jsx("button", { className: "pollar-btn-primary", onClick: onSubmit, disabled: !canSubmit, children: "Continue" }) })
5547
5727
  ] }),
@@ -5565,6 +5745,16 @@ function SendModalTemplate({
5565
5745
  }
5566
5746
  );
5567
5747
  }
5748
+ var MAX_MEMO_ID = 18446744073709551615n;
5749
+ function parseMemo(type, raw) {
5750
+ const value = type === "id" ? raw.trim() : raw;
5751
+ if (value.trim() === "") return void 0;
5752
+ if (type === "text") {
5753
+ return new TextEncoder().encode(value).length > 28 ? "The memo text can be at most 28 bytes." : { type, value };
5754
+ }
5755
+ if (!/^\d+$/.test(value) || BigInt(value) > MAX_MEMO_ID) return "The memo ID must be a whole number up to 2^64 - 1.";
5756
+ return { type, value };
5757
+ }
5568
5758
  function assetParam(record) {
5569
5759
  if (record.type === "native") return { type: "native" };
5570
5760
  if (record.type === "credit_alphanum4") {
@@ -5589,6 +5779,8 @@ function SendModal({ onClose }) {
5589
5779
  const [step, setStep] = useState("form");
5590
5780
  const [amount, setAmount] = useState("");
5591
5781
  const [destination, setDestination] = useState("");
5782
+ const [memo, setMemo] = useState("");
5783
+ const [memoType, setMemoType] = useState("text");
5592
5784
  const [selectedAsset, setSelectedAsset] = useState(null);
5593
5785
  const [showXdr, setShowXdr] = useState(false);
5594
5786
  const [copied, setCopied] = useState(false);
@@ -5599,9 +5791,10 @@ function SendModal({ onClose }) {
5599
5791
  useEffect(() => {
5600
5792
  if (selectedChain === null && chains.length > 0) setSelectedChain(chains[0]);
5601
5793
  }, [chains, selectedChain]);
5602
- const canSendOnChain = selectedChain === "STELLAR" || selectedChain === "SOLANA";
5794
+ const canSendOnChain = selectedChain === "STELLAR" || selectedChain === "SOLANA" || selectedChain === "POLYGON";
5603
5795
  const notReadyReason = walletNotReadyReason(wallet, selectedChain);
5604
- const isBaseUnitChain = selectedChain === "SOLANA";
5796
+ const isBaseUnitChain = selectedChain === "SOLANA" || selectedChain === "POLYGON";
5797
+ const nativeDecimals = selectedChain === "POLYGON" ? 18 : 9;
5605
5798
  useEffect(() => {
5606
5799
  void refreshWalletBalance();
5607
5800
  }, [refreshWalletBalance]);
@@ -5629,7 +5822,7 @@ function SendModal({ onClose }) {
5629
5822
  const hash = transaction.step === "success" ? transaction.hash : null;
5630
5823
  const buildData = "buildData" in transaction ? transaction.buildData : null;
5631
5824
  const explorerNetwork = buildData?.summary.network?.toLowerCase().includes("testnet") ? "testnet" : buildData ? "public" : network === "testnet" ? "testnet" : "public";
5632
- const explorerUrl = !hash ? null : selectedChain === "SOLANA" ? `https://explorer.solana.com/tx/${hash}${explorerNetwork === "testnet" ? "?cluster=devnet" : ""}` : `https://stellar.expert/explorer/${explorerNetwork}/tx/${hash}`;
5825
+ 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}`;
5633
5826
  const IN_FLIGHT_STEPS3 = [
5634
5827
  "building",
5635
5828
  "signing",
@@ -5668,33 +5861,42 @@ function SendModal({ onClose }) {
5668
5861
  setFormError("Enter a destination address");
5669
5862
  return;
5670
5863
  }
5864
+ const parsedMemo = selectedChain === "STELLAR" ? parseMemo(memoType, memo) : void 0;
5865
+ if (typeof parsedMemo === "string") {
5866
+ setFormError(parsedMemo);
5867
+ return;
5868
+ }
5671
5869
  const isNativeAsset = selectedAsset.type === "native";
5672
5870
  if (isBaseUnitChain && !isNativeAsset && (!selectedAsset.issuer || selectedAsset.decimals === void 0)) {
5673
- setFormError("This token is missing its mint or decimals and cannot be sent.");
5871
+ setFormError("This token is missing its contract or decimals and cannot be sent.");
5674
5872
  return;
5675
5873
  }
5676
5874
  let sendAmount = amount;
5677
5875
  if (isBaseUnitChain) {
5678
5876
  try {
5679
- sendAmount = toBaseUnits(amount, selectedAsset.decimals ?? 9);
5877
+ sendAmount = toBaseUnits(amount, selectedAsset.decimals ?? nativeDecimals);
5680
5878
  } catch (e) {
5681
5879
  setFormError(e instanceof Error ? e.message : "Invalid amount");
5682
5880
  return;
5683
5881
  }
5684
5882
  }
5685
5883
  setStep("tx");
5686
- if (selectedChain === "SOLANA") {
5884
+ if (selectedChain === "SOLANA" || selectedChain === "POLYGON") {
5687
5885
  await sendPayment({
5688
- chain: "SOLANA",
5886
+ chain: selectedChain,
5689
5887
  destination: destination.trim(),
5690
5888
  amount: sendAmount,
5691
- // Native SOL carries no mint; an SPL token's mint rides in `issuer`,
5692
- // which the guard above proved is present.
5889
+ // A native coin carries no token id; an SPL mint or ERC-20 contract rides
5890
+ // in `issuer`, which the guard above proved is present.
5693
5891
  ...isNativeAsset ? {} : { mint: selectedAsset.issuer }
5694
5892
  });
5695
5893
  return;
5696
5894
  }
5697
- await buildTx("payment", { destination: destination.trim(), amount, asset: assetParam(selectedAsset) });
5895
+ await buildTx(
5896
+ "payment",
5897
+ { destination: destination.trim(), amount, asset: assetParam(selectedAsset) },
5898
+ parsedMemo ? { memo: parsedMemo } : void 0
5899
+ );
5698
5900
  }
5699
5901
  function handleSignAndSend() {
5700
5902
  if (transaction.step === "built") {
@@ -5779,6 +5981,10 @@ function SendModal({ onClose }) {
5779
5981
  onMax: handleMax,
5780
5982
  onPaste: handlePaste,
5781
5983
  onDestinationChange: setDestination,
5984
+ memo,
5985
+ memoType,
5986
+ onMemoChange: setMemo,
5987
+ onMemoTypeChange: setMemoType,
5782
5988
  onSubmit: () => void handleSubmit(),
5783
5989
  onSignAndSend: handleSignAndSend,
5784
5990
  onToggleXdr: () => setShowXdr((v) => !v),
@@ -6186,7 +6392,7 @@ function SwapModalTemplate({
6186
6392
  onDone
6187
6393
  }
6188
6394
  ),
6189
- /* @__PURE__ */ jsx(PollarModalFooter, { shield: true })
6395
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
6190
6396
  ]
6191
6397
  }
6192
6398
  );
@@ -7015,7 +7221,8 @@ function groupPan(pan) {
7015
7221
  }
7016
7222
  var CARD_ERROR_COPY = {
7017
7223
  SDK_CARDS_PROVIDER_ERROR: "The card provider is not responding right now. Please try again in a few minutes.",
7018
- SDK_CARDS_IP_NOT_SUPPORTED: "The card provider cannot accept your current connection (IPv6). Please try again from another network, for example Wi-Fi."
7224
+ SDK_CARDS_IP_NOT_SUPPORTED: "The card provider cannot accept your current connection (IPv6). Please try again from another network, for example Wi-Fi.",
7225
+ 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."
7019
7226
  };
7020
7227
  function errorText(e, fallback) {
7021
7228
  if (isPollarApiError(e)) {
@@ -7931,6 +8138,362 @@ function SessionsModal({ onClose }) {
7931
8138
  }
7932
8139
  ) });
7933
8140
  }
8141
+ function useCosign() {
8142
+ const { getClient, isAuthenticated } = usePollar();
8143
+ const [state, setState] = useState({ pending: [] });
8144
+ const [loaded, setLoaded] = useState(false);
8145
+ useEffect(() => getClient().onCosignStateChange(setState), [getClient]);
8146
+ const refresh = useCallback(async () => {
8147
+ if (!isAuthenticated) return;
8148
+ try {
8149
+ await getClient().cosign.pending();
8150
+ } finally {
8151
+ setLoaded(true);
8152
+ }
8153
+ }, [getClient, isAuthenticated]);
8154
+ useEffect(() => {
8155
+ void refresh();
8156
+ }, [refresh]);
8157
+ return {
8158
+ pending: state.pending,
8159
+ ...state.lastResolved ? { lastResolved: state.lastResolved } : {},
8160
+ loaded,
8161
+ refresh,
8162
+ approve: useCallback((request) => getClient().cosign.approve(request), [getClient]),
8163
+ reject: useCallback((request) => getClient().cosign.reject(request), [getClient]),
8164
+ verify: useCallback((request) => getClient().cosign.verify(request), [getClient]),
8165
+ inspectQuorum: useCallback(() => getClient().cosign.inspectQuorum(), [getClient]),
8166
+ devices: useCallback(() => getClient().cosign.devices(), [getClient]),
8167
+ revokeDevice: useCallback(
8168
+ (deviceId, options) => getClient().cosign.revokeDevice(deviceId, options),
8169
+ [getClient]
8170
+ )
8171
+ };
8172
+ }
8173
+ var OPERATION_LABELS = {
8174
+ payment: "Send",
8175
+ path_payment_strict_send: "Swap",
8176
+ change_trust: "Add asset",
8177
+ create_account: "Create account",
8178
+ invoke_contract: "Contract call",
8179
+ manage_data: "Manage data"
8180
+ };
8181
+ function labelOf(request) {
8182
+ const op = request.operation ?? "";
8183
+ return OPERATION_LABELS[op] ?? (op ? op.replace(/_/g, " ") : "Transaction");
8184
+ }
8185
+ function expiresIn(request) {
8186
+ const ms = new Date(request.expiresAt).getTime() - Date.now();
8187
+ if (!Number.isFinite(ms) || ms <= 0) return "expired";
8188
+ const h = Math.floor(ms / 36e5);
8189
+ const m = Math.floor(ms % 36e5 / 6e4);
8190
+ return h > 0 ? `${h}h ${m}m` : `${m}m`;
8191
+ }
8192
+ function detailRows(request) {
8193
+ const details = request.details ?? {};
8194
+ const rows = [];
8195
+ const push = (label, value) => {
8196
+ if (value === void 0 || value === null || value === "") return;
8197
+ rows.push([
8198
+ label,
8199
+ typeof value === "string" && value.length > 24 && /^[GC][A-Z2-7]{55}$/.test(value) ? cropAddress(value) : String(value)
8200
+ ]);
8201
+ };
8202
+ push("Destination", details.destination);
8203
+ push("Amount", details.amount);
8204
+ push("Asset", details.asset ?? details.assetCode);
8205
+ push("Network", request.network);
8206
+ return rows;
8207
+ }
8208
+ function CloseIcon2() {
8209
+ return /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "m3 3 8 8M11 3l-8 8", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
8210
+ }
8211
+ function CosignModalTemplate({
8212
+ theme,
8213
+ accentColor,
8214
+ styleOverrides,
8215
+ pending,
8216
+ current,
8217
+ verification,
8218
+ busy,
8219
+ error,
8220
+ approveBlocked = false,
8221
+ lastResolved,
8222
+ explorerUrl,
8223
+ onSelect,
8224
+ onApprove,
8225
+ onReject,
8226
+ onClose
8227
+ }) {
8228
+ const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
8229
+ const verified = verification?.ok === true;
8230
+ const canVote = !!current && verified && !busy && !approveBlocked;
8231
+ return /* @__PURE__ */ jsxs(
8232
+ "div",
8233
+ {
8234
+ className: "pollar-modal-card pollar-cosign-modal",
8235
+ "data-theme": theme,
8236
+ style: cssVars,
8237
+ onClick: (e) => e.stopPropagation(),
8238
+ children: [
8239
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
8240
+ /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Confirm with your device" }),
8241
+ /* @__PURE__ */ jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-modal-close", onClick: onClose, "aria-label": "Close", title: "Close", children: /* @__PURE__ */ jsx(CloseIcon2, {}) }) })
8242
+ ] }),
8243
+ pending.length === 0 && /* @__PURE__ */ jsx("div", { className: "pollar-cosign-empty", children: lastResolved ? /* @__PURE__ */ jsxs(Fragment, { children: [
8244
+ lastResolved.status === "APPROVED" && /* @__PURE__ */ jsxs("svg", { className: "pollar-cosign-approved-icon", width: "44", height: "44", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: [
8245
+ /* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "7", fill: "currentColor" }),
8246
+ /* @__PURE__ */ jsx(
8247
+ "path",
8248
+ {
8249
+ d: "M3.5 7l2.5 2.5 4.5-5",
8250
+ stroke: "white",
8251
+ strokeWidth: "1.2",
8252
+ strokeLinecap: "round",
8253
+ strokeLinejoin: "round"
8254
+ }
8255
+ )
8256
+ ] }),
8257
+ /* @__PURE__ */ jsx("p", { className: "pollar-cosign-empty-title", children: lastResolved.status === "APPROVED" ? "Approved" : lastResolved.status === "REJECTED" ? "Rejected" : lastResolved.status.toLowerCase() }),
8258
+ /* @__PURE__ */ jsx("p", { className: "pollar-cosign-muted", children: lastResolved.submit?.hash ? /* @__PURE__ */ jsxs(Fragment, { children: [
8259
+ "Sent. Transaction",
8260
+ " ",
8261
+ explorerUrl ? /* @__PURE__ */ jsx("a", { className: "pollar-cosign-tx-link", href: explorerUrl, target: "_blank", rel: "noopener noreferrer", children: cropAddress(lastResolved.submit.hash) }) : cropAddress(lastResolved.submit.hash)
8262
+ ] }) : lastResolved.signedXdr ? "Signed. The app will send it." : "Nothing was signed." })
8263
+ ] }) : /* @__PURE__ */ jsx("p", { className: "pollar-cosign-muted", children: "Nothing waits for your approval." }) }),
8264
+ pending.length > 1 && /* @__PURE__ */ jsx("ul", { className: "pollar-cosign-list", children: pending.map((r) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
8265
+ "button",
8266
+ {
8267
+ type: "button",
8268
+ className: `pollar-cosign-item${current?.id === r.id ? " pollar-cosign-item-active" : ""}`,
8269
+ onClick: () => onSelect(r),
8270
+ children: [
8271
+ /* @__PURE__ */ jsx("span", { children: labelOf(r) }),
8272
+ /* @__PURE__ */ jsx("span", { className: "pollar-cosign-muted", children: expiresIn(r) })
8273
+ ]
8274
+ }
8275
+ ) }, r.id)) }),
8276
+ current && /* @__PURE__ */ jsxs("div", { className: "pollar-cosign-detail", children: [
8277
+ /* @__PURE__ */ jsx("p", { className: "pollar-cosign-detail-title", children: labelOf(current) }),
8278
+ current.summary && /* @__PURE__ */ jsx("p", { className: "pollar-cosign-muted", children: current.summary }),
8279
+ /* @__PURE__ */ jsx(GroupSteps, { request: current }),
8280
+ /* @__PURE__ */ jsxs("dl", { className: "pollar-cosign-rows", children: [
8281
+ detailRows(current).map(([k, v]) => /* @__PURE__ */ jsxs("div", { className: "pollar-cosign-row", children: [
8282
+ /* @__PURE__ */ jsx("dt", { children: k }),
8283
+ /* @__PURE__ */ jsx("dd", { children: v })
8284
+ ] }, k)),
8285
+ /* @__PURE__ */ jsxs("div", { className: "pollar-cosign-row", children: [
8286
+ /* @__PURE__ */ jsx("dt", { children: "Expires in" }),
8287
+ /* @__PURE__ */ jsx("dd", { children: expiresIn(current) })
8288
+ ] })
8289
+ ] }),
8290
+ /* @__PURE__ */ jsxs(
8291
+ "div",
8292
+ {
8293
+ className: `pollar-cosign-verify pollar-cosign-verify-${verification ? verification.ok ? "ok" : "bad" : "pending"}`,
8294
+ children: [
8295
+ !verification && "Checking the transaction against Turnkey...",
8296
+ verification?.ok && "Verified: this is exactly what will be signed.",
8297
+ verification && !verification.ok && `Not verified: ${verification.reason}`
8298
+ ]
8299
+ }
8300
+ ),
8301
+ error && /* @__PURE__ */ jsx("div", { className: "pollar-cosign-error", children: error }),
8302
+ /* @__PURE__ */ jsxs("div", { className: "pollar-cosign-actions", children: [
8303
+ /* @__PURE__ */ jsx(
8304
+ "button",
8305
+ {
8306
+ type: "button",
8307
+ className: "pollar-cosign-btn pollar-cosign-btn-secondary",
8308
+ disabled: !!busy,
8309
+ onClick: () => onReject(current),
8310
+ children: busy === "rejecting" ? "Rejecting..." : "Reject"
8311
+ }
8312
+ ),
8313
+ /* @__PURE__ */ jsx(
8314
+ "button",
8315
+ {
8316
+ type: "button",
8317
+ className: "pollar-cosign-btn pollar-cosign-btn-primary",
8318
+ disabled: !canVote,
8319
+ onClick: () => onApprove(current),
8320
+ children: busy === "approving" ? "Approving..." : "Approve"
8321
+ }
8322
+ )
8323
+ ] })
8324
+ ] }),
8325
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
8326
+ ]
8327
+ }
8328
+ );
8329
+ }
8330
+ function GroupSteps({ request }) {
8331
+ const group = cosignGroupOf(request);
8332
+ if (!group || group.steps.length < 2) return null;
8333
+ const stepKey = cosignStepKeyOf(request);
8334
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-cosign-group", children: [
8335
+ /* @__PURE__ */ jsx("p", { className: "pollar-cosign-group-title", children: group.title }),
8336
+ /* @__PURE__ */ jsx("p", { className: "pollar-cosign-muted", children: "Approving covers these steps; each one is checked before it is signed." }),
8337
+ /* @__PURE__ */ jsx("ol", { className: "pollar-cosign-group-steps", children: group.steps.map((step) => {
8338
+ const isThis = stepKey !== null && stepInGroup({ steps: [step] }, stepKey);
8339
+ return /* @__PURE__ */ jsxs("li", { className: isThis ? "pollar-cosign-group-step-current" : void 0, children: [
8340
+ step.label,
8341
+ isThis && /* @__PURE__ */ jsx("span", { className: "pollar-cosign-muted", children: " (this one)" })
8342
+ ] }, step.key);
8343
+ }) })
8344
+ ] });
8345
+ }
8346
+ function CosignModal({ onClose }) {
8347
+ const { getClient, styles, network } = usePollar();
8348
+ const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
8349
+ const { pending, lastResolved, approve, reject, verify, inspectQuorum } = useCosign();
8350
+ const [selectedId, setSelectedId] = useState(null);
8351
+ const [verification, setVerification] = useState(null);
8352
+ const [busy, setBusy] = useState(null);
8353
+ const [error, setError] = useState(null);
8354
+ const [approveFailedFor, setApproveFailedFor] = useState(null);
8355
+ const [quorumFailure, setQuorumFailure] = useState(null);
8356
+ useEffect(() => {
8357
+ let cancelled = false;
8358
+ inspectQuorum().then((q) => {
8359
+ if (!cancelled && !q.ok) setQuorumFailure(q.reason);
8360
+ }).catch(() => void 0);
8361
+ return () => {
8362
+ cancelled = true;
8363
+ };
8364
+ }, [inspectQuorum]);
8365
+ const current = pending.find((r) => r.id === selectedId) ?? pending[0] ?? null;
8366
+ const currentRef = useRef(current);
8367
+ currentRef.current = current;
8368
+ const currentId = current?.id ?? null;
8369
+ useEffect(() => {
8370
+ const request = currentRef.current;
8371
+ if (!request) return;
8372
+ setVerification(null);
8373
+ setError(null);
8374
+ setApproveFailedFor(null);
8375
+ let cancelled = false;
8376
+ verify(request).then((v) => {
8377
+ if (!cancelled) setVerification(v);
8378
+ }).catch((err) => {
8379
+ if (!cancelled) setVerification({ ok: false, reason: err instanceof Error ? err.message : String(err) });
8380
+ });
8381
+ return () => {
8382
+ cancelled = true;
8383
+ };
8384
+ }, [currentId, verify]);
8385
+ const onCloseRef = useRef(onClose);
8386
+ onCloseRef.current = onClose;
8387
+ useEffect(() => {
8388
+ return getClient().onAuthStateChange((authState) => {
8389
+ if (authState.step === "idle") onCloseRef.current();
8390
+ });
8391
+ }, [getClient]);
8392
+ const run = useCallback(
8393
+ async (kind, request, action) => {
8394
+ setBusy(kind);
8395
+ setError(null);
8396
+ try {
8397
+ await action(request);
8398
+ } catch (err) {
8399
+ setError(transactionErrorMessage(isPollarApiError(err) ? err.code : null, err instanceof Error ? err.message : null));
8400
+ if (kind === "approving") setApproveFailedFor(request.id);
8401
+ } finally {
8402
+ setBusy(null);
8403
+ }
8404
+ },
8405
+ []
8406
+ );
8407
+ return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: onClose, children: /* @__PURE__ */ jsx(
8408
+ CosignModalTemplate,
8409
+ {
8410
+ theme,
8411
+ accentColor,
8412
+ styleOverrides,
8413
+ pending,
8414
+ current,
8415
+ verification: current ? quorumFailure ? { ok: false, reason: quorumFailure } : verification : null,
8416
+ busy,
8417
+ error,
8418
+ approveBlocked: !!current && approveFailedFor === current.id,
8419
+ ...lastResolved ? { lastResolved } : {},
8420
+ explorerUrl: lastResolved?.submit?.hash ? explorerTxUrl(lastResolved.network, lastResolved.submit.hash, network) : null,
8421
+ onSelect: (r) => setSelectedId(r.id),
8422
+ onApprove: (r) => void run("approving", r, approve),
8423
+ onReject: (r) => void run("rejecting", r, reject),
8424
+ onClose
8425
+ }
8426
+ ) });
8427
+ }
8428
+ var OPERATION_LABELS2 = {
8429
+ payment: "Send",
8430
+ path_payment_strict_send: "Swap",
8431
+ change_trust: "Add asset",
8432
+ create_account: "Create account",
8433
+ invoke_contract: "Contract call",
8434
+ manage_data: "Manage data"
8435
+ };
8436
+ function labelOf2(confirmation) {
8437
+ const op = confirmation.operation ?? "";
8438
+ return OPERATION_LABELS2[op] ?? (op ? op.replace(/_/g, " ") : "Transaction");
8439
+ }
8440
+ function detailRows2(confirmation) {
8441
+ const details = confirmation.details ?? {};
8442
+ const rows = [];
8443
+ const push = (label, value) => {
8444
+ if (value === void 0 || value === null || value === "") return;
8445
+ const text = typeof value === "object" ? JSON.stringify(value) : String(value);
8446
+ rows.push([label, /^[GC][A-Z2-7]{55}$/.test(text) ? cropAddress(text) : text]);
8447
+ };
8448
+ push("Destination", details.destination);
8449
+ push("Amount", details.amount);
8450
+ push("Asset", details.asset ?? details.assetCode ?? details.mint);
8451
+ push("Network", confirmation.network);
8452
+ return rows;
8453
+ }
8454
+ function CloseIcon3() {
8455
+ return /* @__PURE__ */ jsx("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx("path", { d: "m3 3 8 8M11 3l-8 8", stroke: "currentColor", strokeWidth: "1.7", strokeLinecap: "round" }) });
8456
+ }
8457
+ function ConfirmModal({ confirmation }) {
8458
+ const { getClient, styles } = usePollar();
8459
+ const { theme, accentColor, styleOverrides, overlayStyle } = modalChrome(styles);
8460
+ const cssVars = buildModalCssVars(theme, accentColor, styleOverrides);
8461
+ const rejectRef = useRef(confirmation.reject);
8462
+ rejectRef.current = confirmation.reject;
8463
+ useEffect(() => {
8464
+ return getClient().onAuthStateChange((authState) => {
8465
+ if (authState.step === "idle") rejectRef.current();
8466
+ });
8467
+ }, [getClient]);
8468
+ return /* @__PURE__ */ jsx("div", { className: "pollar-overlay", style: overlayStyle, onClick: confirmation.reject, children: /* @__PURE__ */ jsxs(
8469
+ "div",
8470
+ {
8471
+ className: "pollar-modal-card pollar-cosign-modal",
8472
+ "data-theme": theme,
8473
+ style: cssVars,
8474
+ onClick: (e) => e.stopPropagation(),
8475
+ children: [
8476
+ /* @__PURE__ */ jsxs("div", { className: "pollar-modal-header", children: [
8477
+ /* @__PURE__ */ jsx("h2", { className: "pollar-modal-title", children: "Confirm transaction" }),
8478
+ /* @__PURE__ */ jsx("div", { className: "pollar-modal-header-actions", children: /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-modal-close", onClick: confirmation.reject, "aria-label": "Close", title: "Close", children: /* @__PURE__ */ jsx(CloseIcon3, {}) }) })
8479
+ ] }),
8480
+ /* @__PURE__ */ jsxs("div", { className: "pollar-cosign-detail", children: [
8481
+ /* @__PURE__ */ jsx("p", { className: "pollar-cosign-detail-title", children: labelOf2(confirmation) }),
8482
+ /* @__PURE__ */ jsx("p", { className: "pollar-cosign-muted", children: "The app asks you to sign this transaction with your wallet." }),
8483
+ /* @__PURE__ */ jsx("dl", { className: "pollar-cosign-rows", children: detailRows2(confirmation).map(([k, v]) => /* @__PURE__ */ jsxs("div", { className: "pollar-cosign-row", children: [
8484
+ /* @__PURE__ */ jsx("dt", { children: k }),
8485
+ /* @__PURE__ */ jsx("dd", { children: v })
8486
+ ] }, k)) }),
8487
+ /* @__PURE__ */ jsxs("div", { className: "pollar-cosign-actions", children: [
8488
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-cosign-btn pollar-cosign-btn-secondary", onClick: confirmation.reject, children: "Cancel" }),
8489
+ /* @__PURE__ */ jsx("button", { type: "button", className: "pollar-cosign-btn pollar-cosign-btn-primary", onClick: confirmation.confirm, children: "Confirm" })
8490
+ ] })
8491
+ ] }),
8492
+ /* @__PURE__ */ jsx(PollarModalFooter, {})
8493
+ ]
8494
+ }
8495
+ ) });
8496
+ }
7934
8497
  function TransactionModalTemplate({
7935
8498
  theme,
7936
8499
  accentColor,
@@ -8040,12 +8603,6 @@ function TransactionModal({ onClose }) {
8040
8603
  ) });
8041
8604
  }
8042
8605
  var PAGE_SIZE = 10;
8043
- function explorerUrlFor(chain, hash, network) {
8044
- if (chain === "SOLANA") {
8045
- return `https://explorer.solana.com/tx/${hash}${network === "testnet" ? "?cluster=devnet" : ""}`;
8046
- }
8047
- return `https://stellar.expert/explorer/${network === "testnet" ? "testnet" : "public"}/tx/${hash}`;
8048
- }
8049
8606
  function StatusBadge({ status }) {
8050
8607
  return /* @__PURE__ */ jsx("span", { className: "pollar-hist-item-badge", "data-status": status, children: status });
8051
8608
  }
@@ -8162,7 +8719,7 @@ function TxHistoryModalTemplate({
8162
8719
  txHistory.step === "loaded" && records.length === 0 && /* @__PURE__ */ jsx("div", { className: "pollar-modal-empty", children: "No transactions yet." }),
8163
8720
  records.map((record) => {
8164
8721
  const hash = typeof record.hash === "string" && record.hash.length > 0 ? record.hash : void 0;
8165
- const explorerUrl = hash ? explorerUrlFor(record.chain, hash, record.network) : void 0;
8722
+ const explorerUrl = hash ? explorerTxUrl(record.chain, hash, record.network) : void 0;
8166
8723
  const asset = typeof record.details?.asset === "string" ? record.details.asset : void 0;
8167
8724
  const colon = asset ? asset.indexOf(":") : -1;
8168
8725
  const trustline = record.operation === "change_trust" && asset && colon > 0 ? {
@@ -8571,6 +9128,9 @@ function PollarProvider({
8571
9128
  const [transaction, setTransaction] = useState({ step: "idle" });
8572
9129
  const [txHistory, setTxHistory] = useState({ step: "idle" });
8573
9130
  const [sessions, setSessions] = useState({ step: "idle" });
9131
+ const [cosign, setCosign] = useState({ pending: [] });
9132
+ const [confirmations, setConfirmations] = useState([]);
9133
+ const firstConfirmation = confirmations[0] ?? null;
8574
9134
  const [walletBalance, setWalletBalance] = useState({ step: "idle" });
8575
9135
  const [enabledAssets, setEnabledAssets] = useState({ step: "idle" });
8576
9136
  const [resolvedConfig, setResolvedConfig] = useState(() => appConfigProp ?? DEFAULT_APP_CONFIG);
@@ -8588,6 +9148,12 @@ function PollarProvider({
8588
9148
  useEffect(() => {
8589
9149
  return pollarClient.onTxHistoryStateChange(setTxHistory);
8590
9150
  }, [pollarClient]);
9151
+ useEffect(() => {
9152
+ return pollarClient.onCosignStateChange(setCosign);
9153
+ }, [pollarClient]);
9154
+ useEffect(() => {
9155
+ return pollarClient.onConfirmationRequest(setConfirmations);
9156
+ }, [pollarClient]);
8591
9157
  useEffect(() => {
8592
9158
  return pollarClient.onSessionsStateChange(setSessions);
8593
9159
  }, [pollarClient]);
@@ -8631,7 +9197,7 @@ function PollarProvider({
8631
9197
  triggered = false;
8632
9198
  return;
8633
9199
  }
8634
- if (triggered || sessionRef.current?.wallet?.address) return;
9200
+ if (triggered || sessionRef.current) return;
8635
9201
  triggered = true;
8636
9202
  pollarClient.login({ provider: id });
8637
9203
  })
@@ -8688,6 +9254,12 @@ function PollarProvider({
8688
9254
  const [cardModalKey, setCardModalKey] = useState(0);
8689
9255
  const [receiveModalOpen, setReceiveModalOpen] = useState(false);
8690
9256
  const [sessionsModalOpen, setSessionsModalOpen] = useState(false);
9257
+ const [cosignModalOpen, setCosignModalOpen] = useState(false);
9258
+ const cosignPendingCount = useRef(0);
9259
+ useEffect(() => {
9260
+ if (cosign.pending.length > cosignPendingCount.current) setCosignModalOpen(true);
9261
+ cosignPendingCount.current = cosign.pending.length;
9262
+ }, [cosign.pending.length]);
8691
9263
  const [distributionRulesModalOpen, setDistributionRulesModalOpen] = useState(false);
8692
9264
  useEffect(
8693
9265
  () => pollarClient.onAuthStateChange((authState) => {
@@ -8704,12 +9276,14 @@ function PollarProvider({
8704
9276
  setCardModalOpen(false);
8705
9277
  setReceiveModalOpen(false);
8706
9278
  setSessionsModalOpen(false);
9279
+ setCosignModalOpen(false);
8707
9280
  setDistributionRulesModalOpen(false);
8708
9281
  }),
8709
9282
  [pollarClient]
8710
9283
  );
8711
9284
  const walletAddress = sessionState?.wallet?.address || "";
8712
9285
  const walletProvisioning = sessionState?.wallet?.provisioning;
9286
+ const hasSession = sessionState !== null;
8713
9287
  const getClient = useCallback(() => pollarClient, [pollarClient]);
8714
9288
  const refreshWalletBalance = useCallback(() => pollarClient.refreshBalance(), [pollarClient, walletAddress]);
8715
9289
  const refreshAssets = useCallback(() => pollarClient.refreshAssets(), [pollarClient, walletAddress]);
@@ -8719,7 +9293,9 @@ function PollarProvider({
8719
9293
  // session
8720
9294
  wallet: pollarClient.getWallet(),
8721
9295
  wallets: pollarClient.getWallets(),
8722
- isAuthenticated: !!walletAddress,
9296
+ isAuthenticated: hasSession,
9297
+ hasWallet: pollarClient.hasWallet(),
9298
+ createWallet: () => pollarClient.createWallet(),
8723
9299
  verified,
8724
9300
  // client
8725
9301
  getClient,
@@ -8785,6 +9361,10 @@ function PollarProvider({
8785
9361
  // sessions
8786
9362
  sessions,
8787
9363
  openSessionsModal: () => setSessionsModalOpen(true),
9364
+ // cosign
9365
+ cosign,
9366
+ openCosignModal: () => setCosignModalOpen(true),
9367
+ confirmations,
8788
9368
  // distribution
8789
9369
  openDistributionRulesModal: () => setDistributionRulesModalOpen(true),
8790
9370
  // network
@@ -8807,12 +9387,15 @@ function PollarProvider({
8807
9387
  }, [
8808
9388
  walletAddress,
8809
9389
  walletProvisioning,
9390
+ hasSession,
8810
9391
  verified,
8811
9392
  pollarClient,
8812
9393
  getClient,
8813
9394
  transaction,
8814
9395
  txHistory,
8815
9396
  sessions,
9397
+ cosign,
9398
+ confirmations,
8816
9399
  walletBalance,
8817
9400
  refreshWalletBalance,
8818
9401
  enabledAssets,
@@ -8860,6 +9443,8 @@ function PollarProvider({
8860
9443
  /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setCardModalOpen(false), children: /* @__PURE__ */ jsx(CardModal, { onClose: () => setCardModalOpen(false) }) }, `${cardModalKey}:${walletAddress}`),
8861
9444
  receiveModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setReceiveModalOpen(false), children: /* @__PURE__ */ jsx(ReceiveModal, { onClose: () => setReceiveModalOpen(false) }) }),
8862
9445
  sessionsModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setSessionsModalOpen(false), children: /* @__PURE__ */ jsx(SessionsModal, { onClose: () => setSessionsModalOpen(false) }) }),
9446
+ cosignModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setCosignModalOpen(false), children: /* @__PURE__ */ jsx(CosignModal, { onClose: () => setCosignModalOpen(false) }) }),
9447
+ firstConfirmation && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: firstConfirmation.reject, children: /* @__PURE__ */ jsx(ConfirmModal, { confirmation: firstConfirmation }, firstConfirmation.id) }),
8863
9448
  distributionRulesModalOpen && /* @__PURE__ */ jsx(ModalErrorBoundary, { onClose: () => setDistributionRulesModalOpen(false), children: /* @__PURE__ */ jsx(DistributionRulesModal, { onClose: () => setDistributionRulesModalOpen(false) }) })
8864
9449
  ] });
8865
9450
  }
@@ -8922,8 +9507,54 @@ function WalletButtonTemplate({
8922
9507
  onRamp,
8923
9508
  onDistributionRules,
8924
9509
  onLogout,
8925
- onLogin
9510
+ onLogin,
9511
+ signedIn,
9512
+ creatingWallet,
9513
+ createWalletError,
9514
+ onCreateWallet
8926
9515
  }) {
9516
+ if (!walletAddress && signedIn) {
9517
+ return /* @__PURE__ */ jsxs("div", { className: "pollar-wallet-wrapper", ref: wrapperRef, children: [
9518
+ /* @__PURE__ */ jsxs("button", { className: "pollar-wallet-btn", style: { backgroundColor: accentColor }, onClick: onToggleOpen, children: [
9519
+ /* @__PURE__ */ jsx("span", { className: "pollar-wallet-btn-label", children: onCreateWallet ? "No wallet" : "Signed in" }),
9520
+ /* @__PURE__ */ jsx(
9521
+ "svg",
9522
+ {
9523
+ className: `pollar-wallet-chevron${open ? " pollar-open" : ""}`,
9524
+ viewBox: "0 0 12 12",
9525
+ fill: "none",
9526
+ stroke: "currentColor",
9527
+ strokeWidth: "2",
9528
+ strokeLinecap: "round",
9529
+ strokeLinejoin: "round",
9530
+ children: /* @__PURE__ */ jsx("polyline", { points: "2,4 6,8 10,4" })
9531
+ }
9532
+ )
9533
+ ] }),
9534
+ open && /* @__PURE__ */ jsxs("div", { className: "pollar-wallet-dropdown", style: { backgroundColor: dropdownBg, borderColor: dropdownBorder }, children: [
9535
+ createWalletError && /* @__PURE__ */ jsxs(Fragment, { children: [
9536
+ /* @__PURE__ */ jsx("div", { className: "pollar-wallet-dropdown-notice", style: { color: itemColor }, role: "status", children: createWalletError }),
9537
+ /* @__PURE__ */ jsx("div", { className: "pollar-wallet-dropdown-divider" })
9538
+ ] }),
9539
+ onCreateWallet && /* @__PURE__ */ jsxs(Fragment, { children: [
9540
+ /* @__PURE__ */ jsx(
9541
+ "button",
9542
+ {
9543
+ className: "pollar-wallet-dropdown-item",
9544
+ style: { color: itemColor },
9545
+ onClick: onCreateWallet,
9546
+ disabled: creatingWallet,
9547
+ children: creatingWallet ? "Creating wallet\u2026" : "Create wallet"
9548
+ }
9549
+ ),
9550
+ /* @__PURE__ */ jsx("div", { className: "pollar-wallet-dropdown-divider" })
9551
+ ] }),
9552
+ /* @__PURE__ */ jsx("button", { className: "pollar-wallet-dropdown-item", style: { color: itemColor }, onClick: onSessions, children: "Active sessions" }),
9553
+ /* @__PURE__ */ jsx("div", { className: "pollar-wallet-dropdown-divider" }),
9554
+ /* @__PURE__ */ jsx("button", { className: "pollar-wallet-dropdown-item pollar-danger", onClick: onLogout, children: "Log out" })
9555
+ ] })
9556
+ ] });
9557
+ }
8927
9558
  if (!walletAddress) {
8928
9559
  return /* @__PURE__ */ jsxs("button", { type: "button", className: "pollar-wallet-login-btn", style: { backgroundColor: accentColor }, onClick: onLogin, children: [
8929
9560
  /* @__PURE__ */ jsx(ButtonLogo, {}),
@@ -9244,7 +9875,10 @@ function WalletButton() {
9244
9875
  openKycModal,
9245
9876
  openRampModal,
9246
9877
  openDistributionRulesModal,
9247
- tx: transaction
9878
+ tx: transaction,
9879
+ isAuthenticated,
9880
+ createWallet,
9881
+ appConfig
9248
9882
  } = usePollar();
9249
9883
  const { primaryChain, primaryAddress } = useChains();
9250
9884
  const walletAddress = primaryAddress || (wallet?.address ?? "");
@@ -9252,6 +9886,8 @@ function WalletButton() {
9252
9886
  const [copied, setCopied] = useState(false);
9253
9887
  const [creating, setCreating] = useState(false);
9254
9888
  const [created, setCreated] = useState(false);
9889
+ const [creatingWallet, setCreatingWallet] = useState(false);
9890
+ const [createWalletError, setCreateWalletError] = useState(null);
9255
9891
  const wrapperRef = useRef(null);
9256
9892
  const copyTimerRef = useRef(null);
9257
9893
  const isInProgress = transaction.step === "building" || transaction.step === "signing";
@@ -9305,6 +9941,21 @@ function WalletButton() {
9305
9941
  setCreating(false);
9306
9942
  }
9307
9943
  }
9944
+ async function handleCreateWallet() {
9945
+ if (creatingWallet) return;
9946
+ setCreatingWallet(true);
9947
+ setCreateWalletError(null);
9948
+ try {
9949
+ await createWallet();
9950
+ setOpen(false);
9951
+ } catch (err) {
9952
+ setCreateWalletError(
9953
+ isPollarApiError(err) && err.code === "SDK_WALLET_PROVISIONING_DISABLED" ? "This app does not create wallets." : "Could not create the wallet. Try again."
9954
+ );
9955
+ } finally {
9956
+ setCreatingWallet(false);
9957
+ }
9958
+ }
9308
9959
  function handleWalletBalance() {
9309
9960
  setOpen(false);
9310
9961
  openWalletBalanceModal();
@@ -9350,6 +10001,10 @@ function WalletButton() {
9350
10001
  wrapperRef,
9351
10002
  isInProgress,
9352
10003
  showCreateAccount: canCreateAccount,
10004
+ signedIn: isAuthenticated,
10005
+ creatingWallet,
10006
+ createWalletError,
10007
+ ...appConfig.application?.walletProvisioning === "NONE" ? {} : { onCreateWallet: handleCreateWallet },
9353
10008
  notReadyReason,
9354
10009
  creatingAccount: creating,
9355
10010
  onToggleOpen: () => setOpen((v) => !v),
@@ -9369,6 +10024,6 @@ function WalletButton() {
9369
10024
  );
9370
10025
  }
9371
10026
 
9372
- export { CardModal, ChainSelect, DistributionRulesModal, DistributionRulesModalTemplate, EarnModal, EnabledAssetsModal, EnabledAssetsModalTemplate, KycModal, KycModalTemplate, KycStatus, LoginModalTemplate, PollarProvider, ProviderRegistrationModal, RampWidget, RampWidgetTemplate, ReceiveModal, ReceiveModalTemplate, RegistryCheckModal, RequirementFormModal, RouteDisplay, SendModal, SendModalTemplate, SessionsModal, SessionsModalTemplate, SwapModal, SwapModalTemplate, TransactionModalTemplate, TxHistoryModalTemplate, TxStatusView, WalletBalanceModal, WalletBalanceModalTemplate, WalletButton, WalletButtonTemplate, addressForChain, browserPasskeyCeremony, browserPasskeySigner, buildModalCssVars, chainsOf, createPollarAdapterHook, modalChrome, readableTextOn, resolveChain, useChains, usePollar, walletNotReadyReason };
10027
+ export { CardModal, ChainSelect, CosignModal, CosignModalTemplate, DistributionRulesModal, DistributionRulesModalTemplate, EarnModal, EnabledAssetsModal, EnabledAssetsModalTemplate, KycModal, KycModalTemplate, KycStatus, LoginModalTemplate, PollarProvider, ProviderRegistrationModal, RampWidget, RampWidgetTemplate, ReceiveModal, ReceiveModalTemplate, RegistryCheckModal, RequirementFormModal, RouteDisplay, SendModal, SendModalTemplate, SessionsModal, SessionsModalTemplate, SwapModal, SwapModalTemplate, TransactionModalTemplate, TxHistoryModalTemplate, TxStatusView, WalletBalanceModal, WalletBalanceModalTemplate, WalletButton, WalletButtonTemplate, addressForChain, browserPasskeyCeremony, browserPasskeySigner, buildModalCssVars, chainsOf, createPollarAdapterHook, modalChrome, readableTextOn, resolveChain, useChains, useCosign, usePollar, walletNotReadyReason };
9373
10028
  //# sourceMappingURL=index.mjs.map
9374
10029
  //# sourceMappingURL=index.mjs.map