@coti-io/coti-wallet-plugin 0.2.3 → 0.2.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
@@ -876,8 +876,192 @@ var init_podSdkConfig = __esm({
876
876
  }
877
877
  });
878
878
 
879
- // src/chains/portal/podPTokenBlockingDiagnostics.ts
879
+ // src/lib/rpcProvider.ts
880
880
  import { ethers as ethers5 } from "ethers";
881
+ async function waitForTransactionResilient(chainId, txHash, options = {}) {
882
+ const {
883
+ confirmations = 1,
884
+ timeoutMs = 18e4,
885
+ pollIntervalMs = 2e3,
886
+ primary,
887
+ createProvider = createJsonRpcProvider
888
+ } = options;
889
+ if (!txHash) {
890
+ throw new Error("waitForTransactionResilient: missing transaction hash");
891
+ }
892
+ const deadline = Date.now() + timeoutMs;
893
+ let lastError;
894
+ if (primary) {
895
+ const remaining = Math.max(0, deadline - Date.now());
896
+ const primaryTimeout = Math.min(12e3, remaining);
897
+ if (primaryTimeout > 0) {
898
+ try {
899
+ const receipt = await primary.waitForTransaction(txHash, confirmations, primaryTimeout);
900
+ if (receipt) return receipt;
901
+ } catch (error) {
902
+ lastError = error;
903
+ if (isTransactionRevertError(error)) throw error;
904
+ if (!isTransientRpcError(error) && !isWaitTimeoutError(error)) throw error;
905
+ logger.warn(
906
+ `[rpc] primary waitForTransaction failed for ${txHash} on chain ${chainId}; polling via fallback RPCs`
907
+ );
908
+ }
909
+ }
910
+ }
911
+ let delay = pollIntervalMs;
912
+ while (Date.now() < deadline) {
913
+ try {
914
+ const receipt = await getTransactionReceiptAcrossRpcs(chainId, txHash, createProvider);
915
+ if (receipt) {
916
+ if (confirmations <= 1) return receipt;
917
+ const blockNumber = await withRpcFallback(chainId, (provider) => provider.getBlockNumber());
918
+ if (receipt.blockNumber + (confirmations - 1) <= blockNumber) {
919
+ return receipt;
920
+ }
921
+ }
922
+ } catch (error) {
923
+ lastError = error;
924
+ if (!isTransientRpcError(error)) throw error;
925
+ logger.warn(
926
+ `[rpc] receipt poll failed for ${txHash} on chain ${chainId}; retrying after backoff`
927
+ );
928
+ }
929
+ const remaining = deadline - Date.now();
930
+ if (remaining <= 0) break;
931
+ await sleep(Math.min(delay, remaining));
932
+ delay = Math.min(Math.floor(delay * 1.5), 8e3);
933
+ }
934
+ throw lastError instanceof Error ? lastError : new Error(
935
+ `Timed out waiting for transaction ${txHash} on chain ${chainId} after ${timeoutMs}ms`
936
+ );
937
+ }
938
+ async function getTransactionReceiptAcrossRpcs(chainId, txHash, createProvider = createJsonRpcProvider) {
939
+ const urls = resolveRpcUrlsForChain(chainId);
940
+ let lastError;
941
+ let sawNotFound = false;
942
+ for (const url of urls) {
943
+ const provider = createProvider(url, chainId);
944
+ try {
945
+ const receipt = await provider.getTransactionReceipt(txHash);
946
+ if (receipt) return receipt;
947
+ sawNotFound = true;
948
+ } catch (error) {
949
+ lastError = error;
950
+ if (!isTransientRpcError(error)) throw error;
951
+ logger.warn(`[rpc] ${url} getTransactionReceipt failed for chain ${chainId}, trying fallback`);
952
+ }
953
+ }
954
+ if (sawNotFound) return null;
955
+ throw lastError instanceof Error ? lastError : new Error(`All RPC endpoints failed reading receipt for ${txHash} on chain ${chainId}`);
956
+ }
957
+ var resolveRpcUrlsForChain, collectErrorText, readNestedRpcCode, readNestedHttpStatus, isTransientRpcError, createJsonRpcProvider, isWaitTimeoutError, isTransactionRevertError, sleep, createResilientJsonRpcProvider, withRpcFallback;
958
+ var init_rpcProvider = __esm({
959
+ "src/lib/rpcProvider.ts"() {
960
+ "use strict";
961
+ init_plugin();
962
+ init_coti();
963
+ init_rpcUrls();
964
+ init_sepolia();
965
+ init_logger();
966
+ resolveRpcUrlsForChain = (chainId) => {
967
+ const base = getRpcUrlsForChain(chainId);
968
+ const numericId = chainId == null ? void 0 : Number(chainId);
969
+ if (numericId == null || !Number.isFinite(numericId)) return base;
970
+ const plugin = getPluginConfig();
971
+ let override;
972
+ if (numericId === SEPOLIA_CHAIN_ID && plugin.sepoliaRpcUrl) {
973
+ override = plugin.sepoliaRpcUrl;
974
+ } else if (numericId === COTI_TESTNET_CHAIN_ID && plugin.cotiTestnetRpcUrl) {
975
+ override = plugin.cotiTestnetRpcUrl;
976
+ }
977
+ if (!override) return base;
978
+ return [.../* @__PURE__ */ new Set([override, ...base])];
979
+ };
980
+ collectErrorText = (error) => {
981
+ if (!error) return "";
982
+ if (typeof error === "string") return error;
983
+ if (error instanceof Error) return error.message;
984
+ try {
985
+ return JSON.stringify(error);
986
+ } catch {
987
+ return String(error);
988
+ }
989
+ };
990
+ readNestedRpcCode = (error) => {
991
+ const e = error;
992
+ return e.code ?? e.error?.code ?? e.info?.error?.code;
993
+ };
994
+ readNestedHttpStatus = (error) => {
995
+ const e = error;
996
+ return e.data?.httpStatus ?? e.error?.data?.httpStatus ?? e.info?.responseStatus;
997
+ };
998
+ isTransientRpcError = (error) => {
999
+ const text = collectErrorText(error);
1000
+ const lower = text.toLowerCase();
1001
+ if (lower.includes("too many requests") || lower.includes("rate limit") || text.includes("-32005") || text.includes("ECONNRESET") || text.includes("ETIMEDOUT") || lower.includes("timeout") || text.includes("503") || text.includes("502") || text.includes("429")) {
1002
+ return true;
1003
+ }
1004
+ if (error && typeof error === "object") {
1005
+ const code = readNestedRpcCode(error);
1006
+ if (code === "SERVER_ERROR" || code === "TIMEOUT" || code === "NETWORK_ERROR" || code === -32005 || code === "-32005") {
1007
+ return true;
1008
+ }
1009
+ const httpStatus = readNestedHttpStatus(error);
1010
+ if (httpStatus === 429 || httpStatus === "429") {
1011
+ return true;
1012
+ }
1013
+ }
1014
+ return false;
1015
+ };
1016
+ createJsonRpcProvider = (url, chainId) => new ethers5.JsonRpcProvider(url, chainId);
1017
+ isWaitTimeoutError = (error) => {
1018
+ const text = collectErrorText(error).toLowerCase();
1019
+ return text.includes("timeout") || text.includes("timed out") || text.includes("waitfortx");
1020
+ };
1021
+ isTransactionRevertError = (error) => {
1022
+ if (!error || typeof error !== "object") return false;
1023
+ const code = error.code;
1024
+ return code === "CALL_EXCEPTION" || code === "TRANSACTION_REPLACED";
1025
+ };
1026
+ sleep = (ms) => new Promise((resolve) => {
1027
+ setTimeout(resolve, ms);
1028
+ });
1029
+ createResilientJsonRpcProvider = async (chainId) => {
1030
+ const urls = resolveRpcUrlsForChain(chainId);
1031
+ let lastError;
1032
+ for (const url of urls) {
1033
+ const provider = createJsonRpcProvider(url, chainId);
1034
+ try {
1035
+ await provider.getNetwork();
1036
+ return provider;
1037
+ } catch (error) {
1038
+ lastError = error;
1039
+ if (!isTransientRpcError(error)) throw error;
1040
+ logger.warn(`[rpc] ${url} unavailable for chain ${chainId}, trying fallback`);
1041
+ }
1042
+ }
1043
+ throw lastError instanceof Error ? lastError : new Error(`No RPC available for chain ${chainId}`);
1044
+ };
1045
+ withRpcFallback = async (chainId, fn) => {
1046
+ const urls = resolveRpcUrlsForChain(chainId);
1047
+ let lastError;
1048
+ for (const url of urls) {
1049
+ const provider = createJsonRpcProvider(url, chainId);
1050
+ try {
1051
+ return await fn(provider);
1052
+ } catch (error) {
1053
+ lastError = error;
1054
+ if (!isTransientRpcError(error)) throw error;
1055
+ logger.warn(`[rpc] ${url} request failed for chain ${chainId}, trying fallback`);
1056
+ }
1057
+ }
1058
+ throw lastError instanceof Error ? lastError : new Error(`All RPC endpoints failed for chain ${chainId}`);
1059
+ };
1060
+ }
1061
+ });
1062
+
1063
+ // src/chains/portal/podPTokenBlockingDiagnostics.ts
1064
+ import { ethers as ethers6 } from "ethers";
881
1065
  import { PodRequest as PodRequest2 } from "@coti-io/pod-sdk";
