@coti-io/coti-wallet-plugin 0.2.4 → 0.2.6

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,
@@ -1339,20 +1523,14 @@ var init_podPortalFees = __esm({
1339
1523
  return BigInt(gasPriceHex);
1340
1524
  };
1341
1525
  resolvePodTxGasPrice = async (provider) => {
1342
- let base;
1343
- try {
1344
- const feeData = await provider.getFeeData();
1345
- base = feeData.gasPrice ?? await getPodGasPrice(provider);
1346
- } catch {
1347
- base = await getPodGasPrice(provider);
1348
- }
1526
+ const base = await getPodGasPrice(provider);
1349
1527
  return base * POD_GAS_PRICE_BUFFER_BPS / 1000n;
1350
1528
  };
1351
1529
  getSepoliaGasPrice = resolvePodTxGasPrice;
1352
1530
  quotePortalFeeOnly = async (runner, portalAddress, amount, direction, gasPrice) => {
1353
1531
  const provider = resolveFeeRunnerProvider(runner);
1354
1532
  const resolvedGasPrice = gasPrice ?? await resolvePodTxGasPrice(provider);
1355
- const portal = new ethers7.Contract(portalAddress, PRIVACY_PORTAL_ABI, runner);
1533
+ const portal = new ethers8.Contract(portalAddress, PRIVACY_PORTAL_ABI, runner);
1356
1534
  if (direction === "to-private") {
1357
1535
  const [portalFee2, usedDynamicPricing2] = await portal.estimateDepositFees(amount);
1358
1536
  const quote2 = {
@@ -1384,8 +1562,8 @@ var init_podPortalFees = __esm({
1384
1562
  });
1385
1563
  return quote;
1386
1564
  };
1387
- formatPortalFeeDisplay = (portalFee, _usedDynamicPricing) => ethers7.formatEther(portalFee).replace(/\.?0+$/, "") || "0";
1388
- formatPodFeeDisplay = (totalFee) => ethers7.formatEther(totalFee).replace(/\.?0+$/, "") || "0";
1565
+ formatPortalFeeDisplay = (portalFee, _usedDynamicPricing) => ethers8.formatEther(portalFee).replace(/\.?0+$/, "") || "0";
1566
+ formatPodFeeDisplay = (totalFee) => ethers8.formatEther(totalFee).replace(/\.?0+$/, "") || "0";
1389
1567
  resolvePodFeeEstimationConfig = (chainId, direction, gasPrice) => {
1390
1568
  const limits = getChainConfig(chainId)?.podFeeEstimation?.[direction === "to-private" ? "deposit" : "withdraw"];
1391
1569
  if (!limits) {
@@ -1436,8 +1614,8 @@ var init_podPortalFees = __esm({
1436
1614
  { type: DataType.Uint256, value: "0", isCallBackFee: true },
1437
1615
  { type: DataType.Uint256, value: placeholderDeadline.toString(), isCallBackFee: false },
1438
1616
  { 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 }
1617
+ { type: DataType.String, value: ethers8.ZeroHash, isCallBackFee: false },
1618
+ { type: DataType.String, value: ethers8.ZeroHash, isCallBackFee: false }
1441
1619
  ];
1442
1620
  }
1443
1621
  return [
@@ -1465,8 +1643,8 @@ var init_podPortalFees = __esm({
1465
1643
  const fallbackLimit = fallbackExecutionGasLimit(params.chainId, params.direction);
1466
1644
  try {
1467
1645
  const rpcUrl = getRpcUrlForChain(params.chainId);
1468
- const rpcProvider = new ethers7.JsonRpcProvider(rpcUrl);
1469
- const portal = new ethers7.Contract(params.portalAddress, PRIVACY_PORTAL_ABI, rpcProvider);
1646
+ const rpcProvider = new ethers8.JsonRpcProvider(rpcUrl);
1647
+ const portal = new ethers8.Contract(params.portalAddress, PRIVACY_PORTAL_ABI, rpcProvider);
1470
1648
  if (params.direction === "to-private") {
1471
1649
  const method = resolvePodPortalMethod("to-private", params.isNativeDeposit);
1472
1650
  const nativeAmount = params.isNativeDeposit ? params.amountWei : 0n;
@@ -1483,8 +1661,8 @@ var init_podPortalFees = __esm({
1483
1661
  const permit = params.withdrawPermit;
1484
1662
  const deadline = permit ? BigInt(permit.deadline) : BigInt(Math.floor(Date.now() / 1e3) + 60 * 30);
1485
1663
  const v = permit?.v ?? 0;
1486
- const r = permit?.r ?? ethers7.ZeroHash;
1487
- const s = permit?.s ?? ethers7.ZeroHash;
1664
+ const r = permit?.r ?? ethers8.ZeroHash;
1665
+ const s = permit?.s ?? ethers8.ZeroHash;
1488
1666
  const gasLimit = await portal.requestWithdrawWithPermit.estimateGas(
1489
1667
  params.wallet,
1490
1668
  params.amountWei,
@@ -1531,8 +1709,8 @@ var init_podPortalFees = __esm({
1531
1709
  let supportsEip1559 = false;
1532
1710
  if (provider) {
1533
1711
  try {
1534
- const feeData = await provider.getFeeData();
1535
- supportsEip1559 = feeData.maxFeePerGas != null && feeData.maxPriorityFeePerGas != null;
1712
+ const block = await provider.getBlock("latest");
1713
+ supportsEip1559 = block?.baseFeePerGas != null;
1536
1714
  } catch {
1537
1715
  supportsEip1559 = false;
1538
1716
  }
@@ -1584,11 +1762,11 @@ var init_podPortalFees = __esm({
1584
1762
  });
1585
1763
 
1586
1764
  // src/chains/portal/executePodPortalTransaction.ts
1587
- import { ethers as ethers8 } from "ethers";
1765
+ import { ethers as ethers9 } from "ethers";
1588
1766
  async function signPodWithdrawPermit(params) {
1589
1767
  const { signer, pTokenAddress, portalAddress, amountWei } = params;
1590
1768
  const wallet = await signer.getAddress();
1591
- const pToken = new ethers8.Contract(pTokenAddress, POD_PTOKEN_ABI, signer);
1769
+ const pToken = new ethers9.Contract(pTokenAddress, POD_PTOKEN_ABI, signer);
1592
1770
  const signingChainId = params.chainId ?? Number((await signer.provider.getNetwork()).chainId);
1593
1771
  const resolvedTokenSymbol = params.tokenSymbol ?? await pToken.symbol().catch(() => void 0);
1594
1772
  await assertPodPTokenReady(pToken, wallet, "withdraw", {
@@ -1658,9 +1836,9 @@ async function executePodPortalTransaction(params) {
1658
1836
  throw new Error("PoD portal is not configured for this token");
1659
1837
  }
1660
1838
  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);
1839
+ const amountWei = ethers9.parseUnits(txAmount, decimals);
1840
+ const pToken = new ethers9.Contract(pTokenAddress, POD_PTOKEN_ABI, signer);
1841
+ const portalIface2 = new ethers9.Interface(PRIVACY_PORTAL_ABI);
1664
1842
  const gasPrice = await resolvePodTxGasPrice(provider);
1665
1843
  if (txDirection === "to-private") {
1666
1844
  await assertPodPTokenReady(pToken, wallet, "deposit", {
@@ -1689,7 +1867,7 @@ async function executePodPortalTransaction(params) {
1689
1867
  });
1690
1868
  let gasLimit2;
1691
1869
  try {
1692
- const portal = new ethers8.Contract(portalAddress, PRIVACY_PORTAL_ABI, signer);
1870
+ const portal = new ethers9.Contract(portalAddress, PRIVACY_PORTAL_ABI, signer);
1693
1871
  const nativeAmount = isNativeDeposit ? amountWei : 0n;
1694
1872
  const estimated = await portal[method2].estimateGas(
1695
1873
  wallet,
@@ -1721,7 +1899,9 @@ async function executePodPortalTransaction(params) {
1721
1899
  fee: podFee2
1722
1900
  });
1723
1901
  onProgress?.("transfer-start", tx2.hash);
1724
- const receipt2 = await tx2.wait();
1902
+ const receipt2 = await waitForTransactionResilient(chainId, tx2.hash, {
1903
+ primary: provider ?? signer.provider ?? void 0
1904
+ });
1725
1905
  if (!receipt2 || receipt2.status !== 1) {
1726
1906
  const failed = new Error("PoD deposit transaction failed");
1727
1907
  failed.txHash = tx2.hash;
@@ -1778,7 +1958,7 @@ async function executePodPortalTransaction(params) {
1778
1958
  });
1779
1959
  let gasLimit;
1780
1960
  try {
1781
- const portal = new ethers8.Contract(portalAddress, PRIVACY_PORTAL_ABI, signer);
1961
+ const portal = new ethers9.Contract(portalAddress, PRIVACY_PORTAL_ABI, signer);
1782
1962
  const estimated = await portal.requestWithdrawWithPermit.estimateGas(
1783
1963
  wallet,
1784
1964
  amountWei,
@@ -1812,7 +1992,9 @@ async function executePodPortalTransaction(params) {
1812
1992
  fee: podFee
1813
1993
  });
1814
1994
  onProgress?.("transfer-start", tx.hash);
1815
- const receipt = await tx.wait();
1995
+ const receipt = await waitForTransactionResilient(chainId, tx.hash, {
1996
+ primary: provider ?? signer.provider ?? void 0
1997
+ });
1816
1998
  if (!receipt || receipt.status !== 1) {
1817
1999
  const failed = new Error("Sepolia withdraw transaction failed");
1818
2000
  failed.txHash = tx.hash;
@@ -1846,13 +2028,14 @@ var init_executePodPortalTransaction = __esm({
1846
2028
  "use strict";
1847
2029
  init_pod();
1848
2030
  init_logger();
2031
+ init_rpcProvider();
1849
2032
  init_podPTokenBlockingDiagnostics();
1850
2033
  init_podPortalFees();
1851
2034
  init_podSdkConfig();
1852
2035
  init_podPortalFees();
1853
2036
  init_fees();
1854
2037
  getErrorMessage = (error) => error && typeof error === "object" && "message" in error && typeof error.message === "string" ? error.message : "";
1855
- pTokenErrorIface = new ethers8.Interface(POD_PTOKEN_ABI);
2038
+ pTokenErrorIface = new ethers9.Interface(POD_PTOKEN_ABI);
1856
2039
  extractRevertData = (error) => {
1857
2040
  if (!error || typeof error !== "object") return null;
1858
2041
  const err = error;
@@ -1908,7 +2091,7 @@ var init_executePodPortalTransaction = __esm({
1908
2091
  return null;
1909
2092
  };
1910
2093
  splitSignature = (signature) => {
1911
- const parsed = ethers8.Signature.from(signature);
2094
+ const parsed = ethers9.Signature.from(signature);
1912
2095
  return { v: parsed.v, r: parsed.r, s: parsed.s };
1913
2096
  };
1914
2097
  POD_PTOKEN_FLAT_STATUS_ABI = [
@@ -2055,7 +2238,7 @@ var init_executePodPortalTransaction = __esm({
2055
2238
  if (pendingFromRevert) return pendingFromRevert;
2056
2239
  probeErrors.push(`balanceWithState: ${getErrorMessage(error) || String(error)}`);
2057
2240
  }
2058
- const flatStatusToken = new ethers8.Contract(
2241
+ const flatStatusToken = new ethers9.Contract(
2059
2242
  pTokenAddress,
2060
2243
  POD_PTOKEN_FLAT_STATUS_ABI,
2061
2244
  pToken.runner
@@ -2090,7 +2273,7 @@ var init_executePodPortalTransaction = __esm({
2090
2273
  if (pendingFromRevert) return pendingFromRevert;
2091
2274
  probeErrors.push(`balanceOfWithStatus: ${getErrorMessage(error) || String(error)}`);
2092
2275
  }
2093
- const plainToken = new ethers8.Contract(
2276
+ const plainToken = new ethers9.Contract(
2094
2277
  pTokenAddress,
2095
2278
  POD_PTOKEN_PLAIN_STATUS_ABI,
2096
2279
  pToken.runner
@@ -2297,7 +2480,7 @@ var init_ethereum = __esm({
2297
2480
  });
2298
2481
 
2299
2482
  // src/chains/portal/podTransferFees.ts
2300
- import { ethers as ethers9 } from "ethers";
2483
+ import { ethers as ethers10 } from "ethers";
2301
2484
  import {
2302
2485
  DataType as DataType2,
2303
2486
  PodContract as PodContract2,
@@ -2427,8 +2610,8 @@ var init_podTransferFees = __esm({
2427
2610
  if (!overrides.gasLimit) {
2428
2611
  try {
2429
2612
  const rpcUrl = getRpcUrlForChain(params.chainId);
2430
- const rpcProvider = new ethers9.JsonRpcProvider(rpcUrl);
2431
- const pToken = new ethers9.Contract(params.pTokenAddress, POD_PTOKEN_ABI, rpcProvider);
2613
+ const rpcProvider = new ethers10.JsonRpcProvider(rpcUrl);
2614
+ const pToken = new ethers10.Contract(params.pTokenAddress, POD_PTOKEN_ABI, rpcProvider);
2432
2615
  const estimated = await pToken.getFunction(POD_TRANSFER_METHOD).estimateGas(...vals, {
2433
2616
  from: userAddress,
2434
2617
  value: fee.totalFee,
@@ -2506,7 +2689,7 @@ var init_utils = __esm({
2506
2689
  });
2507
2690
 
2508
2691
  // src/hooks/privacyBridge/executePrivateTokenTransfer.ts
2509
- import { ethers as ethers10 } from "ethers";
2692
+ import { ethers as ethers11 } from "ethers";
2510
2693
  function normalizeAesKeyHex(aesKey) {
2511
2694
  try {
2512
2695
  return normalizeAesKey(aesKey);
@@ -2532,10 +2715,10 @@ function resolvePrivateTokenTransferTarget(chainId, symbol) {
2532
2715
  };
2533
2716
  }
2534
2717
  function validatePrivateTransferInputs(tokenAddress, recipient, amount, walletAddress) {
2535
- if (!ethers10.isAddress(tokenAddress)) {
2718
+ if (!ethers11.isAddress(tokenAddress)) {
2536
2719
  throw new Error("Invalid token contract address");
2537
2720
  }
2538
- if (!ethers10.isAddress(recipient)) {
2721
+ if (!ethers11.isAddress(recipient)) {
2539
2722
  throw new Error("Invalid recipient address");
2540
2723
  }
2541
2724
  if (recipient.toLowerCase() === walletAddress.toLowerCase()) {
@@ -2548,7 +2731,7 @@ function validatePrivateTransferInputs(tokenAddress, recipient, amount, walletAd
2548
2731
  function parseTransferAmountWei(amount, decimals) {
2549
2732
  let amountWei;
2550
2733
  try {
2551
- amountWei = ethers10.parseUnits(amount, decimals);
2734
+ amountWei = ethers11.parseUnits(amount, decimals);
2552
2735
  } catch {
2553
2736
  throw new Error("Invalid amount for token decimals");
2554
2737
  }
@@ -2584,7 +2767,9 @@ async function submitPrivateTokenTransferTx(params) {
2584
2767
  recipient: shortHash(recipient),
2585
2768
  amount
2586
2769
  });
2587
- const browserProvider = new ethers10.BrowserProvider(eip1193);
2770
+ const browserProvider = new ethers11.BrowserProvider(eip1193);
2771
+ const network = await browserProvider.getNetwork();
2772
+ const chainId = Number(network.chainId);
2588
2773
  const rawTxHash = await eip1193.request({
2589
2774
  method: "eth_sendTransaction",
2590
2775
  params: [
@@ -2597,7 +2782,9 @@ async function submitPrivateTokenTransferTx(params) {
2597
2782
  ]
2598
2783
  });
2599
2784
  logger.log("Waiting for private transfer tx", { txHash: shortHash(rawTxHash) });
2600
- const receipt = await browserProvider.waitForTransaction(rawTxHash);
2785
+ const receipt = await waitForTransactionResilient(chainId, rawTxHash, {
2786
+ primary: browserProvider
2787
+ });
2601
2788
  if (!receipt || receipt.status !== 1) {
2602
2789
  throw new Error("Private token transfer failed");
2603
2790
  }
@@ -2635,10 +2822,10 @@ async function sendPrivateTokenTransfer(params) {
2635
2822
  if (!eip1193) {
2636
2823
  throw new Error("No wallet found");
2637
2824
  }
2638
- const browserProvider = new ethers10.BrowserProvider(eip1193);
2825
+ const browserProvider = new ethers11.BrowserProvider(eip1193);
2639
2826
  const signer = await browserProvider.getSigner(walletAddress);
2640
2827
  const amountWei = parseTransferAmountWei(amount, target.decimals);
2641
- const transferSig = ethers10.id(PRIVATE_ERC20_TRANSFER_256_SIG).slice(0, 10);
2828
+ const transferSig = ethers11.id(PRIVATE_ERC20_TRANSFER_256_SIG).slice(0, 10);
2642
2829
  let aesKey = sessionAesKey ? normalizeAesKeyHex(sessionAesKey) : null;
2643
2830
  if (!aesKey && hasSnap && getAESKeyFromSnap) {
2644
2831
  const snapKey = await getAESKeyFromSnap(walletAddress);
@@ -2673,6 +2860,7 @@ var init_executePrivateTokenTransfer = __esm({
2673
2860
  init_aesKey();
2674
2861
  init_ethereum();
2675
2862
  init_logger();
2863
+ init_rpcProvider();
2676
2864
  init_config();
2677
2865
  init_chains();
2678
2866
  init_chains();
@@ -2681,7 +2869,7 @@ var init_executePrivateTokenTransfer = __esm({
2681
2869
  PRIVATE_ERC20_TRANSFER_256_SIG = "transfer(address,((uint256,uint256),bytes))";
2682
2870
  GAS_ESTIMATE_BUFFER_PERCENT = 105n;
2683
2871
  CONFIDENTIAL_TRANSFER_GAS_LIMIT = 2000000n;
2684
- TRANSFER_INTERFACE = new ethers10.Interface([
2872
+ TRANSFER_INTERFACE = new ethers11.Interface([
2685
2873
  "function transfer(address to, tuple(tuple(uint256 ciphertextHigh, uint256 ciphertextLow) ciphertext, bytes signature) value) returns (uint256)"
2686
2874
  ]);
2687
2875
  }
@@ -2695,12 +2883,12 @@ __export(executePodPrivateTokenTransfer_exports, {
2695
2883
  quotePodPrivateTokenTransferFees: () => quotePodPrivateTokenTransferFees,
2696
2884
  quotePodTransferFees: () => quotePodTransferFees
2697
2885
  });
2698
- import { ethers as ethers11 } from "ethers";
2886
+ import { ethers as ethers12 } from "ethers";
2699
2887
  function validatePodTransferInputs(tokenAddress, recipient, amount, walletAddress) {
2700
- if (!ethers11.isAddress(tokenAddress)) {
2888
+ if (!ethers12.isAddress(tokenAddress)) {
2701
2889
  throw new Error("Invalid token contract address");
2702
2890
  }
2703
- if (!ethers11.isAddress(recipient)) {
2891
+ if (!ethers12.isAddress(recipient)) {
2704
2892
  throw new Error("Invalid recipient address");
2705
2893
  }
2706
2894
  if (recipient.toLowerCase() === walletAddress.toLowerCase()) {
@@ -2725,13 +2913,13 @@ async function executePodPrivateTokenTransfer(params) {
2725
2913
  if (!eip1193) {
2726
2914
  throw new Error("No wallet found");
2727
2915
  }
2728
- const browserProvider = new ethers11.BrowserProvider(eip1193);
2916
+ const browserProvider = new ethers12.BrowserProvider(eip1193);
2729
2917
  const signer = await browserProvider.getSigner(walletAddress);
2730
- const amountWei = ethers11.parseUnits(amount, target.decimals);
2918
+ const amountWei = ethers12.parseUnits(amount, target.decimals);
2731
2919
  if (amountWei <= 0n) {
2732
2920
  throw new Error("Amount must be greater than zero");
2733
2921
  }
2734
- const pToken = new ethers11.Contract(target.tokenAddress, POD_PTOKEN_ABI, signer);
2922
+ const pToken = new ethers12.Contract(target.tokenAddress, POD_PTOKEN_ABI, signer);
2735
2923
  await assertPodPTokenReady(pToken, walletAddress, "transfer", {
2736
2924
  chainId,
2737
2925
  tokenSymbol: symbol,
@@ -2763,13 +2951,15 @@ async function executePodPrivateTokenTransfer(params) {
2763
2951
  gasPrice,
2764
2952
  fee: podFee
2765
2953
  });
2766
- const receipt = await tx.wait();
2954
+ const receipt = await waitForTransactionResilient(chainId, tx.hash, {
2955
+ primary: browserProvider
2956
+ });
2767
2957
  if (!receipt || receipt.status !== 1) {
2768
2958
  const failed = new Error("PoD private token transfer failed");
2769
2959
  failed.txHash = tx.hash;
2770
2960
  throw failed;
2771
2961
  }
2772
- const event = findParsedEvent2(receipt, new ethers11.Interface(POD_PTOKEN_ABI), "TransferRequestSubmitted");
2962
+ const event = findParsedEvent2(receipt, new ethers12.Interface(POD_PTOKEN_ABI), "TransferRequestSubmitted");
2773
2963
  const requestId = event?.args?.requestId;
2774
2964
  return {
2775
2965
  txHash: tx.hash,
@@ -2799,10 +2989,10 @@ async function quotePodPrivateTokenTransferFees(params) {
2799
2989
  if (!eip1193) {
2800
2990
  throw new Error("No wallet found");
2801
2991
  }
2802
- const browserProvider = new ethers11.BrowserProvider(eip1193);
2992
+ const browserProvider = new ethers12.BrowserProvider(eip1193);
2803
2993
  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;
2994
+ const amountWei = ethers12.parseUnits(params.amount, target.decimals);
2995
+ const recipient = ethers12.isAddress(params.recipient) && params.recipient !== ethers12.ZeroAddress ? params.recipient : params.walletAddress;
2806
2996
  return quotePodTransferFees({
2807
2997
  runner: signer,
2808
2998
  chainId: params.chainId,
@@ -2819,6 +3009,7 @@ var init_executePodPrivateTokenTransfer = __esm({
2819
3009
  init_chains();
2820
3010
  init_ethereum();
2821
3011
  init_logger();
3012
+ init_rpcProvider();
2822
3013
  init_executePodPortalTransaction();
2823
3014
  init_podPortalFees();
2824
3015
  init_podTransferFees();
@@ -3396,7 +3587,7 @@ init_executePodPrivateTokenTransfer();
3396
3587
  init_logger();
3397
3588
  import { useState, useCallback, useEffect, useRef } from "react";
3398
3589
  import { useAccount } from "wagmi";
3399
- import { ethers as ethers12 } from "ethers";
3590
+ import { ethers as ethers13 } from "ethers";
3400
3591
  var usePodTransferFees = ({
3401
3592
  isConnected,
3402
3593
  walletAddress,
@@ -3453,7 +3644,7 @@ var usePodTransferFees = ({
3453
3644
  const quote = await quotePodPrivateTokenTransferFees({
3454
3645
  chainId,
3455
3646
  symbol,
3456
- recipient: recipient && ethers12.isAddress(recipient) ? recipient : walletAddress,
3647
+ recipient: recipient && ethers13.isAddress(recipient) ? recipient : walletAddress,
3457
3648
  amount: currentAmount,
3458
3649
  walletAddress,
3459
3650
  provider: injected6
@@ -3502,7 +3693,7 @@ var usePodTransferFees = ({
3502
3693
  init_chains();
3503
3694
  init_rpcUrls();
3504
3695
  init_logger();
3505
- import { ethers as ethers13 } from "ethers";
3696
+ import { ethers as ethers14 } from "ethers";
3506
3697
  var POD_PRICE_ORACLE_ABI = [
3507
3698
  "function getLivePrice(address token) view returns (uint256 priceUsd)",
3508
3699
  "function getLivePrices(address tokenA, address tokenB) view returns (uint256 priceA, uint256 priceB)"
@@ -3527,17 +3718,17 @@ async function fetchPodOracleTokenUsdPrice(symbol, chainId, provider) {
3527
3718
  return null;
3528
3719
  }
3529
3720
  const rpcUrls = provider ? [] : getRpcUrlsForChain(chainId);
3530
- const providers = provider ? [provider] : rpcUrls.map((url) => new ethers13.JsonRpcProvider(url));
3721
+ const providers = provider ? [provider] : rpcUrls.map((url) => new ethers14.JsonRpcProvider(url));
3531
3722
  let lastError;
3532
3723
  for (const rpcProvider of providers) {
3533
3724
  try {
3534
- const oracle = new ethers13.Contract(oracleAddress, POD_PRICE_ORACLE_ABI, rpcProvider);
3725
+ const oracle = new ethers14.Contract(oracleAddress, POD_PRICE_ORACLE_ABI, rpcProvider);
3535
3726
  const raw = await oracle.getLivePrice(tokenAddress);
3536
3727
  if (raw === 0n) {
3537
3728
  logger.warn(`PoD price oracle has no live feed for ${symbol} on chain ${chainId}`);
3538
3729
  return null;
3539
3730
  }
3540
- return Number(ethers13.formatEther(raw));
3731
+ return Number(ethers14.formatEther(raw));
3541
3732
  } catch (err) {
3542
3733
  lastError = err;
3543
3734
  }
@@ -3551,12 +3742,12 @@ async function fetchPodOracleTokenUsdPrice(symbol, chainId, provider) {
3551
3742
  init_pod();
3552
3743
  init_chains();
3553
3744
  init_rpcUrls();
3554
- import { ethers as ethers14 } from "ethers";
3745
+ import { ethers as ethers15 } from "ethers";
3555
3746
  init_logger();
3556
3747
  var ERC20_BALANCE_ABI = ["function balanceOf(address) view returns (uint256)"];
3557
3748
  var FEE_DIVISOR = 1000000n;
3558
3749
  var POD_NO_MAX_FEE_SENTINEL = (1n << 128n) - 1n;
3559
- var formatFee = (value) => value >= POD_NO_MAX_FEE_SENTINEL ? "0" : ethers14.formatEther(value);
3750
+ var formatFee = (value) => value >= POD_NO_MAX_FEE_SENTINEL ? "0" : ethers15.formatEther(value);
3560
3751
  async function fetchPortalRow(token, config, provider, nativeSymbol) {
3561
3752
  const portalAddress = config.addresses[token.bridgeAddressKey];
3562
3753
  const privateToken = config.tokens.find(
@@ -3583,12 +3774,12 @@ async function fetchPortalRow(token, config, provider, nativeSymbol) {
3583
3774
  isLoading: false
3584
3775
  };
3585
3776
  try {
3586
- const portal = new ethers14.Contract(portalAddress, POD_PORTAL_ADMIN_ABI, provider);
3777
+ const portal = new ethers15.Contract(portalAddress, POD_PORTAL_ADMIN_ABI, provider);
3587
3778
  const [depCfg, wdCfg, accFees, balance] = await Promise.all([
3588
3779
  portal.getFeeConfig(true),
3589
3780
  portal.getFeeConfig(false),
3590
3781
  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)
3782
+ 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
3783
  ]);
3593
3784
  return {
3594
3785
  ...base,
@@ -3598,8 +3789,8 @@ async function fetchPortalRow(token, config, provider, nativeSymbol) {
3598
3789
  withdrawFixedFee: formatFee(wdCfg[0]),
3599
3790
  withdrawPercentageBps: wdCfg[1].toString(),
3600
3791
  withdrawMaxFee: formatFee(wdCfg[2]),
3601
- accumulatedCotiFees: ethers14.formatEther(accFees),
3602
- bridgeBalance: ethers14.formatUnits(balance, token.decimals),
3792
+ accumulatedCotiFees: ethers15.formatEther(accFees),
3793
+ bridgeBalance: ethers15.formatUnits(balance, token.decimals),
3603
3794
  error: null
3604
3795
  };
3605
3796
  } catch (err) {
@@ -3627,7 +3818,7 @@ async function fetchPodBridgeData(chainId) {
3627
3818
  );
3628
3819
  let lastError;
3629
3820
  for (const rpcUrl of getRpcUrlsForChain(chainId)) {
3630
- const provider = new ethers14.JsonRpcProvider(rpcUrl);
3821
+ const provider = new ethers15.JsonRpcProvider(rpcUrl);
3631
3822
  try {
3632
3823
  await provider.getBlockNumber();
3633
3824
  return await Promise.all(
@@ -3646,7 +3837,7 @@ async function simulatePodPortalFee(chainId, tokenSymbol, amount, fixedFee, perc
3646
3837
  if (!config) return { fee: "\u2014", explanation: "Unsupported chain" };
3647
3838
  const token = config.tokens.find((t) => t.symbol === tokenSymbol && !t.isPrivate);
3648
3839
  if (!token) return { fee: "\u2014", explanation: "Unknown token" };
3649
- const amountWei = ethers14.parseUnits(amount, token.decimals);
3840
+ const amountWei = ethers15.parseUnits(amount, token.decimals);
3650
3841
  let valueInNative;
3651
3842
  if (token.isNative) {
3652
3843
  valueInNative = amountWei;
@@ -3657,27 +3848,27 @@ async function simulatePodPortalFee(chainId, tokenSymbol, amount, fixedFee, perc
3657
3848
  fetchPodOracleTokenUsdPrice(nativeSymbol, chainId)
3658
3849
  ]);
3659
3850
  if (!tokenUsd || !nativeUsd) {
3660
- const fixed = ethers14.parseEther(fixedFee || "0");
3661
- const cap = ethers14.parseEther(maxFee || "0");
3851
+ const fixed = ethers15.parseEther(fixedFee || "0");
3852
+ const cap = ethers15.parseEther(maxFee || "0");
3662
3853
  const fee2 = cap > 0n && fixed > cap ? cap : fixed;
3663
3854
  return {
3664
- fee: parseFloat(ethers14.formatEther(fee2)).toFixed(6),
3855
+ fee: parseFloat(ethers15.formatEther(fee2)).toFixed(6),
3665
3856
  explanation: "Fixed fee applied (no live oracle price)"
3666
3857
  };
3667
3858
  }
3668
- const tokenUsdWei = ethers14.parseEther(tokenUsd.toString());
3669
- const nativeUsdWei = ethers14.parseEther(nativeUsd.toString());
3859
+ const tokenUsdWei = ethers15.parseEther(tokenUsd.toString());
3860
+ const nativeUsdWei = ethers15.parseEther(nativeUsd.toString());
3670
3861
  const amount18 = amountWei * 10n ** BigInt(18 - token.decimals);
3671
3862
  valueInNative = amount18 * tokenUsdWei / nativeUsdWei;
3672
3863
  }
3673
- const fixedFeeWei = ethers14.parseEther(fixedFee || "0");
3674
- const maxFeeWei = ethers14.parseEther(maxFee || "0");
3864
+ const fixedFeeWei = ethers15.parseEther(fixedFee || "0");
3865
+ const maxFeeWei = ethers15.parseEther(maxFee || "0");
3675
3866
  const bps = BigInt(parseInt(percentageBps || "0", 10));
3676
3867
  const percentageFee = valueInNative * bps / FEE_DIVISOR;
3677
3868
  let fee = percentageFee > fixedFeeWei ? percentageFee : fixedFeeWei;
3678
3869
  if (maxFeeWei > 0n && fee > maxFeeWei) fee = maxFeeWei;
3679
3870
  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 };
3871
+ return { fee: parseFloat(ethers15.formatEther(fee)).toFixed(6), explanation };
3681
3872
  } catch (err) {
3682
3873
  logger.error("simulatePodPortalFee error:", err);
3683
3874
  return { fee: "\u2014", explanation: "Simulation failed" };
@@ -3700,7 +3891,7 @@ var LIMITS = {
3700
3891
  init_plugin();
3701
3892
  init_ethereum();
3702
3893
  import { useState as useState2, useCallback as useCallback2, useEffect as useEffect2, useRef as useRef2 } from "react";
3703
- import { ethers as ethers15 } from "ethers";
3894
+ import { ethers as ethers16 } from "ethers";
3704
3895
  init_logger();
3705
3896
 
3706
3897
  // src/lib/format.ts
@@ -3984,7 +4175,7 @@ var useMetamask = ({
3984
4175
  });
3985
4176
  const accounts = await eth.request({ method: "eth_requestAccounts" });
3986
4177
  if (!accounts || accounts.length === 0) return false;
3987
- const provider = new ethers15.BrowserProvider(eth);
4178
+ const provider = new ethers16.BrowserProvider(eth);
3988
4179
  const network = await provider.getNetwork();
3989
4180
  const envDefaultNetwork = getPluginConfig().defaultNetworkId;
3990
4181
  if (accounts.length > 0) {
@@ -4001,7 +4192,7 @@ var useMetamask = ({
4001
4192
  const eth = getMetaMaskProvider();
4002
4193
  if (!eth) return;
4003
4194
  try {
4004
- const provider = new ethers15.BrowserProvider(eth);
4195
+ const provider = new ethers16.BrowserProvider(eth);
4005
4196
  await checkNetwork(provider);
4006
4197
  if (onNetworkChanged) {
4007
4198
  await onNetworkChanged();
@@ -4238,97 +4429,8 @@ function decryptCtUint256(ciphertext, aesKey, options) {
4238
4429
  }
4239
4430
  }
4240
4431
 
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 readNestedRpcCode = (error) => {
4273
- const e = error;
4274
- return e.code ?? e.error?.code ?? e.info?.error?.code;
4275
- };
4276
- var readNestedHttpStatus = (error) => {
4277
- const e = error;
4278
- return e.data?.httpStatus ?? e.error?.data?.httpStatus ?? e.info?.responseStatus;
4279
- };
4280
- var isTransientRpcError = (error) => {
4281
- const text = collectErrorText(error);
4282
- const lower = text.toLowerCase();
4283
- 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")) {
4284
- return true;
4285
- }
4286
- if (error && typeof error === "object") {
4287
- const code = readNestedRpcCode(error);
4288
- if (code === "SERVER_ERROR" || code === "TIMEOUT" || code === "NETWORK_ERROR" || code === -32005 || code === "-32005") {
4289
- return true;
4290
- }
4291
- const httpStatus = readNestedHttpStatus(error);
4292
- if (httpStatus === 429 || httpStatus === "429") {
4293
- return true;
4294
- }
4295
- }
4296
- return false;
4297
- };
4298
- var createJsonRpcProvider = (url, chainId) => new ethers16.JsonRpcProvider(url, chainId);
4299
- var createResilientJsonRpcProvider = async (chainId) => {
4300
- const urls = resolveRpcUrlsForChain(chainId);
4301
- let lastError;
4302
- for (const url of urls) {
4303
- const provider = createJsonRpcProvider(url, chainId);
4304
- try {
4305
- await provider.getNetwork();
4306
- return provider;
4307
- } catch (error) {
4308
- lastError = error;
4309
- if (!isTransientRpcError(error)) throw error;
4310
- logger.warn(`[rpc] ${url} unavailable for chain ${chainId}, trying fallback`);
4311
- }
4312
- }
4313
- throw lastError instanceof Error ? lastError : new Error(`No RPC available for chain ${chainId}`);
4314
- };
4315
- var withRpcFallback = async (chainId, fn) => {
4316
- const urls = resolveRpcUrlsForChain(chainId);
4317
- let lastError;
4318
- for (const url of urls) {
4319
- const provider = createJsonRpcProvider(url, chainId);
4320
- try {
4321
- return await fn(provider);
4322
- } catch (error) {
4323
- lastError = error;
4324
- if (!isTransientRpcError(error)) throw error;
4325
- logger.warn(`[rpc] ${url} request failed for chain ${chainId}, trying fallback`);
4326
- }
4327
- }
4328
- throw lastError instanceof Error ? lastError : new Error(`All RPC endpoints failed for chain ${chainId}`);
4329
- };
4330
-
4331
4432
  // src/hooks/usePrivateTokenBalance.ts
4433
+ init_rpcProvider();
4332
4434
  init_plugin();
4333
4435
  init_logger();
4334
4436
  var PLAIN_BALANCE_ABI = [
@@ -4439,6 +4541,7 @@ var usePrivateTokenBalance = () => {
4439
4541
 
4440
4542
  // src/hooks/useBalanceUpdater.ts
4441
4543
  init_config();
4544
+ init_rpcProvider();
4442
4545
  import { useCallback as useCallback4, useRef as useRef3 } from "react";
4443
4546
  import { ethers as ethers19 } from "ethers";
4444
4547
 
@@ -4534,6 +4637,7 @@ import { encodeKey, encodeUint, encrypt, decryptUint as decryptUint2, decodeUint
4534
4637
  import { ethers as ethers18 } from "ethers";
4535
4638
  init_logger();
4536
4639
  init_config();
4640
+ init_rpcProvider();
4537
4641
  var ROUND_TRIP_TEST_VALUE = 0x0123456789abcdefn;
4538
4642
  var FLAT_BALANCE_ABI2 = [
4539
4643
  "function balanceOf(address) view returns (tuple(uint256 ciphertextHigh, uint256 ciphertextLow))"
@@ -5252,6 +5356,7 @@ import { useState as useState4, useCallback as useCallback7, useEffect as useEff
5252
5356
  import { useAccount as useAccount3 } from "wagmi";
5253
5357
  import { ethers as ethers22 } from "ethers";
5254
5358
  init_logger();
5359
+ init_rpcProvider();
5255
5360
  init_encryptValue256();
5256
5361
  init_utils();
5257
5362
  init_ethereum();
@@ -6231,7 +6336,9 @@ var usePrivacyBridgeAllowance = ({
6231
6336
  }]
6232
6337
  });
6233
6338
  logger.log("\u{1F510} [Approve] Tx submitted, waiting for confirmation", { txHash: shortHash(rawTxHash) });
6234
- await provider.waitForTransaction(rawTxHash);
6339
+ await waitForTransactionResilient(currentChainId, rawTxHash, {
6340
+ primary: provider
6341
+ });
6235
6342
  logger.log("\u{1F510} [Approve] Tx confirmed, refreshing allowance...");
6236
6343
  setIsApproving(false);
6237
6344
  setToastState((prev) => ({ ...prev, visible: false }));
@@ -6248,7 +6355,9 @@ var usePrivacyBridgeAllowance = ({
6248
6355
  title: "Approving...",
6249
6356
  message: "Waiting for allowance confirmation..."
6250
6357
  });
6251
- await tx.wait();
6358
+ await waitForTransactionResilient(currentChainId, tx.hash, {
6359
+ primary: provider
6360
+ });
6252
6361
  await checkAllowance();
6253
6362
  setIsApproving(false);
6254
6363
  setToastState((prev) => ({ ...prev, visible: false }));
@@ -6292,6 +6401,7 @@ import { useAccount as useAccount4 } from "wagmi";
6292
6401
  import { ethers as ethers23 } from "ethers";
6293
6402
  init_chains();
6294
6403
  init_logger();
6404
+ init_rpcProvider();
6295
6405
  init_utils();
6296
6406
  var usePrivacyBridgeExecutor = ({
6297
6407
  walletAddress,
@@ -6540,7 +6650,9 @@ var usePrivacyBridgeExecutor = ({
6540
6650
  logger.log("ERC20 deposit tx sent", { txHash: shortHash(rawDepositTxHash) });
6541
6651
  tx = {
6542
6652
  hash: rawDepositTxHash,
6543
- wait: async () => await provider.waitForTransaction(rawDepositTxHash)
6653
+ wait: async () => await waitForTransactionResilient(currentChainId, rawDepositTxHash, {
6654
+ primary: provider
6655
+ })
6544
6656
  };
6545
6657
  } else {
6546
6658
  logger.log("\u{1F504} Executing Native COTI Deposit...");
@@ -6697,7 +6809,9 @@ var usePrivacyBridgeExecutor = ({
6697
6809
  logger.log("Withdraw tx sent", { txHash: shortHash(rawWithdrawTxHash) });
6698
6810
  tx = {
6699
6811
  hash: rawWithdrawTxHash,
6700
- wait: async () => await provider.waitForTransaction(rawWithdrawTxHash)
6812
+ wait: async () => await waitForTransactionResilient(currentChainId, rawWithdrawTxHash, {
6813
+ primary: provider
6814
+ })
6701
6815
  };
6702
6816
  } catch (e) {
6703
6817
  setIsBridgingLoading(false);
@@ -6713,12 +6827,13 @@ var usePrivacyBridgeExecutor = ({
6713
6827
  title: "Processing Transaction",
6714
6828
  message: "Transaction sent to network. Waiting for confirmation..."
6715
6829
  });
6716
- const receipt = await tx.wait();
6830
+ const receipt = await waitForTransactionResilient(currentChainId, tx.hash, {
6831
+ primary: provider
6832
+ });
6717
6833
  logger.log("Transaction confirmed", {
6718
6834
  status: receipt.status,
6719
6835
  blockNumber: receipt.blockNumber,
6720
- gasUsed: receipt.gasUsed?.toString(),
6721
- gasLimit: receipt.gasLimit?.toString() ?? "n/a"
6836
+ gasUsed: receipt.gasUsed?.toString()
6722
6837
  });
6723
6838
  if (receipt.status !== 1) {
6724
6839
  const gasUsed = receipt.gasUsed ? Number(receipt.gasUsed) : 0;
@@ -6733,11 +6848,12 @@ var usePrivacyBridgeExecutor = ({
6733
6848
  const replayProvider = new ethers23.JsonRpcProvider(
6734
6849
  getRpcUrlForChain(Number(network2.chainId))
6735
6850
  );
6851
+ const broadcastTx = await replayProvider.getTransaction(txHashStr);
6736
6852
  await replayProvider.call({
6737
- to: receipt.to,
6738
- from: receipt.from,
6739
- data: receipt.data || void 0,
6740
- value: receipt.value || void 0
6853
+ to: broadcastTx?.to ?? receipt.to,
6854
+ from: broadcastTx?.from ?? receipt.from,
6855
+ data: broadcastTx?.data,
6856
+ value: broadcastTx?.value
6741
6857
  });
6742
6858
  } catch (replayErr) {
6743
6859
  const errorName = replayErr.errorName || replayErr.revert?.name;
@@ -7663,7 +7779,7 @@ async function fetchEncryptedBackupProbe(address, chainId) {
7663
7779
  return null;
7664
7780
  }
7665
7781
  }
7666
- var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7782
+ var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7667
7783
  function resolveAesKeyChainId(currentChainId, overrideChainId) {
7668
7784
  const configuredChainId = getPluginConfig().aesKeyChainId;
7669
7785
  assertAesKeyChainId(configuredChainId);
@@ -7683,7 +7799,7 @@ async function probeSnapKeyWithRetry(hasAesKeyInSnap, address, retries, confirmS
7683
7799
  for (let attempt = 0; attempt <= retries; attempt += 1) {
7684
7800
  const result = await hasAesKeyInSnap(address);
7685
7801
  if (result !== null) return result;
7686
- if (attempt < retries) await sleep(250);
7802
+ if (attempt < retries) await sleep2(250);
7687
7803
  }
7688
7804
  if (confirmSnapInstalled && !await confirmSnapInstalled()) {
7689
7805
  return false;
@@ -7976,7 +8092,7 @@ function toBigInt(value, fallback2) {
7976
8092
  if (value === void 0) return fallback2;
7977
8093
  return getBigInt(value);
7978
8094
  }
7979
- var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
8095
+ var sleep3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7980
8096
  function useAesKeyProvider(walletTypeInfo) {
7981
8097
  const [isOnboarding, setIsOnboarding] = useState11(false);
7982
8098
  const [onboardingError, setOnboardingError] = useState11(null);
@@ -8221,7 +8337,7 @@ function useAesKeyProvider(walletTypeInfo) {
8221
8337
  const timeoutMs = config.onboardingGrantTimeoutMs ?? 6e4;
8222
8338
  const startedAt = Date.now();
8223
8339
  while (nativeBalance < requiredBalanceWei && Date.now() - startedAt < timeoutMs) {
8224
- await sleep2(pollIntervalMs);
8340
+ await sleep3(pollIntervalMs);
8225
8341
  nativeBalance = await provider.getBalance(address);
8226
8342
  logger.log("[AesKeyProvider] Native COTI balance while waiting for grant", {
8227
8343
  address,