@coti-io/coti-wallet-plugin 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -546,10 +546,10 @@ function configureCotiPlugin(config) {
546
546
  ...config.onboardingServices
547
547
  }
548
548
  };
549
- if ("snapInstallEnabled" in config && _config.debug) {
550
- console.log("[CotiPlugin] snapInstallEnabled:", {
551
- snapInstallEnabled: config.snapInstallEnabled,
552
- effective: isSnapInstallEnabled()
549
+ if ("snapEnabled" in config && _config.debug) {
550
+ console.log("[CotiPlugin] snapEnabled:", {
551
+ snapEnabled: config.snapEnabled,
552
+ effective: isSnapEnabled()
553
553
  });
554
554
  }
555
555
  }
@@ -560,8 +560,8 @@ function getSnapRequestParams(snapId = _config.snapId, snapVersion) {
560
560
  function getPluginConfig() {
561
561
  return _config;
562
562
  }
563
- function isSnapInstallEnabled() {
564
- return getPluginConfig().snapInstallEnabled !== false;
563
+ function isSnapEnabled() {
564
+ return getPluginConfig().snapEnabled !== false;
565
565
  }
566
566
  var _config;
567
567
  var init_plugin = __esm({
@@ -570,7 +570,7 @@ var init_plugin = __esm({
570
570
  init_chains();
571
571
  _config = {
572
572
  snapId: "npm:@coti-io/coti-snap",
573
- snapInstallEnabled: true,
573
+ snapEnabled: true,
574
574
  defaultNetworkId: void 0,
575
575
  debug: false,
576
576
  clearSessionKeyOnWagmiDisconnect: false,
@@ -1400,6 +1400,7 @@ var resolveBridgeAddress = (chainId, symbol, pubTok) => {
1400
1400
  if (symbol === "USDC.e") return addresses.PrivacyBridgeUSDCe;
1401
1401
  if (symbol === "WADA") return addresses.PrivacyBridgeWADA;
1402
1402
  if (symbol === "gCOTI") return addresses.PrivacyBridgegCOTI;
1403
+ if (symbol === "NIGHT") return addresses.PrivacyBridgeNight;
1403
1404
  return addresses.PrivacyBridgeCotiNative;
1404
1405
  };
1405
1406
  var quoteCotiBridgeFees = async (params) => {
@@ -1431,7 +1432,7 @@ var quoteCotiBridgeFees = async (params) => {
1431
1432
  if (isWbtc) {
1432
1433
  publicDecimals = 8;
1433
1434
  privateDecimals = 8;
1434
- } else if (isUsdt || isUsdcE || isWada) {
1435
+ } else if (isUsdt || isUsdcE || isWada || isNight) {
1435
1436
  publicDecimals = 6;
1436
1437
  privateDecimals = 6;
1437
1438
  }
@@ -3673,6 +3674,17 @@ var usePrivateTokenBalance = () => {
3673
3674
  if (error instanceof CotiPluginError) {
3674
3675
  throw error;
3675
3676
  }
3677
+ const message = error instanceof Error ? error.message : String(error?.message ?? error ?? "");
3678
+ const code = error?.code;
3679
+ const isDecryptPayloadFailure = message.includes("Invalid encrypted payload") || code === -32603 && /encrypt|decrypt|ciphertext/i.test(message);
3680
+ if (isDecryptPayloadFailure || canUseSnapDecrypt) {
3681
+ logger.error(`\u274C Failed to decrypt private balance for ${contractAddress}`, error);
3682
+ throw new CotiPluginError(
3683
+ "AES_KEY_MISMATCH" /* AES_KEY_MISMATCH */,
3684
+ 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.",
3685
+ message
3686
+ );
3687
+ }
3676
3688
  logger.error(`\u274C Failed to fetch/decrypt for ${contractAddress}`, error);
3677
3689
  return "0.00";
3678
3690
  }
@@ -4073,7 +4085,7 @@ var useBalanceUpdater = ({
4073
4085
  return { symbol: token.symbol, value, isMismatch: false };
4074
4086
  } catch (e) {
4075
4087
  const msg = e?.message || "";
4076
- const isMismatch = msg.includes("AES key mismatch") || msg.includes("onboarding") || msg.includes("ACCOUNT_NOT_ONBOARDED") || msg.includes("implausible decrypted balance");
4088
+ 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");
4077
4089
  if (isMismatch) {
4078
4090
  logger.warn(`\u26A0\uFE0F Private token decrypt mismatch for ${tokenAddress}. Falling back to 0.`);
4079
4091
  return { symbol: token.symbol, value: "0", isMismatch: true };
@@ -4157,8 +4169,10 @@ var SYMBOL_TO_ORACLE_BASE = {
4157
4169
  USDT: "USDT",
4158
4170
  USDC: "USDC",
4159
4171
  "USDC.e": "USDC",
4160
- WADA: "ADA"
4161
- // gCOTI is not in the on-chain price consumer
4172
+ WADA: "ADA",
4173
+ // Consumer base is uppercase GCOTI (lowercase gCOTI reverts).
4174
+ gCOTI: "GCOTI",
4175
+ NIGHT: "NIGHT"
4162
4176
  };
4163
4177
  function getPriceConsumerAddress(chainId = 7082400) {
4164
4178
  const addresses = CONTRACT_ADDRESSES[chainId];
@@ -4266,7 +4280,8 @@ var TOKEN_TO_ORACLE_SYMBOL = {
4266
4280
  USDT: "USDT",
4267
4281
  "USDC.e": "USDC",
4268
4282
  WADA: "ADA",
4269
- gCOTI: "GCOTI"
4283
+ gCOTI: "GCOTI",
4284
+ NIGHT: "NIGHT"
4270
4285
  };
4271
4286
  var TOKEN_DECIMALS = {
4272
4287
  COTI: 18,
@@ -4275,7 +4290,8 @@ var TOKEN_DECIMALS = {
4275
4290
  USDT: 6,
4276
4291
  "USDC.e": 6,
4277
4292
  WADA: 6,
4278
- gCOTI: 18
4293
+ gCOTI: 18,
4294
+ NIGHT: 6
4279
4295
  };
4280
4296
  async function simulateFeeOnChain(bridgeAddress, amount, fixedFee, percentageBps, maxFee, oracleSymbol, tokenDecimals, provider) {
4281
4297
  try {
@@ -4788,6 +4804,10 @@ var useSnap = (setSnapError) => {
4788
4804
  }
4789
4805
  }, [resolveProvider]);
4790
4806
  const isSnapInstalled = useCallback5(async () => {
4807
+ if (!isSnapEnabled()) {
4808
+ logger.log("\u2139\uFE0F Snap disabled via plugin config \u2014 treating as not installed");
4809
+ return false;
4810
+ }
4791
4811
  const provider = await resolveProvider();
4792
4812
  if (!provider) {
4793
4813
  logger.log("\u274C isSnapInstalled: No MetaMask provider");
@@ -4817,8 +4837,8 @@ var useSnap = (setSnapError) => {
4817
4837
  }
4818
4838
  }, [detectFlask, resolveProvider]);
4819
4839
  const connectToSnap = useCallback5(async () => {
4820
- if (!isSnapInstallEnabled()) {
4821
- logger.log("\u2139\uFE0F Snap install disabled via plugin config");
4840
+ if (!isSnapEnabled()) {
4841
+ logger.log("\u2139\uFE0F Snap disabled via plugin config");
4822
4842
  return false;
4823
4843
  }
4824
4844
  const provider = await resolveProvider();
@@ -4965,6 +4985,13 @@ var useSnap = (setSnapError) => {
4965
4985
  return parseSnapItUint256(result?.value);
4966
4986
  }, [connectedAddress, invokeSnapOperation]);
4967
4987
  const getAESKeyFromSnap = useCallback5(async (accountAddress, options) => {
4988
+ if (!isSnapEnabled()) {
4989
+ logger.log("\u2139\uFE0F Snap disabled via plugin config \u2014 treating as unavailable");
4990
+ throw new CotiPluginError(
4991
+ "SNAP_CONNECT_FAILED" /* SNAP_CONNECT_FAILED */,
4992
+ "COTI Snap is disabled for this app"
4993
+ );
4994
+ }
4968
4995
  if (setSnapError) setSnapError(null);
4969
4996
  const skipCache = options?.skipCache === true;
4970
4997
  if (isSnapRequestPending.current) {
@@ -5101,6 +5128,7 @@ var useSnap = (setSnapError) => {
5101
5128
  }
5102
5129
  }, [isSnapInstalled, setSnapError, resolveProvider, syncEnvironment]);
5103
5130
  const hasAesKeyInSnap = useCallback5(async (accountAddress) => {
5131
+ if (!isSnapEnabled()) return null;
5104
5132
  const provider = await resolveProvider();
5105
5133
  if (!provider) return null;
5106
5134
  const installed = await isSnapInstalled();
@@ -5133,6 +5161,10 @@ var useSnap = (setSnapError) => {
5133
5161
  }
5134
5162
  }, [isSnapInstalled, resolveProvider, syncEnvironment]);
5135
5163
  const saveAESKeyToSnap = useCallback5(async (key, accountAddress = "") => {
5164
+ if (!isSnapEnabled()) {
5165
+ logger.log("\u2139\uFE0F Snap disabled via plugin config \u2014 skipping AES key save");
5166
+ return false;
5167
+ }
5136
5168
  const provider = await resolveProvider();
5137
5169
  if (!provider) return false;
5138
5170
  try {
@@ -6571,7 +6603,7 @@ function useWalletType() {
6571
6603
  const walletType = mapConnectorIdToWalletType(connectorId);
6572
6604
  useEffect6(() => {
6573
6605
  let cancelled = false;
6574
- if (walletType !== "metamask" || !connector) {
6606
+ if (walletType !== "metamask" || !connector || !isSnapEnabled()) {
6575
6607
  setIsMetaMaskWithSnap(false);
6576
6608
  return;
6577
6609
  }
@@ -7660,7 +7692,8 @@ function useAesKeyProvider(walletTypeInfo) {
7660
7692
  }
7661
7693
  }
7662
7694
  let savedToSnap = false;
7663
- const canSaveToConnectedSnap = aesKey && walletTypeInfo.walletType === "metamask" && walletTypeInfo.isMetaMaskWithSnap && canPersistAesKeyToSnap();
7695
+ const shouldPersistToSnap = walletTypeInfo.isMetaMaskWithSnap || options.persistToSnap === true;
7696
+ const canSaveToConnectedSnap = !!aesKey && walletTypeInfo.walletType === "metamask" && shouldPersistToSnap && canPersistAesKeyToSnap();
7664
7697
  const canSaveEncryptedBackup = aesKey && isValidAesKey(aesKey) && options.saveBackup && servicesEnabled && (services?.saveEncryptedAesBackup || services?.replaceEncryptedAesBackup);
7665
7698
  if (canSaveToConnectedSnap) {
7666
7699
  emitStep("persisting-key");
@@ -7672,7 +7705,7 @@ function useAesKeyProvider(walletTypeInfo) {
7672
7705
  success: "Onboarding succeeded, but the AES key could not be saved to MetaMask Snap. You can retry by unlocking again."
7673
7706
  });
7674
7707
  }
7675
- } else if (aesKey && walletTypeInfo.walletType === "metamask" && canPersistAesKeyToSnap() && !walletTypeInfo.isMetaMaskWithSnap) {
7708
+ } else if (aesKey && walletTypeInfo.walletType === "metamask" && canPersistAesKeyToSnap() && !shouldPersistToSnap) {
7676
7709
  logger.log(
7677
7710
  "\u2139\uFE0F Skipping Snap AES persist \u2014 Snap is not connected to this origin"
7678
7711
  );
@@ -7757,7 +7790,17 @@ function useAesKeyProvider(walletTypeInfo) {
7757
7790
  }
7758
7791
  }
7759
7792
  },
7760
- [walletTypeInfo.walletType, getAESKeyFromSnap, saveAESKeyToSnap, clearSnapCache, connector, connectedChainId, emitStep, reportOnboardingFailure]
7793
+ [
7794
+ walletTypeInfo.walletType,
7795
+ walletTypeInfo.isMetaMaskWithSnap,
7796
+ getAESKeyFromSnap,
7797
+ saveAESKeyToSnap,
7798
+ clearSnapCache,
7799
+ connector,
7800
+ connectedChainId,
7801
+ emitStep,
7802
+ reportOnboardingFailure
7803
+ ]
7761
7804
  );
7762
7805
  return {
7763
7806
  getAesKey,
@@ -8140,6 +8183,7 @@ var usePrivacyBridgeNetworkSession = ({
8140
8183
  };
8141
8184
 
8142
8185
  // src/context/privacyBridge/usePrivacyBridgeAccountSync.ts
8186
+ init_plugin();
8143
8187
  import { useCallback as useCallback16, useEffect as useEffect10, useRef as useRef9 } from "react";
8144
8188
  import { useAccount as useAccount8 } from "wagmi";
8145
8189
  init_logger();
@@ -8188,13 +8232,13 @@ var usePrivacyBridgeAccountSync = ({
8188
8232
  );
8189
8233
  const getAESKeyForCurrentNetwork = useCallback16(
8190
8234
  async (accountAddress, options) => {
8191
- if (options?.skipCache && walletTypeInfo.walletType === "metamask" && !options.forceContractOnboarding && !options.restoreOnly) {
8235
+ if (options?.skipCache && walletTypeInfo.walletType === "metamask" && isSnapEnabled() && !options.forceContractOnboarding && !options.restoreOnly) {
8192
8236
  return getAESKeyFromSnap(accountAddress, { skipCache: true });
8193
8237
  }
8194
8238
  if (sessionAesKey && !options?.forceContractOnboarding) return sessionAesKey;
8195
8239
  return options === void 0 ? getAesKeyFromProvider(accountAddress) : getAesKeyFromProvider(accountAddress, options.onProgress, options);
8196
8240
  },
8197
- [sessionAesKey, getAesKeyFromProvider, getAESKeyFromSnap]
8241
+ [sessionAesKey, getAesKeyFromProvider, getAESKeyFromSnap, walletTypeInfo.walletType]
8198
8242
  );
8199
8243
  const { updateAccountState } = useBalanceUpdater({
8200
8244
  setWalletAddress,
@@ -11007,8 +11051,8 @@ function usePrivateUnlockController(options = {}) {
11007
11051
  isPrivateUnlockedRef.current = unlock.isPrivateUnlocked;
11008
11052
  const connectedAddress = wallet.walletAddress || "";
11009
11053
  const isMetaMaskWallet = walletTypeInfo.walletType === "metamask";
11010
- const canAttemptSnapInstall = isMetaMaskWallet && !isMetaMaskMobileBrowser() && isSnapInstallEnabled();
11011
- const usesSnapStorage = canAttemptSnapInstall && (walletTypeInfo.isMetaMaskWithSnap || snapConnectedInModal);
11054
+ const canUseSnap = isMetaMaskWallet && !isMetaMaskMobileBrowser() && isSnapEnabled();
11055
+ const usesSnapStorage = canUseSnap && (walletTypeInfo.isMetaMaskWithSnap || snapConnectedInModal);
11012
11056
  const isActiveUnlockRequest = useCallback19(
11013
11057
  (requestId) => requestId === unlockRequestIdRef.current,
11014
11058
  []
@@ -11106,7 +11150,7 @@ function usePrivateUnlockController(options = {}) {
11106
11150
  dismissOnboardModal();
11107
11151
  }, [dismissOnboardModal, wallet.walletAddress]);
11108
11152
  const connectSnap = useCallback19(async () => {
11109
- if (!canAttemptSnapInstall) return false;
11153
+ if (!canUseSnap) return false;
11110
11154
  setModalError(null);
11111
11155
  try {
11112
11156
  const connected = await unlock.requestSnapConnection();
@@ -11125,7 +11169,7 @@ function usePrivateUnlockController(options = {}) {
11125
11169
  });
11126
11170
  return false;
11127
11171
  }
11128
- }, [canAttemptSnapInstall, unlock]);
11172
+ }, [canUseSnap, unlock]);
11129
11173
  const handleRestoreUnlockProgress = useCallback19((step) => {
11130
11174
  if (step === "signing-backup") {
11131
11175
  setCurrentStep(step);
@@ -11310,7 +11354,7 @@ function usePrivateUnlockController(options = {}) {
11310
11354
  contractOnboardingFailureRef.current = null;
11311
11355
  try {
11312
11356
  let useSnapStorageForOnboarding = usesSnapStorage || snapConnectedInModalRef.current;
11313
- if (!useSnapStorageForOnboarding && canAttemptSnapInstall) {
11357
+ if (!useSnapStorageForOnboarding && canUseSnap) {
11314
11358
  useSnapStorageForOnboarding = await connectSnap();
11315
11359
  }
11316
11360
  if (!isActiveUnlockRequest(requestId)) {
@@ -11319,6 +11363,8 @@ function usePrivateUnlockController(options = {}) {
11319
11363
  const ok = await unlock.refreshPrivateBalances({
11320
11364
  forceContractOnboarding: true,
11321
11365
  saveBackup: useSnapStorageForOnboarding ? false : saveBackup,
11366
+ // Explicit: don't rely on isMetaMaskWithSnap which can lag after connectSnap.
11367
+ persistToSnap: useSnapStorageForOnboarding,
11322
11368
  onProgress: (step, details) => {
11323
11369
  if (isActiveUnlockRequest(requestId)) {
11324
11370
  handleContractOnboardingProgress(step, details);
@@ -11374,7 +11420,7 @@ function usePrivateUnlockController(options = {}) {
11374
11420
  setIsUnlocking(false);
11375
11421
  }
11376
11422
  }
11377
- }, [canAttemptSnapInstall, connectSnap, connectedAddress, currentStep, dismissOnboardModal, handleContractOnboardingProgress, handleOnboardingIncomplete, isActiveUnlockRequest, onOnboardingCancelled, saveBackup, showOnboardingComplete, unlock, usesSnapStorage]);
11423
+ }, [canUseSnap, connectSnap, connectedAddress, currentStep, dismissOnboardModal, handleContractOnboardingProgress, handleOnboardingIncomplete, isActiveUnlockRequest, onOnboardingCancelled, saveBackup, showOnboardingComplete, unlock, usesSnapStorage]);
11378
11424
  const handleOnboardModalClose = useCallback19(() => {
11379
11425
  if (currentStep === "complete" || currentStep === "validating-key" && pendingCompleteRequestIdRef.current !== null) {
11380
11426
  void finishSuccessfulOnboarding();
@@ -12564,7 +12610,7 @@ export {
12564
12610
  isChainUpdatesMuted,
12565
12611
  isCotiPluginError,
12566
12612
  isMultipleWalletsError,
12567
- isSnapInstallEnabled,
12613
+ isSnapEnabled,
12568
12614
  loadPodRequests,
12569
12615
  logger,
12570
12616
  mobileZerionWallet,