882
1066
  async function diagnoseBlockingPodRequest(params) {
883
1067
  const {
@@ -960,8 +1144,8 @@ var init_podPTokenBlockingDiagnostics = __esm({
960
1144
  "callback-errored",
961
1145
  "burn-debt"
962
1146
  ]);
963
- pTokenIface = new ethers5.Interface(POD_PTOKEN_ABI);
964
- portalIface = new ethers5.Interface(PRIVACY_PORTAL_ABI);
1147
+ pTokenIface = new ethers6.Interface(POD_PTOKEN_ABI);
1148
+ portalIface = new ethers6.Interface(PRIVACY_PORTAL_ABI);
965
1149
  formatBlockingPodLogSummary = (blockingRequest, action) => {
966
1150
  if (!blockingRequest?.requestId) {
967
1151
  return `PoD ${action} blocked: wallet has on-chain pending=true but no requestId was resolved (check eventScan / candidateRequests in the log object below).`;
@@ -1090,7 +1274,7 @@ var init_podPTokenBlockingDiagnostics = __esm({
1090
1274
  }
1091
1275
  return { logs: [], lookbackBlocks: Number(lookbackSteps[lookbackSteps.length - 1]), errors };
1092
1276
  };
1093
- paddedAddressTopic = (address) => ethers5.zeroPadValue(ethers5.getAddress(address), 32);
1277
+ paddedAddressTopic = (address) => ethers6.zeroPadValue(ethers6.getAddress(address), 32);
1094
1278
  fetchRecentPTokenEvents = async (provider, pTokenAddress, account) => {
1095
1279
  const accountTopic = paddedAddressTopic(account);
1096
1280
  const errors = [];
@@ -1228,7 +1412,7 @@ var fees_exports = {};
1228
1412
  __export(fees_exports, {
1229
1413
  quotePodPortalTransactionFees: () => quotePodPortalTransactionFees
1230
1414
  });
1231
- import { ethers as ethers6 } from "ethers";
1415
+ import { ethers as ethers7 } from "ethers";
1232
1416
  var quotePodPortalTransactionFees;
1233
1417
  var init_fees = __esm({
1234
1418
  "src/chains/portal/fees.ts"() {
@@ -1238,7 +1422,7 @@ var init_fees = __esm({
1238
1422
  init_podPortalFees();
1239
1423
  quotePodPortalTransactionFees = async (params) => {
1240
1424
  const dec = params.pubTok?.decimals ?? 18;
1241
- const amountWei = ethers6.parseUnits(params.amount, dec);
1425
+ const amountWei = ethers7.parseUnits(params.amount, dec);
1242
1426
  const provider = "provider" in params.runner && params.runner.provider ? params.runner.provider : params.runner;
1243
1427
  const gasPrice = params.gasPrice ?? await resolvePodTxGasPrice(provider);
1244
1428
  const nativeSymbol = getChainConfig(params.chainId)?.walletNetwork.nativeCurrency.symbol ?? "ETH";
@@ -1311,7 +1495,7 @@ var init_fees = __esm({
1311
1495
  });
1312
1496
 
1313
1497
  // src/chains/portal/podPortalFees.ts
1314
- import { ethers as ethers7 } from "ethers";
1498
+ import { ethers as ethers8 } from "ethers";
1315
1499
  import {
1316
1500
  DataType,
1317
1501
  PodContract,
@@ -1352,7 +1536,7 @@ var init_podPortalFees = __esm({
1352
1536
  quotePortalFeeOnly = async (runner, portalAddress, amount, direction, gasPrice) => {
1353
1537
  const provider = resolveFeeRunnerProvider(runner);
1354
1538
  const resolvedGasPrice = gasPrice ?? await resolvePodTxGasPrice(provider);
1355
- const portal = new ethers7.Contract(portalAddress, PRIVACY_PORTAL_ABI, runner);
1539
+ const portal = new ethers8.Contract(portalAddress, PRIVACY_PORTAL_ABI, runner);
1356
1540
  if (direction === "to-private") {
1357
1541
  const [portalFee2, usedDynamicPricing2] = await portal.estimateDepositFees(amount);
1358
1542
  const quote2 = {
@@ -1384,8 +1568,8 @@ var init_podPortalFees = __esm({
1384
1568
  });
1385
1569
  return quote;
1386
1570
  };
1387
- formatPortalFeeDisplay = (portalFee, _usedDynamicPricing) => ethers7.formatEther(portalFee).replace(/\.?0+$/, "") || "0";
1388
- formatPodFeeDisplay = (totalFee) => ethers7.formatEther(totalFee).replace(/\.?0+$/, "") || "0";
1571
+ formatPortalFeeDisplay = (portalFee, _usedDynamicPricing) => ethers8.formatEther(portalFee).replace(/\.?0+$/, "") || "0";
1572
+ formatPodFeeDisplay = (totalFee) => ethers8.formatEther(totalFee).replace(/\.?0+$/, "") || "0";
1389
1573
  resolvePodFeeEstimationConfig = (chainId, direction, gasPrice) => {
1390
1574
  const limits = getChainConfig(chainId)?.podFeeEstimation?.[direction === "to-private" ? "deposit" : "withdraw"];
1391
1575
  if (!limits) {
@@ -1436,8 +1620,8 @@ var init_podPortalFees = __esm({
1436
1620
  { type: DataType.Uint256, value: "0", isCallBackFee: true },
1437
1621
  { type: DataType.Uint256, value: placeholderDeadline.toString(), isCallBackFee: false },
1438
1622
  { type: DataType.Uint8, value: "0", isCallBackFee: false },
1439
- { type: DataType.String, value: ethers7.ZeroHash, isCallBackFee: false },
1440
- { type: DataType.String, value: ethers7.ZeroHash, isCallBackFee: false }
1623
+ { type: DataType.String, value: ethers8.ZeroHash, isCallBackFee: false },
1624
+ { type: DataType.String, value: ethers8.ZeroHash, isCallBackFee: false }
1441
1625
  ];
1442
1626
  }
1443
1627
  return [
@@ -1465,8 +1649,8 @@ var init_podPortalFees = __esm({
1465
1649
  const fallbackLimit = fallbackExecutionGasLimit(params.chainId, params.direction);
1466
1650
  try {
1467
1651
  const rpcUrl = getRpcUrlForChain(params.chainId);
1468
- const rpcProvider = new ethers7.JsonRpcProvider(rpcUrl);
1469
- const portal = new ethers7.Contract(params.portalAddress, PRIVACY_PORTAL_ABI, rpcProvider);
1652
+ const rpcProvider = new ethers8.JsonRpcProvider(rpcUrl);
1653
+ const portal = new ethers8.Contract(params.portalAddress, PRIVACY_PORTAL_ABI, rpcProvider);
1470
1654
  if (params.direction === "to-private") {
1471
1655
  const method = resolvePodPortalMethod("to-private", params.isNativeDeposit);
1472
1656
  const nativeAmount = params.isNativeDeposit ? params.amountWei : 0n;
@@ -1483,8 +1667,8 @@ var init_podPortalFees = __esm({
1483
1667
  const permit = params.withdrawPermit;
1484
1668
  const deadline = permit ? BigInt(permit.deadline) : BigInt(Math.floor(Date.now() / 1e3) + 60 * 30);
1485
1669
  const v = permit?.v ?? 0;
1486
- const r = permit?.r ?? ethers7.ZeroHash;
1487
- const s = permit?.s ?? ethers7.ZeroHash;
1670
+ const r = permit?.r ?? ethers8.ZeroHash;
1671
+ const s = permit?.s ?? ethers8.ZeroHash;
1488
1672
  const gasLimit = await portal.requestWithdrawWithPermit.estimateGas(
1489
1673
  params.wallet,
1490
1674
  params.amountWei,
@@ -1584,11 +1768,11 @@ var init_podPortalFees = __esm({
1584
1768
  });
1585
1769
 
1586
1770
  // src/chains/portal/executePodPortalTransaction.ts
1587
- import { ethers as ethers8 } from "ethers";
1771
+ import { ethers as ethers9 } from "ethers";
1588
1772
  async function signPodWithdrawPermit(params) {
1589
1773
  const { signer, pTokenAddress, portalAddress, amountWei } = params;
1590
1774
  const wallet = await signer.getAddress();
1591
- const pToken = new ethers8.Contract(pTokenAddress, POD_PTOKEN_ABI, signer);
1775
+ const pToken = new ethers9.Contract(pTokenAddress, POD_PTOKEN_ABI, signer);
1592
1776
  const signingChainId = params.chainId ?? Number((await signer.provider.getNetwork()).chainId);
1593
1777
  const resolvedTokenSymbol = params.tokenSymbol ?? await pToken.symbol().catch(() => void 0);
1594
1778
  await assertPodPTokenReady(pToken, wallet, "withdraw", {
@@ -1658,9 +1842,9 @@ async function executePodPortalTransaction(params) {
1658
1842
  throw new Error("PoD portal is not configured for this token");
1659
1843
  }
1660
1844
  const wallet = await signer.getAddress();
1661
- const amountWei = ethers8.parseUnits(txAmount, decimals);
1662
- const pToken = new ethers8.Contract(pTokenAddress, POD_PTOKEN_ABI, signer);
1663
- const portalIface2 = new ethers8.Interface(PRIVACY_PORTAL_ABI);
1845
+ const amountWei = ethers9.parseUnits(txAmount, decimals);
1846
+ const pToken = new ethers9.Contract(pTokenAddress, POD_PTOKEN_ABI, signer);
1847
+ const portalIface2 = new ethers9.Interface(PRIVACY_PORTAL_ABI);
1664
1848
  const gasPrice = await resolvePodTxGasPrice(provider);
1665
1849
  if (txDirection === "to-private") {
1666
1850
  await assertPodPTokenReady(pToken, wallet, "deposit", {
@@ -1689,7 +1873,7 @@ async function executePodPortalTransaction(params) {
1689
1873
  });
1690
1874
  let gasLimit2;
1691
1875
  try {
1692
- const portal = new ethers8.Contract(portalAddress, PRIVACY_PORTAL_ABI, signer);
1876
+ const portal = new ethers9.Contract(portalAddress, PRIVACY_PORTAL_ABI, signer);
1693
1877
  const nativeAmount = isNativeDeposit ? amountWei : 0n;
1694
1878
  const estimated = await portal[method2].estimateGas(
1695
1879
  wallet,
@@ -1721,7 +1905,9 @@ async function executePodPortalTransaction(params) {
1721
1905
  fee: podFee2
1722
1906
  });
1723
1907
  onProgress?.("transfer-start", tx2.hash);
1724
- const receipt2 = await tx2.wait();
1908
+ const receipt2 = await waitForTransactionResilient(chainId, tx2.hash, {
1909
+ primary: provider ?? signer.provider ?? void 0
1910
+ });
1725
1911
  if (!receipt2 || receipt2.status !== 1) {
1726
1912
  const failed = new Error("PoD deposit transaction failed");
1727
1913
  failed.txHash = tx2.hash;
@@ -1778,7 +1964,7 @@ async function executePodPortalTransaction(params) {
1778
1964
  });
1779
1965
  let gasLimit;
1780
1966
  try {
1781
- const portal = new ethers8.Contract(portalAddress, PRIVACY_PORTAL_ABI, signer);
1967
+ const portal = new ethers9.Contract(portalAddress, PRIVACY_PORTAL_ABI, signer);
1782
1968
  const estimated = await portal.requestWithdrawWithPermit.estimateGas(
1783
1969
  wallet,
1784
1970
  amountWei,
@@ -1812,7 +1998,9 @@ async function executePodPortalTransaction(params) {
1812
1998
  fee: podFee
1813
1999
  });
1814
2000
  onProgress?.("transfer-start", tx.hash);
1815
- const receipt = await tx.wait();
2001
+ const receipt = await waitForTransactionResilient(chainId, tx.hash, {
2002
+ primary: provider ?? signer.provider ?? void 0
2003
+ });
1816
2004
  if (!receipt || receipt.status !== 1) {
1817
2005
  const failed = new Error("Sepolia withdraw transaction failed");
1818
2006
  failed.txHash = tx.hash;
@@ -1846,13 +2034,14 @@ var init_executePodPortalTransaction = __esm({
1846
2034
  "use strict";
1847
2035
  init_pod();
1848
2036
  init_logger();
2037
+ init_rpcProvider();
1849
2038
  init_podPTokenBlockingDiagnostics();
1850
2039
  init_podPortalFees();
1851
2040
  init_podSdkConfig();
1852
2041
  init_podPortalFees();
1853
2042
  init_fees();
1854
2043
  getErrorMessage = (error) => error && typeof error === "object" && "message" in error && typeof error.message === "string" ? error.message : "";
1855
- pTokenErrorIface = new ethers8.Interface(POD_PTOKEN_ABI);
2044
+ pTokenErrorIface = new ethers9.Interface(POD_PTOKEN_ABI);
1856
2045
  extractRevertData = (error) => {
1857
2046
  if (!error || typeof error !== "object") return null;
1858
2047
  const err = error;
@@ -1908,7 +2097,7 @@ var init_executePodPortalTransaction = __esm({
1908
2097
  return null;
1909
2098
  };
1910
2099
  splitSignature = (signature) => {
1911
- const parsed = ethers8.Signature.from(signature);
2100
+ const parsed = ethers9.Signature.from(signature);
1912
2101
  return { v: parsed.v, r: parsed.r, s: parsed.s };
1913
2102
  };
1914
2103
  POD_PTOKEN_FLAT_STATUS_ABI = [
@@ -2055,7 +2244,7 @@ var init_executePodPortalTransaction = __esm({
2055
2244
  if (pendingFromRevert) return pendingFromRevert;
2056
2245
  probeErrors.push(`balanceWithState: ${getErrorMessage(error) || String(error)}`);
2057
2246
  }
2058
- const flatStatusToken = new ethers8.Contract(
2247
+ const flatStatusToken = new ethers9.Contract(
2059
2248
  pTokenAddress,
2060
2249
  POD_PTOKEN_FLAT_STATUS_ABI,
2061
2250
  pToken.runner
@@ -2090,7 +2279,7 @@ var init_executePodPortalTransaction = __esm({
2090
2279
  if (pendingFromRevert) return pendingFromRevert;
2091
2280
  probeErrors.push(`balanceOfWithStatus: ${getErrorMessage(error) || String(error)}`);
2092
2281
  }
2093
- const plainToken = new ethers8.Contract(
2282
+ const plainToken = new ethers9.Contract(
2094
2283
  pTokenAddress,
2095
2284
  POD_PTOKEN_PLAIN_STATUS_ABI,
2096
2285
  pToken.runner
@@ -2297,7 +2486,7 @@ var init_ethereum = __esm({
2297
2486
  });
2298
2487
 
2299
2488
  // src/chains/portal/podTransferFees.ts
2300
- import { ethers as ethers9 } from "ethers";
2489
+ import { ethers as ethers10 } from "ethers";
2301
2490
  import {
2302
2491
  DataType as DataType2,
2303
2492
  PodContract as PodContract2,
@@ -2427,8 +2616,8 @@ var init_podTransferFees = __esm({
2427
2616
  if (!overrides.gasLimit) {
2428
2617
  try {
2429
2618
  const rpcUrl = getRpcUrlForChain(params.chainId);
2430
- const rpcProvider = new ethers9.JsonRpcProvider(rpcUrl);
2431
- const pToken = new ethers9.Contract(params.pTokenAddress, POD_PTOKEN_ABI, rpcProvider);
2619
+ const rpcProvider = new ethers10.JsonRpcProvider(rpcUrl);
2620
+ const pToken = new ethers10.Contract(params.pTokenAddress, POD_PTOKEN_ABI, rpcProvider);
2432
2621
  const estimated = await pToken.getFunction(POD_TRANSFER_METHOD).estimateGas(...vals, {
2433
2622
  from: userAddress,
2434
2623
  value: fee.totalFee,
@@ -2506,7 +2695,7 @@ var init_utils = __esm({
2506
2695
  });
2507
2696
 
2508
2697
  // src/hooks/privacyBridge/executePrivateTokenTransfer.ts
2509
- import { ethers as ethers10 } from "ethers";
2698
+ import { ethers as ethers11 } from "ethers";
2510
2699
  function normalizeAesKeyHex(aesKey) {
2511
2700
  try {
2512
2701
  return normalizeAesKey(aesKey);
@@ -2532,10 +2721,10 @@ function resolvePrivateTokenTransferTarget(chainId, symbol) {
2532
2721
  };
2533
2722
  }
2534
2723
  function validatePrivateTransferInputs(tokenAddress, recipient, amount, walletAddress) {
2535
- if (!ethers10.isAddress(tokenAddress)) {
2724
+ if (!ethers11.isAddress(tokenAddress)) {
2536
2725
  throw new Error("Invalid token contract address");
2537
2726
  }
2538
- if (!ethers10.isAddress(recipient)) {
2727
+ if (!ethers11.isAddress(recipient)) {
2539
2728
  throw new Error("Invalid recipient address");
2540
2729
  }
2541
2730
  if (recipient.toLowerCase() === walletAddress.toLowerCase()) {
@@ -2548,7 +2737,7 @@ function validatePrivateTransferInputs(tokenAddress, recipient, amount, walletAd
2548
2737
  function parseTransferAmountWei(amount, decimals) {
2549
2738
  let amountWei;
2550
2739
  try {
2551
- amountWei = ethers10.parseUnits(amount, decimals);
2740
+ amountWei = ethers11.parseUnits(amount, decimals);
2552
2741
  } catch {
2553
2742
  throw new Error("Invalid amount for token decimals");
2554
2743
  }
@@ -2584,7 +2773,9 @@ async function submitPrivateTokenTransferTx(params) {
2584
2773
  recipient: shortHash(recipient),
2585
2774
  amount
2586
2775
  });
2587
- const browserProvider = new ethers10.BrowserProvider(eip1193);
2776
+ const browserProvider = new ethers11.BrowserProvider(eip1193);
2777
+ const network = await browserProvider.getNetwork();
2778
+ const chainId = Number(network.chainId);
2588
2779
  const rawTxHash = await eip1193.request({
2589
2780
  method: "eth_sendTransaction",
2590
2781
  params: [
@@ -2597,7 +2788,9 @@ async function submitPrivateTokenTransferTx(params) {
2597
2788
  ]
2598
2789
  });
2599
2790
  logger.log("Waiting for private transfer tx", { txHash: shortHash(rawTxHash) });
2600
- const receipt = await browserProvider.waitForTransaction(rawTxHash);
2791
+ const receipt = await waitForTransactionResilient(chainId, rawTxHash, {
2792
+ primary: browserProvider
2793
+ });
2601
2794
  if (!receipt || receipt.status !== 1) {
2602
2795
  throw new Error("Private token transfer failed");
2603
2796
  }
@@ -2635,10 +2828,10 @@ async function sendPrivateTokenTransfer(params) {
2635
2828
  if (!eip1193) {
2636
2829
  throw new Error("No wallet found");
2637
2830
  }
2638
- const browserProvider = new ethers10.BrowserProvider(eip1193);
2831
+ const browserProvider = new ethers11.BrowserProvider(eip1193);
2639
2832
  const signer = await browserProvider.getSigner(walletAddress);
2640
2833
  const amountWei = parseTransferAmountWei(amount, target.decimals);
2641
- const transferSig = ethers10.id(PRIVATE_ERC20_TRANSFER_256_SIG).slice(0, 10);
2834
+ const transferSig = ethers11.id(PRIVATE_ERC20_TRANSFER_256_SIG).slice(0, 10);
2642
2835
  let aesKey = sessionAesKey ? normalizeAesKeyHex(sessionAesKey) : null;
2643
2836
  if (!aesKey && hasSnap && getAESKeyFromSnap) {
2644
2837
  const snapKey = await getAESKeyFromSnap(walletAddress);
@@ -2673,6 +2866,7 @@ var init_executePrivateTokenTransfer = __esm({
2673
2866
  init_aesKey();
2674
2867
  init_ethereum();
2675
2868
  init_logger();
2869
+ init_rpcProvider();
2676
2870
  init_config();
2677
2871
  init_chains();
2678
2872
  init_chains();
@@ -2681,7 +2875,7 @@ var init_executePrivateTokenTransfer = __esm({
2681
2875
  PRIVATE_ERC20_TRANSFER_256_SIG = "transfer(address,((uint256,uint256),bytes))";
2682
2876
  GAS_ESTIMATE_BUFFER_PERCENT = 105n;
2683
2877
  CONFIDENTIAL_TRANSFER_GAS_LIMIT = 2000000n;
2684
- TRANSFER_INTERFACE = new ethers10.Interface([
2878
+ TRANSFER_INTERFACE = new ethers11.Interface([
2685
2879
  "function transfer(address to, tuple(tuple(uint256 ciphertextHigh, uint256 ciphertextLow) ciphertext, bytes signature) value) returns (uint256)"
2686
2880
  ]);
2687
2881
  }
@@ -2695,12 +2889,12 @@ __export(executePodPrivateTokenTransfer_exports, {
2695
2889
  quotePodPrivateTokenTransferFees: () => quotePodPrivateTokenTransferFees,
2696
2890
  quotePodTransferFees: () => quotePodTransferFees
2697
2891
  });
2698
- import { ethers as ethers11 } from "ethers";
2892
+ import { ethers as ethers12 } from "ethers";
2699
2893
  function validatePodTransferInputs(tokenAddress, recipient, amount, walletAddress) {
2700
- if (!ethers11.isAddress(tokenAddress)) {
2894
+ if (!ethers12.isAddress(tokenAddress)) {
2701
2895
  throw new Error("Invalid token contract address");
2702
2896
  }
2703
- if (!ethers11.isAddress(recipient)) {
2897
+ if (!ethers12.isAddress(recipient)) {
2704
2898
  throw new Error("Invalid recipient address");
2705
2899
  }
2706
2900
  if (recipient.toLowerCase() === walletAddress.toLowerCase()) {
@@ -2725,13 +2919,13 @@ async function executePodPrivateTokenTransfer(params) {
2725
2919
  if (!eip1193) {
2726
2920
  throw new Error("No wallet found");
2727
2921
  }
2728
- const browserProvider = new ethers11.BrowserProvider(eip1193);
2922
+ const browserProvider = new ethers12.BrowserProvider(eip1193);
2729
2923
  const signer = await browserProvider.getSigner(walletAddress);
2730
- const amountWei = ethers11.parseUnits(amount, target.decimals);
2924
+ const amountWei = ethers12.parseUnits(amount, target.decimals);
2731
2925
  if (amountWei <= 0n) {
2732
2926
  throw new Error("Amount must be greater than zero");
2733
2927
  }
2734
- const pToken = new ethers11.Contract(target.tokenAddress, POD_PTOKEN_ABI, signer);
2928
+ const pToken = new ethers12.Contract(target.tokenAddress, POD_PTOKEN_ABI, signer);
2735
2929
  await assertPodPTokenReady(pToken, walletAddress, "transfer", {
2736
2930
  chainId,
2737
2931
  tokenSymbol: symbol,
@@ -2763,13 +2957,15 @@ async function executePodPrivateTokenTransfer(params) {
2763
2957
  gasPrice,
2764
2958
  fee: podFee
2765
2959
  });
2766
- const receipt = await tx.wait();
2960
+ const receipt = await waitForTransactionResilient(chainId, tx.hash, {
2961
+ primary: browserProvider
2962
+ });
2767
2963
  if (!receipt || receipt.status !== 1) {
2768
2964
  const failed = new Error("PoD private token transfer failed");
2769
2965
  failed.txHash = tx.hash;
2770
2966
  throw failed;
2771
2967
  }
2772
- const event = findParsedEvent2(receipt, new ethers11.Interface(POD_PTOKEN_ABI), "TransferRequestSubmitted");
2968
+ const event = findParsedEvent2(receipt, new ethers12.Interface(POD_PTOKEN_ABI), "TransferRequestSubmitted");
2773
2969
  const requestId = event?.args?.requestId;
2774
2970
  return {
2775
2971
  txHash: tx.hash,
@@ -2799,10 +2995,10 @@ async function quotePodPrivateTokenTransferFees(params) {
2799
2995
  if (!eip1193) {
2800
2996
  throw new Error("No wallet found");
2801
2997
  }
2802
- const browserProvider = new ethers11.BrowserProvider(eip1193);
2998
+ const browserProvider = new ethers12.BrowserProvider(eip1193);
2803
2999
  const signer = await browserProvider.getSigner(params.walletAddress);
2804
- const amountWei = ethers11.parseUnits(params.amount, target.decimals);
2805
- const recipient = ethers11.isAddress(params.recipient) && params.recipient !== ethers11.ZeroAddress ? params.recipient : params.walletAddress;
3000
+ const amountWei = ethers12.parseUnits(params.amount, target.decimals);
3001
+ const recipient = ethers12.isAddress(params.recipient) && params.recipient !== ethers12.ZeroAddress ? params.recipient : params.walletAddress;
2806
3002
  return quotePodTransferFees({
2807
3003
  runner: signer,
2808
3004
  chainId: params.chainId,
@@ -2819,6 +3015,7 @@ var init_executePodPrivateTokenTransfer = __esm({
2819
3015
  init_chains();
2820
3016
  init_ethereum();
2821
3017
  init_logger();
3018
+ init_rpcProvider();
2822
3019
  init_executePodPortalTransaction();
2823
3020
  init_podPortalFees();
2824
3021
  init_podTransferFees();
@@ -3396,7 +3593,7 @@ init_executePodPrivateTokenTransfer();
3396
3593
  init_logger();
3397
3594
  import { useState, useCallback, useEffect, useRef } from "react";
3398
3595
  import { useAccount } from "wagmi";
3399
- import { ethers as ethers12 } from "ethers";
3596
+ import { ethers as ethers13 } from "ethers";
3400
3597
  var usePodTransferFees = ({
3401
3598
  isConnected,
3402
3599
  walletAddress,
@@ -3453,7 +3650,7 @@ var usePodTransferFees = ({
3453
3650
  const quote = await quotePodPrivateTokenTransferFees({
3454
3651
  chainId,
3455
3652
  symbol,
3456
- recipient: recipient && ethers12.isAddress(recipient) ? recipient : walletAddress,
3653
+ recipient: recipient && ethers13.isAddress(recipient) ? recipient : walletAddress,
3457
3654
  amount: currentAmount,
3458
3655
  walletAddress,
3459
3656
  provider: injected6
@@ -3502,7 +3699,7 @@ var usePodTransferFees = ({
3502
3699
  init_chains();
3503
3700
  init_rpcUrls();
3504
3701
  init_logger();
3505
- import { ethers as ethers13 } from "ethers";
3702
+ import { ethers as ethers14 } from "ethers";
3506
3703
  var POD_PRICE_ORACLE_ABI = [
3507
3704
  "function getLivePrice(address token) view returns (uint256 priceUsd)",
3508
3705
  "function getLivePrices(address tokenA, address tokenB) view returns (uint256 priceA, uint256 priceB)"
@@ -3527,17 +3724,17 @@ async function fetchPodOracleTokenUsdPrice(symbol, chainId, provider) {
3527
3724
  return null;
3528
3725
  }
3529
3726
  const rpcUrls = provider ? [] : getRpcUrlsForChain(chainId);
3530
- const providers = provider ? [provider] : rpcUrls.map((url) => new ethers13.JsonRpcProvider(url));
3727
+ const providers = provider ? [provider] : rpcUrls.map((url) => new ethers14.JsonRpcProvider(url));
3531
3728
  let lastError;
3532
3729
  for (const rpcProvider of providers) {
3533
3730
  try {
3534
- const oracle = new ethers13.Contract(oracleAddress, POD_PRICE_ORACLE_ABI, rpcProvider);
3731
+ const oracle = new ethers14.Contract(oracleAddress, POD_PRICE_ORACLE_ABI, rpcProvider);
3535
3732
  const raw = await oracle.getLivePrice(tokenAddress);
3536
3733
  if (raw === 0n) {
3537
3734
  logger.warn(`PoD price oracle has no live feed for ${symbol} on chain ${chainId}`);
3538
3735
  return null;
3539
3736
  }
3540
- return Number(ethers13.formatEther(raw));
3737
+ return Number(ethers14.formatEther(raw));
3541
3738
  } catch (err) {
3542
3739
  lastError = err;
3543
3740
  }
@@ -3551,12 +3748,12 @@ async function fetchPodOracleTokenUsdPrice(symbol, chainId, provider) {
3551
3748
  init_pod();
3552
3749
  init_chains();
3553
3750
  init_rpcUrls();
3554
- import { ethers as ethers14 } from "ethers";
3751
+ import { ethers as ethers15 } from "ethers";
3555
3752
  init_logger();
3556
3753
  var ERC20_BALANCE_ABI = ["function balanceOf(address) view returns (uint256)"];
3557
3754
  var FEE_DIVISOR = 1000000n;
3558
3755
  var POD_NO_MAX_FEE_SENTINEL = (1n << 128n) - 1n;
3559
- var formatFee = (value) => value >= POD_NO_MAX_FEE_SENTINEL ? "0" : ethers14.formatEther(value);
3756
+ var formatFee = (value) => value >= POD_NO_MAX_FEE_SENTINEL ? "0" : ethers15.formatEther(value);
3560
3757
  async function fetchPortalRow(token, config, provider, nativeSymbol) {
3561
3758
  const portalAddress = config.addresses[token.bridgeAddressKey];
3562
3759
  const privateToken = config.tokens.find(
@@ -3583,12 +3780,12 @@ async function fetchPortalRow(token, config, provider, nativeSymbol) {
3583
3780
  isLoading: false
3584
3781
  };
3585
3782
  try {
3586
- const portal = new ethers14.Contract(portalAddress, POD_PORTAL_ADMIN_ABI, provider);
3783
+ const portal = new ethers15.Contract(portalAddress, POD_PORTAL_ADMIN_ABI, provider);
3587
3784
  const [depCfg, wdCfg, accFees, balance] = await Promise.all([
3588
3785
  portal.getFeeConfig(true),
3589
3786
  portal.getFeeConfig(false),
3590
3787
  portal.accumulatedPortalFees().catch(() => 0n),
3591
- token.isNative ? provider.getBalance(portalAddress) : token.addressKey && config.addresses[token.addressKey] ? new ethers14.Contract(config.addresses[token.addressKey], ERC20_BALANCE_ABI, provider).balanceOf(portalAddress).catch(() => 0n) : Promise.resolve(0n)
3788
+ token.isNative ? provider.getBalance(portalAddress) : token.addressKey && config.addresses[token.addressKey] ? new ethers15.Contract(config.addresses[token.addressKey], ERC20_BALANCE_ABI, provider).balanceOf(portalAddress).catch(() => 0n) : Promise.resolve(0n)
3592
3789
  ]);
3593
3790
  return {
3594
3791
  ...base,
@@ -3598,8 +3795,8 @@ async function fetchPortalRow(token, config, provider, nativeSymbol) {
3598
3795
  withdrawFixedFee: formatFee(wdCfg[0]),
3599
3796
  withdrawPercentageBps: wdCfg[1].toString(),
3600
3797
  withdrawMaxFee: formatFee(wdCfg[2]),
3601
- accumulatedCotiFees: ethers14.formatEther(accFees),
3602
- bridgeBalance: ethers14.formatUnits(balance, token.decimals),
3798
+ accumulatedCotiFees: ethers15.formatEther(accFees),
3799
+ bridgeBalance: ethers15.formatUnits(balance, token.decimals),
3603
3800
  error: null
3604
3801
  };
3605
3802
  } catch (err) {
@@ -3627,7 +3824,7 @@ async function fetchPodBridgeData(chainId) {
3627
3824
  );
3628
3825
  let lastError;
3629
3826
  for (const rpcUrl of getRpcUrlsForChain(chainId)) {
3630
- const provider = new ethers14.JsonRpcProvider(rpcUrl);
3827
+ const provider = new ethers15.JsonRpcProvider(rpcUrl);
3631
3828
  try {
3632
3829
  await provider.getBlockNumber();
3633
3830
  return await Promise.all(
@@ -3646,7 +3843,7 @@ async function simulatePodPortalFee(chainId, tokenSymbol, amount, fixedFee, perc
3646
3843
  if (!config) return { fee: "\u2014", explanation: "Unsupported chain" };
3647
3844
  const token = config.tokens.find((t) => t.symbol === tokenSymbol && !t.isPrivate);
3648
3845
  if (!token) return { fee: "\u2014", explanation: "Unknown token" };
3649
- const amountWei = ethers14.parseUnits(amount, token.decimals);
3846
+ const amountWei = ethers15.parseUnits(amount, token.decimals);
3650
3847
  let valueInNative;
3651
3848
  if (token.isNative) {
3652
3849
  valueInNative = amountWei;
@@ -3657,27 +3854,27 @@ async function simulatePodPortalFee(chainId, tokenSymbol, amount, fixedFee, perc
3657
3854
  fetchPodOracleTokenUsdPrice(nativeSymbol, chainId)
3658
3855
  ]);
3659
3856
  if (!tokenUsd || !nativeUsd) {
3660
- const fixed = ethers14.parseEther(fixedFee || "0");
3661
- const cap = ethers14.parseEther(maxFee || "0");
3857
+ const fixed = ethers15.parseEther(fixedFee || "0");
3858
+ const cap = ethers15.parseEther(maxFee || "0");
3662
3859
  const fee2 = cap > 0n && fixed > cap ? cap : fixed;
3663
3860
  return {
3664
- fee: parseFloat(ethers14.formatEther(fee2)).toFixed(6),
3861
+ fee: parseFloat(ethers15.formatEther(fee2)).toFixed(6),
3665
3862
  explanation: "Fixed fee applied (no live oracle price)"
3666
3863
  };
3667
3864
  }
3668
- const tokenUsdWei = ethers14.parseEther(tokenUsd.toString());
3669
- const nativeUsdWei = ethers14.parseEther(nativeUsd.toString());
3865
+ const tokenUsdWei = ethers15.parseEther(tokenUsd.toString());
3866
+ const nativeUsdWei = ethers15.parseEther(nativeUsd.toString());
3670
3867
  const amount18 = amountWei * 10n ** BigInt(18 - token.decimals);
3671
3868
  valueInNative = amount18 * tokenUsdWei / nativeUsdWei;
3672
3869
  }
3673
- const fixedFeeWei = ethers14.parseEther(fixedFee || "0");
3674
- const maxFeeWei = ethers14.parseEther(maxFee || "0");
3870
+ const fixedFeeWei = ethers15.parseEther(fixedFee || "0");
3871
+ const maxFeeWei = ethers15.parseEther(maxFee || "0");
3675
3872
  const bps = BigInt(parseInt(percentageBps || "0", 10));
3676
3873
  const percentageFee = valueInNative * bps / FEE_DIVISOR;
3677
3874
  let fee = percentageFee > fixedFeeWei ? percentageFee : fixedFeeWei;
3678
3875
  if (maxFeeWei > 0n && fee > maxFeeWei) fee = maxFeeWei;
3679
3876
  const explanation = maxFeeWei > 0n && fee === maxFeeWei && fee !== fixedFeeWei ? "Max fee cap applied" : fee === fixedFeeWei ? "Fixed fee floor applied" : "Percentage fee applied";
3680
- return { fee: parseFloat(ethers14.formatEther(fee)).toFixed(6), explanation };
3877
+ return { fee: parseFloat(ethers15.formatEther(fee)).toFixed(6), explanation };
3681
3878
  } catch (err) {
3682
3879
  logger.error("simulatePodPortalFee error:", err);
3683
3880
  return { fee: "\u2014", explanation: "Simulation failed" };
@@ -3700,7 +3897,7 @@ var LIMITS = {
3700
3897
  init_plugin();
3701
3898
  init_ethereum();
3702
3899
  import { useState as useState2, useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2 } from "react";
3703
- import { ethers as ethers15 } from "ethers";
3900
+ import { ethers as ethers16 } from "ethers";
3704
3901
  init_logger();
3705
3902
 
3706
3903
  // src/lib/format.ts
@@ -3984,7 +4181,7 @@ var useMetamask = ({
3984
4181
  });
3985
4182
  const accounts = await eth.request({ method: "eth_requestAccounts" });
3986
4183
  if (!accounts || accounts.length === 0) return false;
3987
- const provider = new ethers15.BrowserProvider(eth);
4184
+ const provider = new ethers16.BrowserProvider(eth);
3988
4185
  const network = await provider.getNetwork();
3989
4186
  const envDefaultNetwork = getPluginConfig().defaultNetworkId;
3990
4187
  if (accounts.length > 0) {
@@ -4001,7 +4198,7 @@ var useMetamask = ({
4001
4198
  const eth = getMetaMaskProvider();
4002
4199
  if (!eth) return;
4003
4200
  try {
4004
- const provider = new ethers15.BrowserProvider(eth);
4201
+ const provider = new ethers16.BrowserProvider(eth);
4005
4202
  await checkNetwork(provider);
4006
4203
  if (onNetworkChanged) {
4007
4204
  await onNetworkChanged();
@@ -4238,84 +4435,8 @@ function decryptCtUint256(ciphertext, aesKey, options) {
4238
4435
  }
4239
4436
  }
4240
4437
 
4241
- // src/lib/rpcProvider.ts
4242
- init_plugin();
4243
- init_coti();
4244
- init_rpcUrls();
4245
- init_sepolia();
4246
- init_logger();
4247
- import { ethers as ethers16 } from "ethers";
4248
- var resolveRpcUrlsForChain = (chainId) => {
4249
- const base = getRpcUrlsForChain(chainId);
4250
- const numericId = chainId == null ? void 0 : Number(chainId);
4251
- if (numericId == null || !Number.isFinite(numericId)) return base;
4252
- const plugin = getPluginConfig();
4253
- let override;
4254
- if (numericId === SEPOLIA_CHAIN_ID && plugin.sepoliaRpcUrl) {
4255
- override = plugin.sepoliaRpcUrl;
4256
- } else if (numericId === COTI_TESTNET_CHAIN_ID && plugin.cotiTestnetRpcUrl) {
4257
- override = plugin.cotiTestnetRpcUrl;
4258
- }
4259
- if (!override) return base;
4260
- return [.../* @__PURE__ */ new Set([override, ...base])];
4261
- };
4262
- var collectErrorText = (error) => {
4263
- if (!error) return "";
4264
- if (typeof error === "string") return error;
4265
- if (error instanceof Error) return error.message;
4266
- try {
4267
- return JSON.stringify(error);
4268
- } catch {
4269
- return String(error);
4270
- }
4271
- };
4272
- var isTransientRpcError = (error) => {
4273
- const text = collectErrorText(error);
4274
- if (text.includes("Too Many Requests") || text.includes("rate limit") || text.includes("-32005") || text.includes("ECONNRESET") || text.includes("ETIMEDOUT") || text.includes("timeout") || text.includes("503") || text.includes("502")) {
4275
- return true;
4276
- }
4277
- if (error && typeof error === "object") {
4278
- const code = error.code;
4279
- if (code === "SERVER_ERROR" || code === "TIMEOUT" || code === "NETWORK_ERROR") {
4280
- return true;
4281
- }
4282
- }
4283
- return false;
4284
- };
4285
- var createJsonRpcProvider = (url, chainId) => new ethers16.JsonRpcProvider(url, chainId);
4286
- var createResilientJsonRpcProvider = async (chainId) => {
4287
- const urls = resolveRpcUrlsForChain(chainId);
4288
- let lastError;
4289
- for (const url of urls) {
4290
- const provider = createJsonRpcProvider(url, chainId);
4291
- try {
4292
- await provider.getNetwork();
4293
- return provider;
4294
- } catch (error) {
4295
- lastError = error;
4296
- if (!isTransientRpcError(error)) throw error;
4297
- logger.warn(`[rpc] ${url} unavailable for chain ${chainId}, trying fallback`);
4298
- }
4299
- }
4300
- throw lastError instanceof Error ? lastError : new Error(`No RPC available for chain ${chainId}`);
4301
- };
4302
- var withRpcFallback = async (chainId, fn) => {
4303
- const urls = resolveRpcUrlsForChain(chainId);
4304
- let lastError;
4305
- for (const url of urls) {
4306
- const provider = createJsonRpcProvider(url, chainId);
4307
- try {
4308
- return await fn(provider);
4309
- } catch (error) {
4310
- lastError = error;
4311
- if (!isTransientRpcError(error)) throw error;
4312
- logger.warn(`[rpc] ${url} request failed for chain ${chainId}, trying fallback`);
4313
- }
4314
- }
4315
- throw lastError instanceof Error ? lastError : new Error(`All RPC endpoints failed for chain ${chainId}`);
4316
- };
4317
-
4318
4438
  // src/hooks/usePrivateTokenBalance.ts
4439
+ init_rpcProvider();
4319
4440
  init_plugin();
4320
4441
  init_logger();
4321
4442
  var PLAIN_BALANCE_ABI = [
@@ -4426,6 +4547,7 @@ var usePrivateTokenBalance = () => {
4426
4547
 
4427
4548
  // src/hooks/useBalanceUpdater.ts
4428
4549
  init_config();
4550
+ init_rpcProvider();
4429
4551
  import { useCallback as useCallback4, useRef as useRef3 } from "react";
4430
4552
  import { ethers as ethers19 } from "ethers";
4431
4553
 
@@ -4521,6 +4643,7 @@ import { encodeKey, encodeUint, encrypt, decryptUint as decryptUint2, decodeUint
4521
4643
  import { ethers as ethers18 } from "ethers";
4522
4644
  init_logger();
4523
4645
  init_config();
4646
+ init_rpcProvider();
4524
4647
  var ROUND_TRIP_TEST_VALUE = 0x0123456789abcdefn;
4525
4648
  var FLAT_BALANCE_ABI2 = [
4526
4649
  "function balanceOf(address) view returns (tuple(uint256 ciphertextHigh, uint256 ciphertextLow))"
@@ -5239,6 +5362,7 @@ import { useState as useState4, useCallback as useCallback7, useEffect as useEff
5239
5362
  import { useAccount as useAccount3 } from "wagmi";
5240
5363
  import { ethers as ethers22 } from "ethers";
5241
5364
  init_logger();
5365
+ init_rpcProvider();
5242
5366
  init_encryptValue256();
5243
5367
  init_utils();
5244
5368
  init_ethereum();
@@ -6218,7 +6342,9 @@ var usePrivacyBridgeAllowance = ({
6218
6342
  }]
6219
6343
  });
6220
6344
  logger.log("\u{1F510} [Approve] Tx submitted, waiting for confirmation", { txHash: shortHash(rawTxHash) });
6221
- await provider.waitForTransaction(rawTxHash);
6345
+ await waitForTransactionResilient(currentChainId, rawTxHash, {
6346
+ primary: provider
6347
+ });
6222
6348
  logger.log("\u{1F510} [Approve] Tx confirmed, refreshing allowance...");
6223
6349
  setIsApproving(false);
6224
6350
  setToastState((prev) => ({ ...prev, visible: false }));
@@ -6235,7 +6361,9 @@ var usePrivacyBridgeAllowance = ({
6235
6361
  title: "Approving...",
6236
6362
  message: "Waiting for allowance confirmation..."
6237
6363
  });
6238
- await tx.wait();
6364
+ await waitForTransactionResilient(currentChainId, tx.hash, {
6365
+ primary: provider
6366
+ });
6239
6367
  await checkAllowance();
6240
6368
  setIsApproving(false);
6241
6369
  setToastState((prev) => ({ ...prev, visible: false }));
@@ -6279,6 +6407,7 @@ import { useAccount as useAccount4 } from "wagmi";
6279
6407
  import { ethers as ethers23 } from "ethers";
6280
6408
  init_chains();
6281
6409
  init_logger();
6410
+ init_rpcProvider();
6282
6411
  init_utils();
6283
6412
  var usePrivacyBridgeExecutor = ({
6284
6413
  walletAddress,
@@ -6527,7 +6656,9 @@ var usePrivacyBridgeExecutor = ({
6527
6656
  logger.log("ERC20 deposit tx sent", { txHash: shortHash(rawDepositTxHash) });
6528
6657
  tx = {
6529
6658
  hash: rawDepositTxHash,
6530
- wait: async () => await provider.waitForTransaction(rawDepositTxHash)
6659
+ wait: async () => await waitForTransactionResilient(currentChainId, rawDepositTxHash, {
6660
+ primary: provider
6661
+ })
6531
6662
  };
6532
6663
  } else {
6533
6664
  logger.log("\u{1F504} Executing Native COTI Deposit...");
@@ -6684,7 +6815,9 @@ var usePrivacyBridgeExecutor = ({
6684
6815
  logger.log("Withdraw tx sent", { txHash: shortHash(rawWithdrawTxHash) });
6685
6816
  tx = {
6686
6817
  hash: rawWithdrawTxHash,
6687
- wait: async () => await provider.waitForTransaction(rawWithdrawTxHash)
6818
+ wait: async () => await waitForTransactionResilient(currentChainId, rawWithdrawTxHash, {
6819
+ primary: provider
6820
+ })
6688
6821
  };
6689
6822
  } catch (e) {
6690
6823
  setIsBridgingLoading(false);
@@ -6700,12 +6833,13 @@ var usePrivacyBridgeExecutor = ({
6700
6833
  title: "Processing Transaction",
6701
6834
  message: "Transaction sent to network. Waiting for confirmation..."
6702
6835
  });
6703
- const receipt = await tx.wait();
6836
+ const receipt = await waitForTransactionResilient(currentChainId, tx.hash, {
6837
+ primary: provider
6838
+ });
6704
6839
  logger.log("Transaction confirmed", {
6705
6840
  status: receipt.status,
6706
6841
  blockNumber: receipt.blockNumber,
6707
- gasUsed: receipt.gasUsed?.toString(),
6708
- gasLimit: receipt.gasLimit?.toString() ?? "n/a"
6842
+ gasUsed: receipt.gasUsed?.toString()
6709
6843
  });
6710
6844
  if (receipt.status !== 1) {
6711
6845
  const gasUsed = receipt.gasUsed ? Number(receipt.gasUsed) : 0;
@@ -6720,11 +6854,12 @@ var usePrivacyBridgeExecutor = ({
6720
6854
  const replayProvider = new ethers23.JsonRpcProvider(
6721
6855
  getRpcUrlForChain(Number(network2.chainId))
6722
6856
  );
6857
+ const broadcastTx = await replayProvider.getTransaction(txHashStr);
6723
6858
  await replayProvider.call({
6724
- to: receipt.to,
6725
- from: receipt.from,
6726
- data: receipt.data || void 0,
6727
- value: receipt.value || void 0
6859
+ to: broadcastTx?.to ?? receipt.to,
6860
+ from: broadcastTx?.from ?? receipt.from,
6861
+ data: broadcastTx?.data,
6862
+ value: broadcastTx?.value
6728
6863
  });
6729
6864
  } catch (replayErr) {
6730
6865
  const errorName = replayErr.errorName || replayErr.revert?.name;
@@ -7650,7 +7785,7 @@ async function fetchEncryptedBackupProbe(address, chainId) {
7650
7785
  return null;
7651
7786
  }
7652
7787
  }
7653
- var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7788
+ var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7654
7789
  function resolveAesKeyChainId(currentChainId, overrideChainId) {
7655
7790
  const configuredChainId = getPluginConfig().aesKeyChainId;
7656
7791
  assertAesKeyChainId(configuredChainId);
@@ -7670,7 +7805,7 @@ async function probeSnapKeyWithRetry(hasAesKeyInSnap, address, retries, confirmS
7670
7805
  for (let attempt = 0; attempt <= retries; attempt += 1) {
7671
7806
  const result = await hasAesKeyInSnap(address);
7672
7807
  if (result !== null) return result;
7673
- if (attempt < retries) await sleep(250);
7808
+ if (attempt < retries) await sleep2(250);
7674
7809
  }
7675
7810
  if (confirmSnapInstalled && !await confirmSnapInstalled()) {
7676
7811
  return false;
@@ -7963,7 +8098,7 @@ function toBigInt(value, fallback2) {
7963
8098
  if (value === void 0) return fallback2;
7964
8099
  return getBigInt(value);
7965
8100
  }
7966
- var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
8101
+ var sleep3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7967
8102
  function useAesKeyProvider(walletTypeInfo) {
7968
8103
  const [isOnboarding, setIsOnboarding] = useState11(false);
7969
8104
  const [onboardingError, setOnboardingError] = useState11(null);
@@ -8208,7 +8343,7 @@ function useAesKeyProvider(walletTypeInfo) {
8208
8343
  const timeoutMs = config.onboardingGrantTimeoutMs ?? 6e4;
8209
8344
  const startedAt = Date.now();
8210
8345
  while (nativeBalance < requiredBalanceWei && Date.now() - startedAt < timeoutMs) {
8211
- await sleep2(pollIntervalMs);
8346
+ await sleep3(pollIntervalMs);
8212
8347
  nativeBalance = await provider.getBalance(address);
8213
8348
  logger.log("[AesKeyProvider] Native COTI balance while waiting for grant", {
8214
8349
  address,