@coti-io/coti-wallet-plugin 0.1.0 → 0.2.1

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
@@ -574,6 +574,7 @@ var init_plugin = __esm({
574
574
  defaultNetworkId: void 0,
575
575
  debug: false,
576
576
  clearSessionKeyOnWagmiDisconnect: false,
577
+ waitForBalanceRefreshAfterTransfer: false,
577
578
  onboardingServices: { mode: "disabled" },
578
579
  onboardingGrantMinBalanceWei: 0,
579
580
  onboardingGrantPollIntervalMs: 2e3,
@@ -3672,6 +3673,17 @@ var usePrivateTokenBalance = () => {
3672
3673
  if (error instanceof CotiPluginError) {
3673
3674
  throw error;
3674
3675
  }
3676
+ const message = error instanceof Error ? error.message : String(error?.message ?? error ?? "");
3677
+ const code = error?.code;
3678
+ const isDecryptPayloadFailure = message.includes("Invalid encrypted payload") || code === -32603 && /encrypt|decrypt|ciphertext/i.test(message);
3679
+ if (isDecryptPayloadFailure || canUseSnapDecrypt) {
3680
+ logger.error(`\u274C Failed to decrypt private balance for ${contractAddress}`, error);
3681
+ throw new CotiPluginError(
3682
+ "AES_KEY_MISMATCH" /* AES_KEY_MISMATCH */,
3683
+ isDecryptPayloadFailure ? "Could not decrypt private balances. The Snap AES key may be missing or invalid \u2014 re-onboarding is required." : "Could not decrypt private balances via Snap. Re-onboarding may be required.",
3684
+ message
3685
+ );
3686
+ }
3675
3687
  logger.error(`\u274C Failed to fetch/decrypt for ${contractAddress}`, error);
3676
3688
  return "0.00";
3677
3689
  }
@@ -4072,7 +4084,7 @@ var useBalanceUpdater = ({
4072
4084
  return { symbol: token.symbol, value, isMismatch: false };
4073
4085
  } catch (e) {
4074
4086
  const msg = e?.message || "";
4075
- const isMismatch = msg.includes("AES key mismatch") || msg.includes("onboarding") || msg.includes("ACCOUNT_NOT_ONBOARDED") || msg.includes("implausible decrypted balance");
4087
+ const isMismatch = e instanceof CotiPluginError && (e.code === "AES_KEY_MISMATCH" /* AES_KEY_MISMATCH */ || e.code === "ACCOUNT_NOT_ONBOARDED" /* ACCOUNT_NOT_ONBOARDED */) || msg.includes("AES key mismatch") || msg.includes("Invalid encrypted payload") || msg.includes("onboarding") || msg.includes("ACCOUNT_NOT_ONBOARDED") || msg.includes("implausible decrypted balance");
4076
4088
  if (isMismatch) {
4077
4089
  logger.warn(`\u26A0\uFE0F Private token decrypt mismatch for ${tokenAddress}. Falling back to 0.`);
4078
4090
  return { symbol: token.symbol, value: "0", isMismatch: true };
@@ -7363,7 +7375,7 @@ var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7363
7375
  function useAesKeyProvider(walletTypeInfo) {
7364
7376
  const [isOnboarding, setIsOnboarding] = useState10(false);
7365
7377
  const [onboardingError, setOnboardingError] = useState10(null);
7366
- const [onboardingWarning, setOnboardingWarning] = useState10(null);
7378
+ const [onboardingWarnings, setOnboardingWarnings] = useState10({});
7367
7379
  const [wasRestoreCancelled, setWasRestoreCancelled] = useState10(false);
7368
7380
  const [currentStep, setCurrentStep] = useState10("idle");
7369
7381
  const progressCallbackRef = useRef7();
@@ -7384,7 +7396,7 @@ function useAesKeyProvider(walletTypeInfo) {
7384
7396
  progressCallbackRef.current = onProgress ?? options.onProgress;
7385
7397
  setOnboardingError(null);
7386
7398
  debugTraceRef.current.clear();
7387
- setOnboardingWarning(null);
7399
+ setOnboardingWarnings({});
7388
7400
  setWasRestoreCancelled(false);
7389
7401
  const forceContractOnboarding = options?.forceContractOnboarding === true;
7390
7402
  if (!forceContractOnboarding) {
@@ -7493,7 +7505,9 @@ function useAesKeyProvider(walletTypeInfo) {
7493
7505
  }
7494
7506
  } catch (restoreError) {
7495
7507
  if (isUserRejection(restoreError)) {
7496
- setOnboardingWarning("Backup restore was cancelled. Approve the wallet signature to unlock from your encrypted backup.");
7508
+ setOnboardingWarnings({
7509
+ intro: "Backup restore was cancelled. Approve the wallet signature to unlock from your encrypted backup."
7510
+ });
7497
7511
  setWasRestoreCancelled(true);
7498
7512
  options.onRestoreCancelled?.();
7499
7513
  emitStep("idle");
@@ -7502,7 +7516,9 @@ function useAesKeyProvider(walletTypeInfo) {
7502
7516
  const message = restoreError instanceof Error ? restoreError.message : "Encrypted AES backup could not be restored.";
7503
7517
  logger.warn("\u26A0\uFE0F AES backup restore failed, falling back to contract onboarding:", restoreError);
7504
7518
  restoreBackupFailed = true;
7505
- setOnboardingWarning(`Encrypted backup could not be restored. Continuing with onboarding. ${message}`);
7519
+ setOnboardingWarnings({
7520
+ intro: `Encrypted backup could not be restored. Continuing with onboarding. ${message}`
7521
+ });
7506
7522
  }
7507
7523
  }
7508
7524
  if (options.restoreOnly) {
@@ -7663,9 +7679,9 @@ function useAesKeyProvider(walletTypeInfo) {
7663
7679
  savedToSnap = await saveAESKeyToSnap(aesKey, address);
7664
7680
  if (!savedToSnap) {
7665
7681
  logger.warn("\u26A0\uFE0F AES key retrieved but could not persist to Snap");
7666
- setOnboardingWarning(
7667
- "Onboarding succeeded, but the AES key could not be saved to MetaMask Snap. You can retry by unlocking again."
7668
- );
7682
+ setOnboardingWarnings({
7683
+ success: "Onboarding succeeded, but the AES key could not be saved to MetaMask Snap. You can retry by unlocking again."
7684
+ });
7669
7685
  }
7670
7686
  } else if (aesKey && walletTypeInfo.walletType === "metamask" && canPersistAesKeyToSnap() && !walletTypeInfo.isMetaMaskWithSnap) {
7671
7687
  logger.log(
@@ -7687,14 +7703,14 @@ function useAesKeyProvider(walletTypeInfo) {
7687
7703
  "\u26A0\uFE0F AES key retrieved but encrypted backup save failed:",
7688
7704
  backupResult.message
7689
7705
  );
7690
- setOnboardingWarning(
7691
- `Onboarding succeeded, but encrypted backup was not saved. ${backupResult.message}`
7692
- );
7706
+ setOnboardingWarnings({
7707
+ success: `Onboarding succeeded, but encrypted backup was not saved. ${backupResult.message}`
7708
+ });
7693
7709
  } else if (backupResult.status === "cancelled") {
7694
7710
  logger.warn("\u26A0\uFE0F AES key retrieved but encrypted backup save was cancelled");
7695
- setOnboardingWarning(
7696
- "Onboarding succeeded, but encrypted backup save was cancelled. You can save it later by re-entering your AES key."
7697
- );
7711
+ setOnboardingWarnings({
7712
+ success: "Onboarding succeeded, but encrypted backup save was cancelled. You can save it later by re-entering your AES key."
7713
+ });
7698
7714
  }
7699
7715
  }
7700
7716
  if (aesKey && isValidAesKey(aesKey)) {
@@ -7758,7 +7774,7 @@ function useAesKeyProvider(walletTypeInfo) {
7758
7774
  getAesKey,
7759
7775
  isOnboarding,
7760
7776
  onboardingError,
7761
- onboardingWarning,
7777
+ onboardingWarnings,
7762
7778
  wasRestoreCancelled,
7763
7779
  currentStep
7764
7780
  };
@@ -7866,7 +7882,7 @@ var usePrivacyBridgeSessionCore = ({
7866
7882
  getAesKey: getAesKeyFromProvider,
7867
7883
  isOnboarding,
7868
7884
  onboardingError,
7869
- onboardingWarning
7885
+ onboardingWarnings
7870
7886
  } = useAesKeyProvider(walletTypeInfo);
7871
7887
  const { fetchPrivateBalance } = usePrivateTokenBalance();
7872
7888
  useEffect9(() => {
@@ -7922,7 +7938,7 @@ var usePrivacyBridgeSessionCore = ({
7922
7938
  fetchPrivateBalance,
7923
7939
  getAesKeyFromProvider,
7924
7940
  onboardingError,
7925
- onboardingWarning
7941
+ onboardingWarnings
7926
7942
  };
7927
7943
  };
7928
7944
 
@@ -8554,6 +8570,7 @@ var usePrivacyBridgeWalletConnection = ({
8554
8570
  };
8555
8571
 
8556
8572
  // src/context/privacyBridge/usePrivacyBridgeUnlockSession.ts
8573
+ init_plugin();
8557
8574
  init_logger();
8558
8575
  import { useCallback as useCallback17 } from "react";
8559
8576
  import { useAccount as useAccount9 } from "wagmi";
@@ -8825,6 +8842,13 @@ var usePrivacyBridgeUnlockSession = ({
8825
8842
  }, [resolveAesAccess, resolveSessionAesKey, walletAddress, aesKeyChainId, checkSnapStatus, hasAesKeyInSnap, walletTypeInfo.walletType, currentChainId]);
8826
8843
  const refreshPrivateBalances = useCallback17(async (aesKeyOptions) => {
8827
8844
  if (!walletAddress) return false;
8845
+ const lockSessionOnAesFailure = !aesKeyOptions?.preserveSessionOnError;
8846
+ const clearSessionAfterAesFailure = () => {
8847
+ setSessionAesKey(null);
8848
+ clearAesKeyValidatedForUnlock(walletAddress);
8849
+ clearSnapCache();
8850
+ setArePrivateBalancesHidden(true);
8851
+ };
8828
8852
  logger.log("Triggering private balance fetch...");
8829
8853
  try {
8830
8854
  const chainOverride = wagmiSyncRef.current ? wagmiChainId : void 0;
@@ -8903,10 +8927,7 @@ var usePrivacyBridgeUnlockSession = ({
8903
8927
  );
8904
8928
  }
8905
8929
  if (errorInfo.message?.includes("ACCOUNT_NOT_ONBOARDED")) {
8906
- setSessionAesKey(null);
8907
- clearAesKeyValidatedForUnlock(walletAddress);
8908
- clearSnapCache();
8909
- setArePrivateBalancesHidden(true);
8930
+ if (lockSessionOnAesFailure) clearSessionAfterAesFailure();
8910
8931
  throw new CotiPluginError(
8911
8932
  "ACCOUNT_NOT_ONBOARDED" /* ACCOUNT_NOT_ONBOARDED */,
8912
8933
  "Account has not been onboarded to the COTI network.",
@@ -8914,17 +8935,11 @@ var usePrivacyBridgeUnlockSession = ({
8914
8935
  );
8915
8936
  }
8916
8937
  if (err instanceof CotiPluginError && err.code === "AES_KEY_MISMATCH" /* AES_KEY_MISMATCH */) {
8917
- setSessionAesKey(null);
8918
- clearAesKeyValidatedForUnlock(walletAddress);
8919
- clearSnapCache();
8920
- setArePrivateBalancesHidden(true);
8938
+ if (lockSessionOnAesFailure) clearSessionAfterAesFailure();
8921
8939
  throw err;
8922
8940
  }
8923
8941
  if (errorInfo.message?.includes("AES key") || errorInfo.message?.includes("onboarding")) {
8924
- setSessionAesKey(null);
8925
- clearAesKeyValidatedForUnlock(walletAddress);
8926
- clearSnapCache();
8927
- setArePrivateBalancesHidden(true);
8942
+ if (lockSessionOnAesFailure) clearSessionAfterAesFailure();
8928
8943
  throw new CotiPluginError(
8929
8944
  "AES_KEY_MISMATCH" /* AES_KEY_MISMATCH */,
8930
8945
  "AES key mismatch or onboarding error.",
@@ -8969,7 +8984,13 @@ var usePrivacyBridgeUnlockSession = ({
8969
8984
  hasSnap: strategy.snapInstalled,
8970
8985
  getAESKeyFromSnap: strategy.snapInstalled ? getAESKeyFromSnap : void 0
8971
8986
  });
8972
- await refreshPrivateBalances();
8987
+ if (getPluginConfig().waitForBalanceRefreshAfterTransfer) {
8988
+ await refreshPrivateBalances();
8989
+ } else {
8990
+ void refreshPrivateBalances({ preserveSessionOnError: true }).catch(
8991
+ (err) => logger.error("Background balance refresh after transfer failed", err)
8992
+ );
8993
+ }
8973
8994
  return result;
8974
8995
  }, [
8975
8996
  walletAddress,
@@ -9119,7 +9140,7 @@ var usePrivacyBridgeSession = ({ modals }) => {
9119
9140
  refreshPublicBalances: unlock.refreshPublicBalances,
9120
9141
  refreshPrivateBalances: unlock.refreshPrivateBalances,
9121
9142
  onboardingError: core.onboardingError,
9122
- onboardingWarning: core.onboardingWarning,
9143
+ onboardingWarnings: core.onboardingWarnings,
9123
9144
  lockPrivateBalances: unlock.lockPrivateBalances,
9124
9145
  saveManualAesKey: unlock.saveManualAesKey,
9125
9146
  sendPrivateToken: unlock.sendPrivateToken,
@@ -9492,6 +9513,40 @@ function deriveOnboardScreen({
9492
9513
 
9493
9514
  // src/components/OnboardModal.tsx
9494
9515
  init_logger();
9516
+
9517
+ // src/lib/onboardModalWarnings.ts
9518
+ function mergeOnboardModalWarnings(...sources) {
9519
+ const merged = {};
9520
+ for (const source of sources) {
9521
+ if (!source) continue;
9522
+ for (const page of Object.keys(source)) {
9523
+ const message = source[page];
9524
+ if (message) {
9525
+ merged[page] = message;
9526
+ }
9527
+ }
9528
+ }
9529
+ return merged;
9530
+ }
9531
+ function getDefaultSuccessWarning(saveBackup) {
9532
+ return saveBackup ? "Important: An encrypted backup can help restore this key later, but you should still store it safely." : "Important: This key will be lost when you refresh the page. Store it in a secure location.";
9533
+ }
9534
+ function resolveOnboardPageWarning(page, options) {
9535
+ const runtime = options.runtimeWarnings?.[page]?.trim();
9536
+ if (runtime) return runtime;
9537
+ const app = options.warnings?.[page]?.trim();
9538
+ if (app) return app;
9539
+ if (page === "success") {
9540
+ return getDefaultSuccessWarning(options.saveBackup ?? true);
9541
+ }
9542
+ return null;
9543
+ }
9544
+ function hasOnboardModalWarnings(warnings) {
9545
+ if (!warnings) return false;
9546
+ return Object.values(warnings).some((message) => !!message?.trim());
9547
+ }
9548
+
9549
+ // src/components/OnboardModal.tsx
9495
9550
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9496
9551
  var defaultStyles = {
9497
9552
  backdrop: {
@@ -9663,28 +9718,23 @@ var defaultStyles = {
9663
9718
  },
9664
9719
  saveOptionBody: {
9665
9720
  flex: 1,
9666
- minWidth: 0
9721
+ minWidth: 0,
9722
+ display: "flex",
9723
+ alignItems: "center",
9724
+ minHeight: "32px"
9667
9725
  },
9668
9726
  saveOptionTitleRow: {
9669
9727
  display: "flex",
9670
9728
  alignItems: "center",
9671
- gap: "5px",
9672
- marginBottom: "2px"
9729
+ gap: "5px"
9673
9730
  },
9674
9731
  saveOptionTitle: {
9675
9732
  fontSize: "13px",
9676
9733
  fontWeight: 600,
9677
- lineHeight: 1.25,
9678
- color: "#ffffff"
9679
- },
9680
- saveOptionDescription: {
9681
- fontSize: "11px",
9682
- lineHeight: 1.3,
9683
- color: "rgba(255, 255, 255, 0.55)",
9684
- margin: 0,
9685
- whiteSpace: "nowrap",
9686
- overflow: "hidden",
9687
- textOverflow: "ellipsis"
9734
+ lineHeight: "14px",
9735
+ color: "#ffffff",
9736
+ display: "inline-flex",
9737
+ alignItems: "center"
9688
9738
  },
9689
9739
  saveOptionSwitchTrack: {
9690
9740
  position: "relative",
@@ -9726,12 +9776,13 @@ var defaultStyles = {
9726
9776
  tooltipButton: {
9727
9777
  width: "14px",
9728
9778
  height: "14px",
9779
+ boxSizing: "border-box",
9729
9780
  borderRadius: "50%",
9730
9781
  border: "1px solid rgba(255, 255, 255, 0.25)",
9731
9782
  backgroundColor: "rgba(255, 255, 255, 0.08)",
9732
9783
  color: "rgba(255, 255, 255, 0.8)",
9733
9784
  fontSize: "9px",
9734
- lineHeight: 1,
9785
+ lineHeight: "12px",
9735
9786
  padding: 0,
9736
9787
  cursor: "help",
9737
9788
  flexShrink: 0,
@@ -10035,8 +10086,7 @@ var MUTED_TEXT_KEYS = [
10035
10086
  "closeButton",
10036
10087
  "tooltipButton",
10037
10088
  "cancelButton",
10038
- "stepDescription",
10039
- "saveOptionDescription"
10089
+ "stepDescription"
10040
10090
  ];
10041
10091
  var ACCENT_TEXT_KEYS = [
10042
10092
  "keyInput",
@@ -10086,7 +10136,8 @@ var LIGHT_INTERACTIVE_SURFACE_KEYS = [
10086
10136
  "saveOptionCard",
10087
10137
  "saveOptionIconWrap",
10088
10138
  "saveOptionSwitchTrackOff",
10089
- "saveOptionSwitchTrackOn"
10139
+ "saveOptionSwitchTrackOn",
10140
+ "tooltipButton"
10090
10141
  ];
10091
10142
  function isDefaultDarkSurfaceBackground(backgroundColor) {
10092
10143
  if (!backgroundColor) return true;
@@ -10170,6 +10221,11 @@ function applyLightInteractiveSurfaceGaps(merged, theme) {
10170
10221
  saveOptionSwitchTrackOn: {
10171
10222
  backgroundColor: primary,
10172
10223
  borderColor: colorWithAlpha(primary, 0.45)
10224
+ },
10225
+ tooltipButton: {
10226
+ color: muted2,
10227
+ backgroundColor: colorWithAlpha(foreground, 0.08),
10228
+ border: `1px solid ${colorWithAlpha(foreground, 0.2)}`
10173
10229
  }
10174
10230
  };
10175
10231
  for (const key of LIGHT_INTERACTIVE_SURFACE_KEYS) {
@@ -10316,7 +10372,8 @@ var OnboardModal = ({
10316
10372
  showSaveBackupOption = true,
10317
10373
  onSaveBackupChange,
10318
10374
  onManualAesKeySubmit,
10319
- warning,
10375
+ warnings,
10376
+ runtimeWarnings,
10320
10377
  theme
10321
10378
  }) => {
10322
10379
  const [copied, setCopied] = useState14(false);
@@ -10362,6 +10419,15 @@ var OnboardModal = ({
10362
10419
  /* @__PURE__ */ jsx("div", { style: styles2.iconContainer, children: icon }),
10363
10420
  /* @__PURE__ */ jsx("h2", { id: "onboard-modal-title", style: styles2.title, children: title })
10364
10421
  ] });
10422
+ const renderPageWarning = (page) => {
10423
+ const message = resolveOnboardPageWarning(page, {
10424
+ warnings,
10425
+ runtimeWarnings,
10426
+ saveBackup
10427
+ });
10428
+ if (!message) return null;
10429
+ return /* @__PURE__ */ jsx("div", { style: warningStyles.box, children: /* @__PURE__ */ jsx("p", { style: warningStyles.text, children: message }) });
10430
+ };
10365
10431
  const renderSaveLocallyOption = () => {
10366
10432
  if (!showSaveBackupOption) return null;
10367
10433
  return /* @__PURE__ */ jsxs(
@@ -10373,29 +10439,26 @@ var OnboardModal = ({
10373
10439
  },
10374
10440
  children: [
10375
10441
  /* @__PURE__ */ jsx("div", { style: styles2.saveOptionIconWrap, "aria-hidden": "true", children: /* @__PURE__ */ jsx("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0 3 3L22 7l-3-3m-3.5 3.5L19 4" }) }) }),
10376
- /* @__PURE__ */ jsxs("div", { style: styles2.saveOptionBody, children: [
10377
- /* @__PURE__ */ jsxs("div", { style: styles2.saveOptionTitleRow, children: [
10378
- /* @__PURE__ */ jsx("span", { style: styles2.saveOptionTitle, children: "Save Locally" }),
10379
- /* @__PURE__ */ jsxs("span", { style: styles2.tooltipWrap, children: [
10380
- /* @__PURE__ */ jsx(
10381
- "button",
10382
- {
10383
- type: "button",
10384
- "aria-label": "How local save works",
10385
- "aria-describedby": showBackupTooltip ? "backup-details-tooltip" : void 0,
10386
- onMouseEnter: () => setShowBackupTooltip(true),
10387
- onMouseLeave: () => setShowBackupTooltip(false),
10388
- onFocus: () => setShowBackupTooltip(true),
10389
- onBlur: () => setShowBackupTooltip(false),
10390
- style: styles2.tooltipButton,
10391
- children: "?"
10392
- }
10393
- ),
10394
- showBackupTooltip && /* @__PURE__ */ jsx("span", { id: "backup-details-tooltip", role: "tooltip", style: styles2.tooltipBubble, children: "Only an encrypted blob is stored locally. Restoring it requires a wallet signature." })
10395
- ] })
10396
- ] }),
10397
- /* @__PURE__ */ jsx("p", { style: styles2.saveOptionDescription, children: "Encrypted locally. Restore via wallet signature." })
10398
- ] }),
10442
+ /* @__PURE__ */ jsx("div", { style: styles2.saveOptionBody, children: /* @__PURE__ */ jsxs("div", { style: styles2.saveOptionTitleRow, children: [
10443
+ /* @__PURE__ */ jsx("span", { style: styles2.saveOptionTitle, children: "Save Locally" }),
10444
+ /* @__PURE__ */ jsxs("span", { style: styles2.tooltipWrap, children: [
10445
+ /* @__PURE__ */ jsx(
10446
+ "button",
10447
+ {
10448
+ type: "button",
10449
+ "aria-label": "How local save works",
10450
+ "aria-describedby": showBackupTooltip ? "backup-details-tooltip" : void 0,
10451
+ onMouseEnter: () => setShowBackupTooltip(true),
10452
+ onMouseLeave: () => setShowBackupTooltip(false),
10453
+ onFocus: () => setShowBackupTooltip(true),
10454
+ onBlur: () => setShowBackupTooltip(false),
10455
+ style: styles2.tooltipButton,
10456
+ children: "?"
10457
+ }
10458
+ ),
10459
+ showBackupTooltip && /* @__PURE__ */ jsx("span", { id: "backup-details-tooltip", role: "tooltip", style: styles2.tooltipBubble, children: "Only an encrypted blob is stored locally. Restoring it requires a wallet signature." })
10460
+ ] })
10461
+ ] }) }),
10399
10462
  /* @__PURE__ */ jsx(
10400
10463
  "button",
10401
10464
  {
@@ -10591,7 +10654,7 @@ var OnboardModal = ({
10591
10654
  "Onboard User"
10592
10655
  ),
10593
10656
  /* @__PURE__ */ jsx("p", { id: "onboard-modal-description", style: styles2.description, children: "This will execute a transaction on the COTI Network to retrieve your encryption key." }),
10594
- warning && /* @__PURE__ */ jsx("div", { style: warningStyles.box, children: /* @__PURE__ */ jsx("p", { style: warningStyles.text, children: warning }) }),
10657
+ renderPageWarning("intro"),
10595
10658
  renderSaveLocallyOption(),
10596
10659
  /* @__PURE__ */ jsxs(
10597
10660
  "div",
@@ -10608,7 +10671,7 @@ var OnboardModal = ({
10608
10671
  type: "text",
10609
10672
  value: manualAesKey,
10610
10673
  onChange: (event) => setManualAesKey(event.target.value),
10611
- placeholder: "Paste AES key",
10674
+ placeholder: "Paste key",
10612
10675
  "aria-label": "Manual AES key",
10613
10676
  disabled: isSubmittingManualKey,
10614
10677
  style: { ...styles2.manualKeyInput, ...styles2.actionPrimary },
@@ -10682,7 +10745,7 @@ var OnboardModal = ({
10682
10745
  /* @__PURE__ */ jsx("div", { style: styles2.spinner }),
10683
10746
  getProgressTitle(currentStep)
10684
10747
  ),
10685
- warning && /* @__PURE__ */ jsx("div", { style: warningStyles.box, children: /* @__PURE__ */ jsx("p", { style: warningStyles.text, children: warning }) }),
10748
+ renderPageWarning("progress"),
10686
10749
  /* @__PURE__ */ jsx("div", { style: styles2.stepperContainer, children: displaySteps.map((step) => {
10687
10750
  const status = getOnboardingStepStatus(step.id, currentStep, !!error, includePersistStep);
10688
10751
  const isActive = status === "active";
@@ -10780,12 +10843,7 @@ var OnboardModal = ({
10780
10843
  )
10781
10844
  ] })
10782
10845
  ] }),
10783
- /* @__PURE__ */ jsx("div", { style: warningStyles.box, children: /* @__PURE__ */ jsxs("p", { style: warningStyles.text, children: [
10784
- /* @__PURE__ */ jsx("strong", { children: "Important:" }),
10785
- " ",
10786
- saveBackup ? "An encrypted backup can help restore this key later, but you should still store it safely." : "This key will be lost when you refresh the page. Store it in a secure location."
10787
- ] }) }),
10788
- warning && /* @__PURE__ */ jsx("div", { style: warningStyles.box, children: /* @__PURE__ */ jsx("p", { style: warningStyles.text, children: warning }) }),
10846
+ renderPageWarning("success"),
10789
10847
  /* @__PURE__ */ jsx(
10790
10848
  "button",
10791
10849
  {
@@ -10819,6 +10877,7 @@ var OnboardModal = ({
10819
10877
  ),
10820
10878
  /* @__PURE__ */ jsx("p", { id: "onboard-modal-description", style: styles2.description, children: "The onboarding process encountered an error. You can retry the signature request." }),
10821
10879
  /* @__PURE__ */ jsx("div", { style: styles2.errorBox, children: /* @__PURE__ */ jsx("p", { style: styles2.errorText, children: error || "An unknown error occurred" }) }),
10880
+ renderPageWarning("error"),
10822
10881
  /* @__PURE__ */ jsx(
10823
10882
  "button",
10824
10883
  {
@@ -10929,14 +10988,14 @@ function keepForwardContractProgress(previous, next) {
10929
10988
  return nextOrder >= previousOrder ? next : previous;
10930
10989
  }
10931
10990
  function usePrivateUnlockController(options = {}) {
10932
- const { theme, warning, onUnlocked, onRestoreCancelled, onOnboardingCancelled } = options;
10991
+ const { theme, warnings, onUnlocked, onRestoreCancelled, onOnboardingCancelled } = options;
10933
10992
  const unlock = usePrivacyBridgeUnlock();
10934
10993
  const wallet = usePrivacyBridgeWallet();
10935
10994
  const walletTypeInfo = useWalletType();
10936
10995
  const [showOnboardModal, setShowOnboardModal] = useState15(false);
10937
10996
  const [isUnlocking, setIsUnlocking] = useState15(false);
10938
10997
  const [modalError, setModalError] = useState15(null);
10939
- const [modalWarning, setModalWarning] = useState15(null);
10998
+ const [modalRuntimeWarnings, setModalRuntimeWarnings] = useState15({});
10940
10999
  const [snapConnectedInModal, setSnapConnectedInModal] = useState15(false);
10941
11000
  const [saveBackup, setSaveBackup] = useState15(true);
10942
11001
  const [currentStep, setCurrentStep] = useState15("idle");
@@ -10973,7 +11032,7 @@ function usePrivateUnlockController(options = {}) {
10973
11032
  pendingActionOwnerRef.current = null;
10974
11033
  setCurrentStep("idle");
10975
11034
  setModalError(null);
10976
- setModalWarning(null);
11035
+ setModalRuntimeWarnings({});
10977
11036
  backupSaveProgressStartedAtRef.current = null;
10978
11037
  pendingCompleteRequestIdRef.current = null;
10979
11038
  contractOnboardingCancelledRef.current = false;
@@ -11002,7 +11061,7 @@ function usePrivateUnlockController(options = {}) {
11002
11061
  setShowOnboardModal(false);
11003
11062
  setCurrentStep("idle");
11004
11063
  setModalError(null);
11005
- setModalWarning(null);
11064
+ setModalRuntimeWarnings({});
11006
11065
  setIsUnlockInProgress(false);
11007
11066
  setIsUnlocking(false);
11008
11067
  backupSaveProgressStartedAtRef.current = null;
@@ -11027,7 +11086,7 @@ function usePrivateUnlockController(options = {}) {
11027
11086
  setShowOnboardModal(false);
11028
11087
  setCurrentStep("idle");
11029
11088
  setModalError(null);
11030
- setModalWarning(null);
11089
+ setModalRuntimeWarnings({});
11031
11090
  unlockInProgressOwnerRef.current = null;
11032
11091
  setIsUnlockInProgress(false);
11033
11092
  setIsUnlocking(false);
@@ -11063,14 +11122,18 @@ function usePrivateUnlockController(options = {}) {
11063
11122
  try {
11064
11123
  const connected = await unlock.requestSnapConnection();
11065
11124
  if (!connected) {
11066
- setModalWarning("Snap connection was skipped or rejected. Continuing without Snap storage.");
11125
+ setModalRuntimeWarnings({
11126
+ intro: "Snap connection was skipped or rejected. Continuing without Snap storage."
11127
+ });
11067
11128
  return false;
11068
11129
  }
11069
11130
  snapConnectedInModalRef.current = true;
11070
11131
  setSnapConnectedInModal(true);
11071
11132
  return true;
11072
11133
  } catch {
11073
- setModalWarning("Snap connection failed. Continuing without Snap storage.");
11134
+ setModalRuntimeWarnings({
11135
+ intro: "Snap connection failed. Continuing without Snap storage."
11136
+ });
11074
11137
  return false;
11075
11138
  }
11076
11139
  }, [canAttemptSnapInstall, unlock]);
@@ -11104,15 +11167,13 @@ function usePrivateUnlockController(options = {}) {
11104
11167
  if (failureMessage) {
11105
11168
  setCurrentStep("error");
11106
11169
  setModalError(failureMessage);
11107
- setModalWarning(unlock.onboardingWarning ?? null);
11108
11170
  releaseUnlockInProgress(requestId);
11109
11171
  return;
11110
11172
  }
11111
11173
  setCurrentStep("error");
11112
11174
  setModalError("Onboarding did not complete. Please retry.");
11113
- setModalWarning(unlock.onboardingWarning ?? null);
11114
11175
  releaseUnlockInProgress(requestId);
11115
- }, [dismissOnboardModal, isActiveUnlockRequest, onOnboardingCancelled, releaseUnlockInProgress, unlock.onboardingWarning]);
11176
+ }, [dismissOnboardModal, isActiveUnlockRequest, onOnboardingCancelled, releaseUnlockInProgress]);
11116
11177
  const handleStaleRestoreCompletion = useCallback19((requestId, refreshSucceeded) => {
11117
11178
  clearPendingActionForRequest(requestId);
11118
11179
  const unlocked = refreshSucceeded || isPrivateUnlockedRef.current;
@@ -11128,7 +11189,7 @@ function usePrivateUnlockController(options = {}) {
11128
11189
  setPendingActionForRequest(requestId, pendingAction);
11129
11190
  }
11130
11191
  setModalError(null);
11131
- setModalWarning(null);
11192
+ setModalRuntimeWarnings({});
11132
11193
  inFlightRestoreRequestIdRef.current = requestId;
11133
11194
  setIsUnlocking(true);
11134
11195
  try {
@@ -11162,7 +11223,6 @@ function usePrivateUnlockController(options = {}) {
11162
11223
  return false;
11163
11224
  }
11164
11225
  setCurrentStep("idle");
11165
- setModalWarning(unlock.onboardingWarning ?? null);
11166
11226
  setShowOnboardModal(true);
11167
11227
  return false;
11168
11228
  } catch (error) {
@@ -11224,7 +11284,6 @@ function usePrivateUnlockController(options = {}) {
11224
11284
  contractOnboardingFailureRef.current = failureMessage;
11225
11285
  setCurrentStep("error");
11226
11286
  setModalError(failureMessage);
11227
- setModalWarning(unlock.onboardingWarning ?? null);
11228
11287
  releaseUnlockInProgress(unlockRequestIdRef.current);
11229
11288
  }
11230
11289
  return;
@@ -11236,7 +11295,7 @@ function usePrivateUnlockController(options = {}) {
11236
11295
  if (step === "idle") {
11237
11296
  setModalError(null);
11238
11297
  }
11239
- }, [currentStep, showOnboardModal, releaseUnlockInProgress, unlock.onboardingWarning]);
11298
+ }, [currentStep, showOnboardModal, releaseUnlockInProgress]);
11240
11299
  const showOnboardingComplete = useCallback19((requestId) => {
11241
11300
  if (!isActiveUnlockRequest(requestId)) return;
11242
11301
  pendingCompleteRequestIdRef.current = null;
@@ -11254,7 +11313,7 @@ function usePrivateUnlockController(options = {}) {
11254
11313
  if (!connectedAddress) return;
11255
11314
  const requestId = unlockRequestIdRef.current;
11256
11315
  setModalError(null);
11257
- setModalWarning(null);
11316
+ setModalRuntimeWarnings({});
11258
11317
  setIsUnlocking(true);
11259
11318
  setShowOnboardModal(true);
11260
11319
  setCurrentStep("preparing-onboard");
@@ -11289,7 +11348,7 @@ function usePrivateUnlockController(options = {}) {
11289
11348
  currentStep,
11290
11349
  hasSessionAesKey: !!unlock.sessionAesKey,
11291
11350
  hasOnboardingError: !!unlock.onboardingError,
11292
- hasOnboardingWarning: !!unlock.onboardingWarning
11351
+ hasOnboardingWarning: hasOnboardModalWarnings(unlock.onboardingWarnings)
11293
11352
  });
11294
11353
  const backupSaveProgressStartedAt = backupSaveProgressStartedAtRef.current;
11295
11354
  if (backupSaveProgressStartedAt !== null) {
@@ -11405,7 +11464,7 @@ function usePrivateUnlockController(options = {}) {
11405
11464
  onSaveBackupChange: setSaveBackup,
11406
11465
  onManualAesKeySubmit: async (aesKey, { saveBackup: shouldSaveBackup }) => {
11407
11466
  const requestId = unlockRequestIdRef.current;
11408
- setModalWarning(null);
11467
+ setModalRuntimeWarnings({});
11409
11468
  const manualSaveResult = await unlock.saveManualAesKey(aesKey, {
11410
11469
  saveBackup: shouldSaveBackup,
11411
11470
  onProgress: (step) => {
@@ -11426,7 +11485,7 @@ function usePrivateUnlockController(options = {}) {
11426
11485
  return;
11427
11486
  }
11428
11487
  if (manualSaveResult.backupWarning) {
11429
- setModalWarning(manualSaveResult.backupWarning);
11488
+ setModalRuntimeWarnings({ success: manualSaveResult.backupWarning });
11430
11489
  setShowOnboardModal(true);
11431
11490
  setCurrentStep("complete");
11432
11491
  releaseUnlockInProgress(requestId);
@@ -11435,7 +11494,8 @@ function usePrivateUnlockController(options = {}) {
11435
11494
  await completeUnlock(requestId);
11436
11495
  },
11437
11496
  theme,
11438
- warning: modalWarning ?? unlock.onboardingWarning ?? warning ?? null
11497
+ warnings,
11498
+ runtimeWarnings: mergeOnboardModalWarnings(unlock.onboardingWarnings, modalRuntimeWarnings)
11439
11499
  }
11440
11500
  );
11441
11501
  return {
@@ -11608,7 +11668,7 @@ var PrivacyBridgeProvider = ({
11608
11668
  decryptPrivateValue: session.decryptPrivateValue,
11609
11669
  refreshPrivateBalances: session.refreshPrivateBalances,
11610
11670
  onboardingError: session.onboardingError,
11611
- onboardingWarning: session.onboardingWarning,
11671
+ onboardingWarnings: session.onboardingWarnings,
11612
11672
  lockPrivateBalances: session.lockPrivateBalances,
11613
11673
  handleOnboard: session.handleOnboard,
11614
11674
  saveManualAesKey: session.saveManualAesKey,