@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.js CHANGED
@@ -898,6 +898,190 @@ var init_podSdkConfig = __esm({
898
898
  }
899
899
  });
900
900
 
901
+ // src/lib/rpcProvider.ts
902
+ async function waitForTransactionResilient(chainId, txHash, options = {}) {
903
+ const {
904
+ confirmations = 1,
905
+ timeoutMs = 18e4,
906
+ pollIntervalMs = 2e3,
907
+ primary,
908
+ createProvider = createJsonRpcProvider
909
+ } = options;
910
+ if (!txHash) {
911
+ throw new Error("waitForTransactionResilient: missing transaction hash");
912
+ }
913
+ const deadline = Date.now() + timeoutMs;
914
+ let lastError;
915
+ if (primary) {
916
+ const remaining = Math.max(0, deadline - Date.now());
917
+ const primaryTimeout = Math.min(12e3, remaining);
918
+ if (primaryTimeout > 0) {
919
+ try {
920
+ const receipt = await primary.waitForTransaction(txHash, confirmations, primaryTimeout);
921
+ if (receipt) return receipt;
922
+ } catch (error) {
923
+ lastError = error;
924
+ if (isTransactionRevertError(error)) throw error;
925
+ if (!isTransientRpcError(error) && !isWaitTimeoutError(error)) throw error;
926
+ logger.warn(
927
+ `[rpc] primary waitForTransaction failed for ${txHash} on chain ${chainId}; polling via fallback RPCs`
928
+ );
929
+ }
930
+ }
931
+ }
932
+ let delay = pollIntervalMs;
933
+ while (Date.now() < deadline) {
934
+ try {
935
+ const receipt = await getTransactionReceiptAcrossRpcs(chainId, txHash, createProvider);
936
+ if (receipt) {
937
+ if (confirmations <= 1) return receipt;
938
+ const blockNumber = await withRpcFallback(chainId, (provider) => provider.getBlockNumber());
939
+ if (receipt.blockNumber + (confirmations - 1) <= blockNumber) {
940
+ return receipt;
941
+ }
942
+ }
943
+ } catch (error) {
944
+ lastError = error;
945
+ if (!isTransientRpcError(error)) throw error;
946
+ logger.warn(
947
+ `[rpc] receipt poll failed for ${txHash} on chain ${chainId}; retrying after backoff`
948
+ );
949
+ }
950
+ const remaining = deadline - Date.now();
951
+ if (remaining <= 0) break;
952
+ await sleep(Math.min(delay, remaining));
953
+ delay = Math.min(Math.floor(delay * 1.5), 8e3);
954
+ }
955
+ throw lastError instanceof Error ? lastError : new Error(
956
+ `Timed out waiting for transaction ${txHash} on chain ${chainId} after ${timeoutMs}ms`
957
+ );
958
+ }
959
+ async function getTransactionReceiptAcrossRpcs(chainId, txHash, createProvider = createJsonRpcProvider) {
960
+ const urls = resolveRpcUrlsForChain(chainId);
961
+ let lastError;
962
+ let sawNotFound = false;
963
+ for (const url of urls) {
964
+ const provider = createProvider(url, chainId);
965
+ try {
966
+ const receipt = await provider.getTransactionReceipt(txHash);
967
+ if (receipt) return receipt;
968
+ sawNotFound = true;
969
+ } catch (error) {
970
+ lastError = error;
971
+ if (!isTransientRpcError(error)) throw error;
972
+ logger.warn(`[rpc] ${url} getTransactionReceipt failed for chain ${chainId}, trying fallback`);
973
+ }
974
+ }
975
+ if (sawNotFound) return null;
976
+ throw lastError instanceof Error ? lastError : new Error(`All RPC endpoints failed reading receipt for ${txHash} on chain ${chainId}`);
977
+ }
978
+ var import_ethers5, resolveRpcUrlsForChain, collectErrorText, readNestedRpcCode, readNestedHttpStatus, isTransientRpcError, createJsonRpcProvider, isWaitTimeoutError, isTransactionRevertError, sleep, createResilientJsonRpcProvider, withRpcFallback;
979
+ var init_rpcProvider = __esm({
980
+ "src/lib/rpcProvider.ts"() {
981
+ "use strict";
982
+ import_ethers5 = require("ethers");
983
+ init_plugin();
984
+ init_coti();
985
+ init_rpcUrls();
986
+ init_sepolia();
987
+ init_logger();
988
+ resolveRpcUrlsForChain = (chainId) => {
989
+ const base = getRpcUrlsForChain(chainId);
990
+ const numericId = chainId == null ? void 0 : Number(chainId);
991
+ if (numericId == null || !Number.isFinite(numericId)) return base;
992
+ const plugin = getPluginConfig();
993
+ let override;
994
+ if (numericId === SEPOLIA_CHAIN_ID && plugin.sepoliaRpcUrl) {
995
+ override = plugin.sepoliaRpcUrl;
996
+ } else if (numericId === COTI_TESTNET_CHAIN_ID && plugin.cotiTestnetRpcUrl) {
997
+ override = plugin.cotiTestnetRpcUrl;
998
+ }
999
+ if (!override) return base;
1000
+ return [.../* @__PURE__ */ new Set([override, ...base])];
1001
+ };
1002
+ collectErrorText = (error) => {
1003
+ if (!error) return "";
1004
+ if (typeof error === "string") return error;
1005
+ if (error instanceof Error) return error.message;
1006
+ try {
1007
+ return JSON.stringify(error);
1008
+ } catch {
1009
+ return String(error);
1010
+ }
1011
+ };
1012
+ readNestedRpcCode = (error) => {
1013
+ const e = error;
1014
+ return e.code ?? e.error?.code ?? e.info?.error?.code;
1015
+ };
1016
+ readNestedHttpStatus = (error) => {
1017
+ const e = error;
1018
+ return e.data?.httpStatus ?? e.error?.data?.httpStatus ?? e.info?.responseStatus;
1019
+ };
1020
+ isTransientRpcError = (error) => {
1021
+ const text = collectErrorText(error);
1022
+ const lower = text.toLowerCase();
1023
+ 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")) {
1024
+ return true;
1025
+ }
1026
+ if (error && typeof error === "object") {
1027
+ const code = readNestedRpcCode(error);
1028
+ if (code === "SERVER_ERROR" || code === "TIMEOUT" || code === "NETWORK_ERROR" || code === -32005 || code === "-32005") {
1029
+ return true;
1030
+ }
1031
+ const httpStatus = readNestedHttpStatus(error);
1032
+ if (httpStatus === 429 || httpStatus === "429") {
1033
+ return true;
1034
+ }
1035
+ }
1036
+ return false;
1037
+ };
1038
+ createJsonRpcProvider = (url, chainId) => new import_ethers5.ethers.JsonRpcProvider(url, chainId);
1039
+ isWaitTimeoutError = (error) => {
1040
+ const text = collectErrorText(error).toLowerCase();
1041
+ return text.includes("timeout") || text.includes("timed out") || text.includes("waitfortx");
1042
+ };
1043
+ isTransactionRevertError = (error) => {
1044
+ if (!error || typeof error !== "object") return false;
1045
+ const code = error.code;
1046
+ return code === "CALL_EXCEPTION" || code === "TRANSACTION_REPLACED";
1047
+ };
1048
+ sleep = (ms) => new Promise((resolve) => {
1049
+ setTimeout(resolve, ms);
1050
+ });
1051
+ createResilientJsonRpcProvider = async (chainId) => {
1052
+ const urls = resolveRpcUrlsForChain(chainId);
1053
+ let lastError;
1054
+ for (const url of urls) {
1055
+ const provider = createJsonRpcProvider(url, chainId);
1056
+ try {
1057
+ await provider.getNetwork();
1058
+ return provider;
1059
+ } catch (error) {
1060
+ lastError = error;
1061
+ if (!isTransientRpcError(error)) throw error;
1062
+ logger.warn(`[rpc] ${url} unavailable for chain ${chainId}, trying fallback`);
1063
+ }
1064
+ }
1065
+ throw lastError instanceof Error ? lastError : new Error(`No RPC available for chain ${chainId}`);
1066
+ };
1067
+ withRpcFallback = async (chainId, fn) => {
1068
+ const urls = resolveRpcUrlsForChain(chainId);
1069
+ let lastError;
1070
+ for (const url of urls) {
1071
+ const provider = createJsonRpcProvider(url, chainId);
1072
+ try {
1073
+ return await fn(provider);
1074
+ } catch (error) {
1075
+ lastError = error;
1076
+ if (!isTransientRpcError(error)) throw error;
1077
+ logger.warn(`[rpc] ${url} request failed for chain ${chainId}, trying fallback`);
1078
+ }
1079
+ }
1080
+ throw lastError instanceof Error ? lastError : new Error(`All RPC endpoints failed for chain ${chainId}`);
1081
+ };
1082
+ }
1083
+ });
1084
+
901
1085
  // src/chains/portal/podPTokenBlockingDiagnostics.ts
902
1086
  async function diagnoseBlockingPodRequest(params) {
903
1087
  const {
@@ -967,11 +1151,11 @@ async function diagnoseBlockingPodRequest(params) {
967
1151
  eventScan
968
1152
  };
969
1153
  }
970
- var import_ethers5, import_pod_sdk2, TERMINAL_POD_REQUEST_STATUSES, pTokenIface, portalIface, formatBlockingPodLogSummary, chainIdToExplorerSlug2, withExplorerUrl, tokenMatchesContext, summarizeInFlightLocalPodRequests, summarizeLocalCandidates, isPodRequestStillInFlight, enrichWithPodTracking, POD_EVENT_LOOKBACK_STEPS, fetchLogsWithLookback, paddedAddressTopic, fetchRecentPTokenEvents, fetchRecentPortalEvents, dedupeCandidates, pickBlockingRequest;
1154
+ var import_ethers6, import_pod_sdk2, TERMINAL_POD_REQUEST_STATUSES, pTokenIface, portalIface, formatBlockingPodLogSummary, chainIdToExplorerSlug2, withExplorerUrl, tokenMatchesContext, summarizeInFlightLocalPodRequests, summarizeLocalCandidates, isPodRequestStillInFlight, enrichWithPodTracking, POD_EVENT_LOOKBACK_STEPS, fetchLogsWithLookback, paddedAddressTopic, fetchRecentPTokenEvents, fetchRecentPortalEvents, dedupeCandidates, pickBlockingRequest;
971
1155
  var init_podPTokenBlockingDiagnostics = __esm({
972
1156
  "src/chains/portal/podPTokenBlockingDiagnostics.ts"() {
973
1157
  "use strict";
974
- import_ethers5 = require("ethers");
1158
+ import_ethers6 = require("ethers");
975
1159
  import_pod_sdk2 = require("@coti-io/pod-sdk");
976
1160
  init_pod();
977
1161
  init_podPortalRequestsStorage();
@@ -982,8 +1166,8 @@ var init_podPTokenBlockingDiagnostics = __esm({
982
1166
  "callback-errored",
983
1167
  "burn-debt"
984
1168
  ]);
985
- pTokenIface = new import_ethers5.ethers.Interface(POD_PTOKEN_ABI);
986
- portalIface = new import_ethers5.ethers.Interface(PRIVACY_PORTAL_ABI);
1169
+ pTokenIface = new import_ethers6.ethers.Interface(POD_PTOKEN_ABI);
1170
+ portalIface = new import_ethers6.ethers.Interface(PRIVACY_PORTAL_ABI);
987
1171
  formatBlockingPodLogSummary = (blockingRequest, action) => {
988
1172
  if (!blockingRequest?.requestId) {
989
1173
  return `PoD ${action} blocked: wallet has on-chain pending=true but no requestId was resolved (check eventScan / candidateRequests in the log object below).`;
@@ -1112,7 +1296,7 @@ var init_podPTokenBlockingDiagnostics = __esm({
1112
1296
  }
1113
1297
  return { logs: [], lookbackBlocks: Number(lookbackSteps[lookbackSteps.length - 1]), errors };
1114
1298
  };
1115
- paddedAddressTopic = (address) => import_ethers5.ethers.zeroPadValue(import_ethers5.ethers.getAddress(address), 32);
1299
+ paddedAddressTopic = (address) => import_ethers6.ethers.zeroPadValue(import_ethers6.ethers.getAddress(address), 32);
1116
1300
  fetchRecentPTokenEvents = async (provider, pTokenAddress, account) => {
1117
1301
  const accountTopic = paddedAddressTopic(account);
1118
1302
  const errors = [];
@@ -1250,17 +1434,17 @@ var fees_exports = {};
1250
1434
  __export(fees_exports, {
1251
1435
  quotePodPortalTransactionFees: () => quotePodPortalTransactionFees
1252
1436
  });
1253
- var import_ethers6, quotePodPortalTransactionFees;
1437
+ var import_ethers7, quotePodPortalTransactionFees;
1254
1438
  var init_fees = __esm({
1255
1439
  "src/chains/portal/fees.ts"() {
1256
1440
  "use strict";
1257
- import_ethers6 = require("ethers");
1441
+ import_ethers7 = require("ethers");
1258
1442
  init_chains();
1259
1443
  init_logger();
1260
1444
  init_podPortalFees();
1261
1445
  quotePodPortalTransactionFees = async (params) => {
1262
1446
  const dec = params.pubTok?.decimals ?? 18;
1263
- const amountWei = import_ethers6.ethers.parseUnits(params.amount, dec);
1447
+ const amountWei = import_ethers7.ethers.parseUnits(params.amount, dec);
1264
1448
  const provider = "provider" in params.runner && params.runner.provider ? params.runner.provider : params.runner;
1265
1449
  const gasPrice = params.gasPrice ?? await resolvePodTxGasPrice(provider);
1266
1450
  const nativeSymbol = getChainConfig(params.chainId)?.walletNetwork.nativeCurrency.symbol ?? "ETH";
@@ -1333,11 +1517,11 @@ var init_fees = __esm({
1333
1517
  });
1334
1518
 
1335
1519
  // src/chains/portal/podPortalFees.ts
1336
- var import_ethers7, import_pod_sdk3, resolveFeeRunnerProvider, POD_GAS_PRICE_BUFFER_BPS, getPodGasPrice, resolvePodTxGasPrice, getSepoliaGasPrice, quotePortalFeeOnly, formatPortalFeeDisplay, formatPodFeeDisplay, resolvePodFeeEstimationConfig, resolvePodPortalMethod, buildPodMethodArgs, createPodContract, fallbackExecutionGasLimit, estimatePodExecutionGasWei, estimatePodFee, estimatePodPortalFees, buildPodPortalTxGasOverrides, sendPodPortalMethod;
1520
+ var import_ethers8, import_pod_sdk3, resolveFeeRunnerProvider, POD_GAS_PRICE_BUFFER_BPS, getPodGasPrice, resolvePodTxGasPrice, getSepoliaGasPrice, quotePortalFeeOnly, formatPortalFeeDisplay, formatPodFeeDisplay, resolvePodFeeEstimationConfig, resolvePodPortalMethod, buildPodMethodArgs, createPodContract, fallbackExecutionGasLimit, estimatePodExecutionGasWei, estimatePodFee, estimatePodPortalFees, buildPodPortalTxGasOverrides, sendPodPortalMethod;
1337
1521
  var init_podPortalFees = __esm({
1338
1522
  "src/chains/portal/podPortalFees.ts"() {
1339
1523
  "use strict";
1340
- import_ethers7 = require("ethers");
1524
+ import_ethers8 = require("ethers");
1341
1525
  import_pod_sdk3 = require("@coti-io/pod-sdk");
1342
1526
  init_pod();
1343
1527
  init_chains();
@@ -1357,20 +1541,14 @@ var init_podPortalFees = __esm({
1357
1541
  return BigInt(gasPriceHex);
1358
1542
  };
1359
1543
  resolvePodTxGasPrice = async (provider) => {
1360
- let base;
1361
- try {
1362
- const feeData = await provider.getFeeData();
1363
- base = feeData.gasPrice ?? await getPodGasPrice(provider);
1364
- } catch {
1365
- base = await getPodGasPrice(provider);
1366
- }
1544
+ const base = await getPodGasPrice(provider);
1367
1545
  return base * POD_GAS_PRICE_BUFFER_BPS / 1000n;
1368
1546
  };
1369
1547
  getSepoliaGasPrice = resolvePodTxGasPrice;
1370
1548
  quotePortalFeeOnly = async (runner, portalAddress, amount, direction, gasPrice) => {
1371
1549
  const provider = resolveFeeRunnerProvider(runner);
1372
1550
  const resolvedGasPrice = gasPrice ?? await resolvePodTxGasPrice(provider);
1373
- const portal = new import_ethers7.ethers.Contract(portalAddress, PRIVACY_PORTAL_ABI, runner);
1551
+ const portal = new import_ethers8.ethers.Contract(portalAddress, PRIVACY_PORTAL_ABI, runner);
1374
1552
  if (direction === "to-private") {
1375
1553
  const [portalFee2, usedDynamicPricing2] = await portal.estimateDepositFees(amount);
1376
1554
  const quote2 = {
@@ -1402,8 +1580,8 @@ var init_podPortalFees = __esm({
1402
1580
  });
1403
1581
  return quote;
1404
1582
  };
1405
- formatPortalFeeDisplay = (portalFee, _usedDynamicPricing) => import_ethers7.ethers.formatEther(portalFee).replace(/\.?0+$/, "") || "0";
1406
- formatPodFeeDisplay = (totalFee) => import_ethers7.ethers.formatEther(totalFee).replace(/\.?0+$/, "") || "0";
1583
+ formatPortalFeeDisplay = (portalFee, _usedDynamicPricing) => import_ethers8.ethers.formatEther(portalFee).replace(/\.?0+$/, "") || "0";
1584
+ formatPodFeeDisplay = (totalFee) => import_ethers8.ethers.formatEther(totalFee).replace(/\.?0+$/, "") || "0";
1407
1585
  resolvePodFeeEstimationConfig = (chainId, direction, gasPrice) => {
1408
1586
  const limits = getChainConfig(chainId)?.podFeeEstimation?.[direction === "to-private" ? "deposit" : "withdraw"];
1409
1587
  if (!limits) {
@@ -1454,8 +1632,8 @@ var init_podPortalFees = __esm({
1454
1632
  { type: import_pod_sdk3.DataType.Uint256, value: "0", isCallBackFee: true },
1455
1633
  { type: import_pod_sdk3.DataType.Uint256, value: placeholderDeadline.toString(), isCallBackFee: false },
1456
1634
  { type: import_pod_sdk3.DataType.Uint8, value: "0", isCallBackFee: false },
1457
- { type: import_pod_sdk3.DataType.String, value: import_ethers7.ethers.ZeroHash, isCallBackFee: false },
1458
- { type: import_pod_sdk3.DataType.String, value: import_ethers7.ethers.ZeroHash, isCallBackFee: false }
1635
+ { type: import_pod_sdk3.DataType.String, value: import_ethers8.ethers.ZeroHash, isCallBackFee: false },
1636
+ { type: import_pod_sdk3.DataType.String, value: import_ethers8.ethers.ZeroHash, isCallBackFee: false }
1459
1637
  ];
1460
1638
  }
1461
1639
  return [
@@ -1483,8 +1661,8 @@ var init_podPortalFees = __esm({
1483
1661
  const fallbackLimit = fallbackExecutionGasLimit(params.chainId, params.direction);
1484
1662
  try {
1485
1663
  const rpcUrl = getRpcUrlForChain(params.chainId);
1486
- const rpcProvider = new import_ethers7.ethers.JsonRpcProvider(rpcUrl);
1487
- const portal = new import_ethers7.ethers.Contract(params.portalAddress, PRIVACY_PORTAL_ABI, rpcProvider);
1664
+ const rpcProvider = new import_ethers8.ethers.JsonRpcProvider(rpcUrl);
1665
+ const portal = new import_ethers8.ethers.Contract(params.portalAddress, PRIVACY_PORTAL_ABI, rpcProvider);
1488
1666
  if (params.direction === "to-private") {
1489
1667
  const method = resolvePodPortalMethod("to-private", params.isNativeDeposit);
1490
1668
  const nativeAmount = params.isNativeDeposit ? params.amountWei : 0n;
@@ -1501,8 +1679,8 @@ var init_podPortalFees = __esm({
1501
1679
  const permit = params.withdrawPermit;
1502
1680
  const deadline = permit ? BigInt(permit.deadline) : BigInt(Math.floor(Date.now() / 1e3) + 60 * 30);
1503
1681
  const v = permit?.v ?? 0;
1504
- const r = permit?.r ?? import_ethers7.ethers.ZeroHash;
1505
- const s = permit?.s ?? import_ethers7.ethers.ZeroHash;
1682
+ const r = permit?.r ?? import_ethers8.ethers.ZeroHash;
1683
+ const s = permit?.s ?? import_ethers8.ethers.ZeroHash;
1506
1684
  const gasLimit = await portal.requestWithdrawWithPermit.estimateGas(
1507
1685
  params.wallet,
1508
1686
  params.amountWei,
@@ -1549,8 +1727,8 @@ var init_podPortalFees = __esm({
1549
1727
  let supportsEip1559 = false;
1550
1728
  if (provider) {
1551
1729
  try {
1552
- const feeData = await provider.getFeeData();
1553
- supportsEip1559 = feeData.maxFeePerGas != null && feeData.maxPriorityFeePerGas != null;
1730
+ const block = await provider.getBlock("latest");
1731
+ supportsEip1559 = block?.baseFeePerGas != null;
1554
1732
  } catch {
1555
1733
  supportsEip1559 = false;
1556
1734
  }
@@ -1605,7 +1783,7 @@ var init_podPortalFees = __esm({
1605
1783
  async function signPodWithdrawPermit(params) {
1606
1784
  const { signer, pTokenAddress, portalAddress, amountWei } = params;
1607
1785
  const wallet = await signer.getAddress();
1608
- const pToken = new import_ethers8.ethers.Contract(pTokenAddress, POD_PTOKEN_ABI, signer);
1786
+ const pToken = new import_ethers9.ethers.Contract(pTokenAddress, POD_PTOKEN_ABI, signer);
1609
1787
  const signingChainId = params.chainId ?? Number((await signer.provider.getNetwork()).chainId);
1610
1788
  const resolvedTokenSymbol = params.tokenSymbol ?? await pToken.symbol().catch(() => void 0);
1611
1789
  await assertPodPTokenReady(pToken, wallet, "withdraw", {
@@ -1675,9 +1853,9 @@ async function executePodPortalTransaction(params) {
1675
1853
  throw new Error("PoD portal is not configured for this token");
1676
1854
  }
1677
1855
  const wallet = await signer.getAddress();
1678
- const amountWei = import_ethers8.ethers.parseUnits(txAmount, decimals);
1679
- const pToken = new import_ethers8.ethers.Contract(pTokenAddress, POD_PTOKEN_ABI, signer);
1680
- const portalIface2 = new import_ethers8.ethers.Interface(PRIVACY_PORTAL_ABI);
1856
+ const amountWei = import_ethers9.ethers.parseUnits(txAmount, decimals);
1857
+ const pToken = new import_ethers9.ethers.Contract(pTokenAddress, POD_PTOKEN_ABI, signer);
1858
+ const portalIface2 = new import_ethers9.ethers.Interface(PRIVACY_PORTAL_ABI);
1681
1859
  const gasPrice = await resolvePodTxGasPrice(provider);
1682
1860
  if (txDirection === "to-private") {
1683
1861
  await assertPodPTokenReady(pToken, wallet, "deposit", {
@@ -1706,7 +1884,7 @@ async function executePodPortalTransaction(params) {
1706
1884
  });
1707
1885
  let gasLimit2;
1708
1886
  try {
1709
- const portal = new import_ethers8.ethers.Contract(portalAddress, PRIVACY_PORTAL_ABI, signer);
1887
+ const portal = new import_ethers9.ethers.Contract(portalAddress, PRIVACY_PORTAL_ABI, signer);
1710
1888
  const nativeAmount = isNativeDeposit ? amountWei : 0n;
1711
1889
  const estimated = await portal[method2].estimateGas(
1712
1890
  wallet,
@@ -1738,7 +1916,9 @@ async function executePodPortalTransaction(params) {
1738
1916
  fee: podFee2
1739
1917
  });
1740
1918
  onProgress?.("transfer-start", tx2.hash);
1741
- const receipt2 = await tx2.wait();
1919
+ const receipt2 = await waitForTransactionResilient(chainId, tx2.hash, {
1920
+ primary: provider ?? signer.provider ?? void 0
1921
+ });
1742
1922
  if (!receipt2 || receipt2.status !== 1) {
1743
1923
  const failed = new Error("PoD deposit transaction failed");
1744
1924
  failed.txHash = tx2.hash;
@@ -1795,7 +1975,7 @@ async function executePodPortalTransaction(params) {
1795
1975
  });
1796
1976
  let gasLimit;
1797
1977
  try {
1798
- const portal = new import_ethers8.ethers.Contract(portalAddress, PRIVACY_PORTAL_ABI, signer);
1978
+ const portal = new import_ethers9.ethers.Contract(portalAddress, PRIVACY_PORTAL_ABI, signer);
1799
1979
  const estimated = await portal.requestWithdrawWithPermit.estimateGas(
1800
1980
  wallet,
1801
1981
  amountWei,
@@ -1829,7 +2009,9 @@ async function executePodPortalTransaction(params) {
1829
2009
  fee: podFee
1830
2010
  });
1831
2011
  onProgress?.("transfer-start", tx.hash);
1832
- const receipt = await tx.wait();
2012
+ const receipt = await waitForTransactionResilient(chainId, tx.hash, {
2013
+ primary: provider ?? signer.provider ?? void 0
2014
+ });
1833
2015
  if (!receipt || receipt.status !== 1) {
1834
2016
  const failed = new Error("Sepolia withdraw transaction failed");
1835
2017
  failed.txHash = tx.hash;
@@ -1857,20 +2039,21 @@ async function executePodPortalTransaction(params) {
1857
2039
  }
1858
2040
  };
1859
2041
  }
1860
- var import_ethers8, getErrorMessage, pTokenErrorIface, extractRevertData, parseTransferAlreadyPendingRevert, pendingProbeFromRevert, findParsedEvent, splitSignature, POD_PTOKEN_FLAT_STATUS_ABI, POD_PTOKEN_PLAIN_STATUS_ABI, serializePodBalanceStatusResponse, readContractResultField, buildBalanceWithStateRaw, buildBalanceOfWithStatusRaw, formatBalanceStatusRawForLog, logBalanceStatusRawResponse, getContractProvider, logPodPTokenReadinessProbe, logPodPTokenReadinessBlocked, resolveBlockingRequestId, readPodPTokenPendingState, assertPodPTokenReady;
2042
+ var import_ethers9, getErrorMessage, pTokenErrorIface, extractRevertData, parseTransferAlreadyPendingRevert, pendingProbeFromRevert, findParsedEvent, splitSignature, POD_PTOKEN_FLAT_STATUS_ABI, POD_PTOKEN_PLAIN_STATUS_ABI, serializePodBalanceStatusResponse, readContractResultField, buildBalanceWithStateRaw, buildBalanceOfWithStatusRaw, formatBalanceStatusRawForLog, logBalanceStatusRawResponse, getContractProvider, logPodPTokenReadinessProbe, logPodPTokenReadinessBlocked, resolveBlockingRequestId, readPodPTokenPendingState, assertPodPTokenReady;
1861
2043
  var init_executePodPortalTransaction = __esm({
1862
2044
  "src/chains/portal/executePodPortalTransaction.ts"() {
1863
2045
  "use strict";
1864
- import_ethers8 = require("ethers");
2046
+ import_ethers9 = require("ethers");
1865
2047
  init_pod();
1866
2048
  init_logger();
2049
+ init_rpcProvider();
1867
2050
  init_podPTokenBlockingDiagnostics();
1868
2051
  init_podPortalFees();
1869
2052
  init_podSdkConfig();
1870
2053
  init_podPortalFees();
1871
2054
  init_fees();
1872
2055
  getErrorMessage = (error) => error && typeof error === "object" && "message" in error && typeof error.message === "string" ? error.message : "";
1873
- pTokenErrorIface = new import_ethers8.ethers.Interface(POD_PTOKEN_ABI);
2056
+ pTokenErrorIface = new import_ethers9.ethers.Interface(POD_PTOKEN_ABI);
1874
2057
  extractRevertData = (error) => {
1875
2058
  if (!error || typeof error !== "object") return null;
1876
2059
  const err = error;
@@ -1926,7 +2109,7 @@ var init_executePodPortalTransaction = __esm({
1926
2109
  return null;
1927
2110
  };
1928
2111
  splitSignature = (signature) => {
1929
- const parsed = import_ethers8.ethers.Signature.from(signature);
2112
+ const parsed = import_ethers9.ethers.Signature.from(signature);
1930
2113
  return { v: parsed.v, r: parsed.r, s: parsed.s };
1931
2114
  };
1932
2115
  POD_PTOKEN_FLAT_STATUS_ABI = [
@@ -2073,7 +2256,7 @@ var init_executePodPortalTransaction = __esm({
2073
2256
  if (pendingFromRevert) return pendingFromRevert;
2074
2257
  probeErrors.push(`balanceWithState: ${getErrorMessage(error) || String(error)}`);
2075
2258
  }
2076
- const flatStatusToken = new import_ethers8.ethers.Contract(
2259
+ const flatStatusToken = new import_ethers9.ethers.Contract(
2077
2260
  pTokenAddress,
2078
2261
  POD_PTOKEN_FLAT_STATUS_ABI,
2079
2262
  pToken.runner
@@ -2108,7 +2291,7 @@ var init_executePodPortalTransaction = __esm({
2108
2291
  if (pendingFromRevert) return pendingFromRevert;
2109
2292
  probeErrors.push(`balanceOfWithStatus: ${getErrorMessage(error) || String(error)}`);
2110
2293
  }
2111
- const plainToken = new import_ethers8.ethers.Contract(
2294
+ const plainToken = new import_ethers9.ethers.Contract(
2112
2295
  pTokenAddress,
2113
2296
  POD_PTOKEN_PLAIN_STATUS_ABI,
2114
2297
  pToken.runner
@@ -2315,11 +2498,11 @@ var init_ethereum = __esm({
2315
2498
  });
2316
2499
 
2317
2500
  // src/chains/portal/podTransferFees.ts
2318
- var import_ethers9, import_pod_sdk4, POD_TRANSFER_METHOD, POD_TRANSFER_FORWARD_DATA_SIZE, POD_TRANSFER_L1_EXECUTION_GAS_FALLBACK, createPodPTokenContract, buildPodTransferMethodArgs, resolvePodTransferFeeEstimationConfig, estimatePodTransferFee, fallbackTransferGasLimit, estimatePodTransferExecutionGasWei, resolveNativeFeeSymbol, quotePodTransferFees, sendPodTransferMethod;
2501
+ var import_ethers10, import_pod_sdk4, POD_TRANSFER_METHOD, POD_TRANSFER_FORWARD_DATA_SIZE, POD_TRANSFER_L1_EXECUTION_GAS_FALLBACK, createPodPTokenContract, buildPodTransferMethodArgs, resolvePodTransferFeeEstimationConfig, estimatePodTransferFee, fallbackTransferGasLimit, estimatePodTransferExecutionGasWei, resolveNativeFeeSymbol, quotePodTransferFees, sendPodTransferMethod;
2319
2502
  var init_podTransferFees = __esm({
2320
2503
  "src/chains/portal/podTransferFees.ts"() {
2321
2504
  "use strict";
2322
- import_ethers9 = require("ethers");
2505
+ import_ethers10 = require("ethers");
2323
2506
  import_pod_sdk4 = require("@coti-io/pod-sdk");
2324
2507
  init_pod();
2325
2508
  init_chains();
@@ -2441,8 +2624,8 @@ var init_podTransferFees = __esm({
2441
2624
  if (!overrides.gasLimit) {
2442
2625
  try {
2443
2626
  const rpcUrl = getRpcUrlForChain(params.chainId);
2444
- const rpcProvider = new import_ethers9.ethers.JsonRpcProvider(rpcUrl);
2445
- const pToken = new import_ethers9.ethers.Contract(params.pTokenAddress, POD_PTOKEN_ABI, rpcProvider);
2627
+ const rpcProvider = new import_ethers10.ethers.JsonRpcProvider(rpcUrl);
2628
+ const pToken = new import_ethers10.ethers.Contract(params.pTokenAddress, POD_PTOKEN_ABI, rpcProvider);
2446
2629
  const estimated = await pToken.getFunction(POD_TRANSFER_METHOD).estimateGas(...vals, {
2447
2630
  from: userAddress,
2448
2631
  value: fee.totalFee,
@@ -2546,10 +2729,10 @@ function resolvePrivateTokenTransferTarget(chainId, symbol) {
2546
2729
  };
2547
2730
  }
2548
2731
  function validatePrivateTransferInputs(tokenAddress, recipient, amount, walletAddress) {
2549
- if (!import_ethers10.ethers.isAddress(tokenAddress)) {
2732
+ if (!import_ethers11.ethers.isAddress(tokenAddress)) {
2550
2733
  throw new Error("Invalid token contract address");
2551
2734
  }
2552
- if (!import_ethers10.ethers.isAddress(recipient)) {
2735
+ if (!import_ethers11.ethers.isAddress(recipient)) {
2553
2736
  throw new Error("Invalid recipient address");
2554
2737
  }
2555
2738
  if (recipient.toLowerCase() === walletAddress.toLowerCase()) {
@@ -2562,7 +2745,7 @@ function validatePrivateTransferInputs(tokenAddress, recipient, amount, walletAd
2562
2745
  function parseTransferAmountWei(amount, decimals) {
2563
2746
  let amountWei;
2564
2747
  try {
2565
- amountWei = import_ethers10.ethers.parseUnits(amount, decimals);
2748
+ amountWei = import_ethers11.ethers.parseUnits(amount, decimals);
2566
2749
  } catch {
2567
2750
  throw new Error("Invalid amount for token decimals");
2568
2751
  }
@@ -2598,7 +2781,9 @@ async function submitPrivateTokenTransferTx(params) {
2598
2781
  recipient: shortHash(recipient),
2599
2782
  amount
2600
2783
  });
2601
- const browserProvider = new import_ethers10.ethers.BrowserProvider(eip1193);
2784
+ const browserProvider = new import_ethers11.ethers.BrowserProvider(eip1193);
2785
+ const network = await browserProvider.getNetwork();
2786
+ const chainId = Number(network.chainId);
2602
2787
  const rawTxHash = await eip1193.request({
2603
2788
  method: "eth_sendTransaction",
2604
2789
  params: [
@@ -2611,7 +2796,9 @@ async function submitPrivateTokenTransferTx(params) {
2611
2796
  ]
2612
2797
  });
2613
2798
  logger.log("Waiting for private transfer tx", { txHash: shortHash(rawTxHash) });
2614
- const receipt = await browserProvider.waitForTransaction(rawTxHash);
2799
+ const receipt = await waitForTransactionResilient(chainId, rawTxHash, {
2800
+ primary: browserProvider
2801
+ });
2615
2802
  if (!receipt || receipt.status !== 1) {
2616
2803
  throw new Error("Private token transfer failed");
2617
2804
  }
@@ -2649,10 +2836,10 @@ async function sendPrivateTokenTransfer(params) {
2649
2836
  if (!eip1193) {
2650
2837
  throw new Error("No wallet found");
2651
2838
  }
2652
- const browserProvider = new import_ethers10.ethers.BrowserProvider(eip1193);
2839
+ const browserProvider = new import_ethers11.ethers.BrowserProvider(eip1193);
2653
2840
  const signer = await browserProvider.getSigner(walletAddress);
2654
2841
  const amountWei = parseTransferAmountWei(amount, target.decimals);
2655
- const transferSig = import_ethers10.ethers.id(PRIVATE_ERC20_TRANSFER_256_SIG).slice(0, 10);
2842
+ const transferSig = import_ethers11.ethers.id(PRIVATE_ERC20_TRANSFER_256_SIG).slice(0, 10);
2656
2843
  let aesKey = sessionAesKey ? normalizeAesKeyHex(sessionAesKey) : null;
2657
2844
  if (!aesKey && hasSnap && getAESKeyFromSnap) {
2658
2845
  const snapKey = await getAESKeyFromSnap(walletAddress);
@@ -2680,14 +2867,15 @@ async function sendPrivateTokenTransfer(params) {
2680
2867
  provider: eip1193
2681
2868
  });
2682
2869
  }
2683
- var import_ethers10, PRIVATE_ERC20_TRANSFER_256_SIG, GAS_ESTIMATE_BUFFER_PERCENT, CONFIDENTIAL_TRANSFER_GAS_LIMIT, TRANSFER_INTERFACE;
2870
+ var import_ethers11, PRIVATE_ERC20_TRANSFER_256_SIG, GAS_ESTIMATE_BUFFER_PERCENT, CONFIDENTIAL_TRANSFER_GAS_LIMIT, TRANSFER_INTERFACE;
2684
2871
  var init_executePrivateTokenTransfer = __esm({
2685
2872
  "src/hooks/privacyBridge/executePrivateTokenTransfer.ts"() {
2686
2873
  "use strict";
2687
- import_ethers10 = require("ethers");
2874
+ import_ethers11 = require("ethers");
2688
2875
  init_aesKey();
2689
2876
  init_ethereum();
2690
2877
  init_logger();
2878
+ init_rpcProvider();
2691
2879
  init_config();
2692
2880
  init_chains();
2693
2881
  init_chains();
@@ -2696,7 +2884,7 @@ var init_executePrivateTokenTransfer = __esm({
2696
2884
  PRIVATE_ERC20_TRANSFER_256_SIG = "transfer(address,((uint256,uint256),bytes))";
2697
2885
  GAS_ESTIMATE_BUFFER_PERCENT = 105n;
2698
2886
  CONFIDENTIAL_TRANSFER_GAS_LIMIT = 2000000n;
2699
- TRANSFER_INTERFACE = new import_ethers10.ethers.Interface([
2887
+ TRANSFER_INTERFACE = new import_ethers11.ethers.Interface([
2700
2888
  "function transfer(address to, tuple(tuple(uint256 ciphertextHigh, uint256 ciphertextLow) ciphertext, bytes signature) value) returns (uint256)"
2701
2889
  ]);
2702
2890
  }
@@ -2711,10 +2899,10 @@ __export(executePodPrivateTokenTransfer_exports, {
2711
2899
  quotePodTransferFees: () => quotePodTransferFees
2712
2900
  });
2713
2901
  function validatePodTransferInputs(tokenAddress, recipient, amount, walletAddress) {
2714
- if (!import_ethers11.ethers.isAddress(tokenAddress)) {
2902
+ if (!import_ethers12.ethers.isAddress(tokenAddress)) {
2715
2903
  throw new Error("Invalid token contract address");
2716
2904
  }
2717
- if (!import_ethers11.ethers.isAddress(recipient)) {
2905
+ if (!import_ethers12.ethers.isAddress(recipient)) {
2718
2906
  throw new Error("Invalid recipient address");
2719
2907
  }
2720
2908
  if (recipient.toLowerCase() === walletAddress.toLowerCase()) {
@@ -2739,13 +2927,13 @@ async function executePodPrivateTokenTransfer(params) {
2739
2927
  if (!eip1193) {
2740
2928
  throw new Error("No wallet found");
2741
2929
  }
2742
- const browserProvider = new import_ethers11.ethers.BrowserProvider(eip1193);
2930
+ const browserProvider = new import_ethers12.ethers.BrowserProvider(eip1193);
2743
2931
  const signer = await browserProvider.getSigner(walletAddress);
2744
- const amountWei = import_ethers11.ethers.parseUnits(amount, target.decimals);
2932
+ const amountWei = import_ethers12.ethers.parseUnits(amount, target.decimals);
2745
2933
  if (amountWei <= 0n) {
2746
2934
  throw new Error("Amount must be greater than zero");
2747
2935
  }
2748
- const pToken = new import_ethers11.ethers.Contract(target.tokenAddress, POD_PTOKEN_ABI, signer);
2936
+ const pToken = new import_ethers12.ethers.Contract(target.tokenAddress, POD_PTOKEN_ABI, signer);
2749
2937
  await assertPodPTokenReady(pToken, walletAddress, "transfer", {
2750
2938
  chainId,
2751
2939
  tokenSymbol: symbol,
@@ -2777,13 +2965,15 @@ async function executePodPrivateTokenTransfer(params) {
2777
2965
  gasPrice,
2778
2966
  fee: podFee
2779
2967
  });
2780
- const receipt = await tx.wait();
2968
+ const receipt = await waitForTransactionResilient(chainId, tx.hash, {
2969
+ primary: browserProvider
2970
+ });
2781
2971
  if (!receipt || receipt.status !== 1) {
2782
2972
  const failed = new Error("PoD private token transfer failed");
2783
2973
  failed.txHash = tx.hash;
2784
2974
  throw failed;
2785
2975
  }
2786
- const event = findParsedEvent2(receipt, new import_ethers11.ethers.Interface(POD_PTOKEN_ABI), "TransferRequestSubmitted");
2976
+ const event = findParsedEvent2(receipt, new import_ethers12.ethers.Interface(POD_PTOKEN_ABI), "TransferRequestSubmitted");
2787
2977
  const requestId = event?.args?.requestId;
2788
2978
  return {
2789
2979
  txHash: tx.hash,
@@ -2813,10 +3003,10 @@ async function quotePodPrivateTokenTransferFees(params) {
2813
3003
  if (!eip1193) {
2814
3004
  throw new Error("No wallet found");
2815
3005
  }
2816
- const browserProvider = new import_ethers11.ethers.BrowserProvider(eip1193);
3006
+ const browserProvider = new import_ethers12.ethers.BrowserProvider(eip1193);
2817
3007
  const signer = await browserProvider.getSigner(params.walletAddress);
2818
- const amountWei = import_ethers11.ethers.parseUnits(params.amount, target.decimals);
2819
- const recipient = import_ethers11.ethers.isAddress(params.recipient) && params.recipient !== import_ethers11.ethers.ZeroAddress ? params.recipient : params.walletAddress;
3008
+ const amountWei = import_ethers12.ethers.parseUnits(params.amount, target.decimals);
3009
+ const recipient = import_ethers12.ethers.isAddress(params.recipient) && params.recipient !== import_ethers12.ethers.ZeroAddress ? params.recipient : params.walletAddress;
2820
3010
  return quotePodTransferFees({
2821
3011
  runner: signer,
2822
3012
  chainId: params.chainId,
@@ -2825,15 +3015,16 @@ async function quotePodPrivateTokenTransferFees(params) {
2825
3015
  amountWei
2826
3016
  });
2827
3017
  }
2828
- var import_ethers11, findParsedEvent2;
3018
+ var import_ethers12, findParsedEvent2;
2829
3019
  var init_executePodPrivateTokenTransfer = __esm({
2830
3020
  "src/chains/portal/executePodPrivateTokenTransfer.ts"() {
2831
3021
  "use strict";
2832
- import_ethers11 = require("ethers");
3022
+ import_ethers12 = require("ethers");
2833
3023
  init_pod();
2834
3024
  init_chains();
2835
3025
  init_ethereum();
2836
3026
  init_logger();
3027
+ init_rpcProvider();
2837
3028
  init_executePodPortalTransaction();
2838
3029
  init_podPortalFees();
2839
3030
  init_podTransferFees();
@@ -3554,7 +3745,7 @@ init_executePodPrivateTokenTransfer();
3554
3745
  // src/hooks/privacyBridge/usePodTransferFees.ts
3555
3746
  var import_react = require("react");
3556
3747
  var import_wagmi = require("wagmi");
3557
- var import_ethers12 = require("ethers");
3748
+ var import_ethers13 = require("ethers");
3558
3749
  init_chains();
3559
3750
  init_executePodPrivateTokenTransfer();
3560
3751
  init_logger();
@@ -3614,7 +3805,7 @@ var usePodTransferFees = ({
3614
3805
  const quote = await quotePodPrivateTokenTransferFees({
3615
3806
  chainId,
3616
3807
  symbol,
3617
- recipient: recipient && import_ethers12.ethers.isAddress(recipient) ? recipient : walletAddress,
3808
+ recipient: recipient && import_ethers13.ethers.isAddress(recipient) ? recipient : walletAddress,
3618
3809
  amount: currentAmount,
3619
3810
  walletAddress,
3620
3811
  provider: injected6
@@ -3660,7 +3851,7 @@ var usePodTransferFees = ({
3660
3851
  };
3661
3852
 
3662
3853
  // src/chains/podPriceOracle.ts
3663
- var import_ethers13 = require("ethers");
3854
+ var import_ethers14 = require("ethers");
3664
3855
  init_chains();
3665
3856
  init_rpcUrls();
3666
3857
  init_logger();
@@ -3688,17 +3879,17 @@ async function fetchPodOracleTokenUsdPrice(symbol, chainId, provider) {
3688
3879
  return null;
3689
3880
  }
3690
3881
  const rpcUrls = provider ? [] : getRpcUrlsForChain(chainId);
3691
- const providers = provider ? [provider] : rpcUrls.map((url) => new import_ethers13.ethers.JsonRpcProvider(url));
3882
+ const providers = provider ? [provider] : rpcUrls.map((url) => new import_ethers14.ethers.JsonRpcProvider(url));
3692
3883
  let lastError;
3693
3884
  for (const rpcProvider of providers) {
3694
3885
  try {
3695
- const oracle = new import_ethers13.ethers.Contract(oracleAddress, POD_PRICE_ORACLE_ABI, rpcProvider);
3886
+ const oracle = new import_ethers14.ethers.Contract(oracleAddress, POD_PRICE_ORACLE_ABI, rpcProvider);
3696
3887
  const raw = await oracle.getLivePrice(tokenAddress);
3697
3888
  if (raw === 0n) {
3698
3889
  logger.warn(`PoD price oracle has no live feed for ${symbol} on chain ${chainId}`);
3699
3890
  return null;
3700
3891
  }
3701
- return Number(import_ethers13.ethers.formatEther(raw));
3892
+ return Number(import_ethers14.ethers.formatEther(raw));
3702
3893
  } catch (err) {
3703
3894
  lastError = err;
3704
3895
  }
@@ -3709,7 +3900,7 @@ async function fetchPodOracleTokenUsdPrice(symbol, chainId, provider) {
3709
3900
  }
3710
3901
 
3711
3902
  // src/chains/portal/podPortalAdminData.ts
3712
- var import_ethers14 = require("ethers");
3903
+ var import_ethers15 = require("ethers");
3713
3904
  init_pod();
3714
3905
  init_chains();
3715
3906
  init_rpcUrls();
@@ -3717,7 +3908,7 @@ init_logger();
3717
3908
  var ERC20_BALANCE_ABI = ["function balanceOf(address) view returns (uint256)"];
3718
3909
  var FEE_DIVISOR = 1000000n;
3719
3910
  var POD_NO_MAX_FEE_SENTINEL = (1n << 128n) - 1n;
3720
- var formatFee = (value) => value >= POD_NO_MAX_FEE_SENTINEL ? "0" : import_ethers14.ethers.formatEther(value);
3911
+ var formatFee = (value) => value >= POD_NO_MAX_FEE_SENTINEL ? "0" : import_ethers15.ethers.formatEther(value);
3721
3912
  async function fetchPortalRow(token, config, provider, nativeSymbol) {
3722
3913
  const portalAddress = config.addresses[token.bridgeAddressKey];
3723
3914
  const privateToken = config.tokens.find(
@@ -3744,12 +3935,12 @@ async function fetchPortalRow(token, config, provider, nativeSymbol) {
3744
3935
  isLoading: false
3745
3936
  };
3746
3937
  try {
3747
- const portal = new import_ethers14.ethers.Contract(portalAddress, POD_PORTAL_ADMIN_ABI, provider);
3938
+ const portal = new import_ethers15.ethers.Contract(portalAddress, POD_PORTAL_ADMIN_ABI, provider);
3748
3939
  const [depCfg, wdCfg, accFees, balance] = await Promise.all([
3749
3940
  portal.getFeeConfig(true),
3750
3941
  portal.getFeeConfig(false),
3751
3942
  portal.accumulatedPortalFees().catch(() => 0n),
3752
- token.isNative ? provider.getBalance(portalAddress) : token.addressKey && config.addresses[token.addressKey] ? new import_ethers14.ethers.Contract(config.addresses[token.addressKey], ERC20_BALANCE_ABI, provider).balanceOf(portalAddress).catch(() => 0n) : Promise.resolve(0n)
3943
+ token.isNative ? provider.getBalance(portalAddress) : token.addressKey && config.addresses[token.addressKey] ? new import_ethers15.ethers.Contract(config.addresses[token.addressKey], ERC20_BALANCE_ABI, provider).balanceOf(portalAddress).catch(() => 0n) : Promise.resolve(0n)
3753
3944
  ]);
3754
3945
  return {
3755
3946
  ...base,
@@ -3759,8 +3950,8 @@ async function fetchPortalRow(token, config, provider, nativeSymbol) {
3759
3950
  withdrawFixedFee: formatFee(wdCfg[0]),
3760
3951
  withdrawPercentageBps: wdCfg[1].toString(),
3761
3952
  withdrawMaxFee: formatFee(wdCfg[2]),
3762
- accumulatedCotiFees: import_ethers14.ethers.formatEther(accFees),
3763
- bridgeBalance: import_ethers14.ethers.formatUnits(balance, token.decimals),
3953
+ accumulatedCotiFees: import_ethers15.ethers.formatEther(accFees),
3954
+ bridgeBalance: import_ethers15.ethers.formatUnits(balance, token.decimals),
3764
3955
  error: null
3765
3956
  };
3766
3957
  } catch (err) {
@@ -3788,7 +3979,7 @@ async function fetchPodBridgeData(chainId) {
3788
3979
  );
3789
3980
  let lastError;
3790
3981
  for (const rpcUrl of getRpcUrlsForChain(chainId)) {
3791
- const provider = new import_ethers14.ethers.JsonRpcProvider(rpcUrl);
3982
+ const provider = new import_ethers15.ethers.JsonRpcProvider(rpcUrl);
3792
3983
  try {
3793
3984
  await provider.getBlockNumber();
3794
3985
  return await Promise.all(
@@ -3807,7 +3998,7 @@ async function simulatePodPortalFee(chainId, tokenSymbol, amount, fixedFee, perc
3807
3998
  if (!config) return { fee: "\u2014", explanation: "Unsupported chain" };
3808
3999
  const token = config.tokens.find((t) => t.symbol === tokenSymbol && !t.isPrivate);
3809
4000
  if (!token) return { fee: "\u2014", explanation: "Unknown token" };
3810
- const amountWei = import_ethers14.ethers.parseUnits(amount, token.decimals);
4001
+ const amountWei = import_ethers15.ethers.parseUnits(amount, token.decimals);
3811
4002
  let valueInNative;
3812
4003
  if (token.isNative) {
3813
4004
  valueInNative = amountWei;
@@ -3818,27 +4009,27 @@ async function simulatePodPortalFee(chainId, tokenSymbol, amount, fixedFee, perc
3818
4009
  fetchPodOracleTokenUsdPrice(nativeSymbol, chainId)
3819
4010
  ]);
3820
4011
  if (!tokenUsd || !nativeUsd) {
3821
- const fixed = import_ethers14.ethers.parseEther(fixedFee || "0");
3822
- const cap = import_ethers14.ethers.parseEther(maxFee || "0");
4012
+ const fixed = import_ethers15.ethers.parseEther(fixedFee || "0");
4013
+ const cap = import_ethers15.ethers.parseEther(maxFee || "0");
3823
4014
  const fee2 = cap > 0n && fixed > cap ? cap : fixed;
3824
4015
  return {
3825
- fee: parseFloat(import_ethers14.ethers.formatEther(fee2)).toFixed(6),
4016
+ fee: parseFloat(import_ethers15.ethers.formatEther(fee2)).toFixed(6),
3826
4017
  explanation: "Fixed fee applied (no live oracle price)"
3827
4018
  };
3828
4019
  }
3829
- const tokenUsdWei = import_ethers14.ethers.parseEther(tokenUsd.toString());
3830
- const nativeUsdWei = import_ethers14.ethers.parseEther(nativeUsd.toString());
4020
+ const tokenUsdWei = import_ethers15.ethers.parseEther(tokenUsd.toString());
4021
+ const nativeUsdWei = import_ethers15.ethers.parseEther(nativeUsd.toString());
3831
4022
  const amount18 = amountWei * 10n ** BigInt(18 - token.decimals);
3832
4023
  valueInNative = amount18 * tokenUsdWei / nativeUsdWei;
3833
4024
  }
3834
- const fixedFeeWei = import_ethers14.ethers.parseEther(fixedFee || "0");
3835
- const maxFeeWei = import_ethers14.ethers.parseEther(maxFee || "0");
4025
+ const fixedFeeWei = import_ethers15.ethers.parseEther(fixedFee || "0");
4026
+ const maxFeeWei = import_ethers15.ethers.parseEther(maxFee || "0");
3836
4027
  const bps = BigInt(parseInt(percentageBps || "0", 10));
3837
4028
  const percentageFee = valueInNative * bps / FEE_DIVISOR;
3838
4029
  let fee = percentageFee > fixedFeeWei ? percentageFee : fixedFeeWei;
3839
4030
  if (maxFeeWei > 0n && fee > maxFeeWei) fee = maxFeeWei;
3840
4031
  const explanation = maxFeeWei > 0n && fee === maxFeeWei && fee !== fixedFeeWei ? "Max fee cap applied" : fee === fixedFeeWei ? "Fixed fee floor applied" : "Percentage fee applied";
3841
- return { fee: parseFloat(import_ethers14.ethers.formatEther(fee)).toFixed(6), explanation };
4032
+ return { fee: parseFloat(import_ethers15.ethers.formatEther(fee)).toFixed(6), explanation };
3842
4033
  } catch (err) {
3843
4034
  logger.error("simulatePodPortalFee error:", err);
3844
4035
  return { fee: "\u2014", explanation: "Simulation failed" };
@@ -3859,7 +4050,7 @@ var LIMITS = {
3859
4050
 
3860
4051
  // src/hooks/useMetamask.ts
3861
4052
  var import_react2 = require("react");
3862
- var import_ethers15 = require("ethers");
4053
+ var import_ethers16 = require("ethers");
3863
4054
  init_plugin();
3864
4055
  init_ethereum();
3865
4056
  init_logger();
@@ -4145,7 +4336,7 @@ var useMetamask = ({
4145
4336
  });
4146
4337
  const accounts = await eth.request({ method: "eth_requestAccounts" });
4147
4338
  if (!accounts || accounts.length === 0) return false;
4148
- const provider = new import_ethers15.ethers.BrowserProvider(eth);
4339
+ const provider = new import_ethers16.ethers.BrowserProvider(eth);
4149
4340
  const network = await provider.getNetwork();
4150
4341
  const envDefaultNetwork = getPluginConfig().defaultNetworkId;
4151
4342
  if (accounts.length > 0) {
@@ -4162,7 +4353,7 @@ var useMetamask = ({
4162
4353
  const eth = getMetaMaskProvider();
4163
4354
  if (!eth) return;
4164
4355
  try {
4165
- const provider = new import_ethers15.ethers.BrowserProvider(eth);
4356
+ const provider = new import_ethers16.ethers.BrowserProvider(eth);
4166
4357
  await checkNetwork(provider);
4167
4358
  if (onNetworkChanged) {
4168
4359
  await onNetworkChanged();
@@ -4396,97 +4587,8 @@ function decryptCtUint256(ciphertext, aesKey, options) {
4396
4587
  }
4397
4588
  }
4398
4589
 
4399
- // src/lib/rpcProvider.ts
4400
- var import_ethers16 = require("ethers");
4401
- init_plugin();
4402
- init_coti();
4403
- init_rpcUrls();
4404
- init_sepolia();
4405
- init_logger();
4406
- var resolveRpcUrlsForChain = (chainId) => {
4407
- const base = getRpcUrlsForChain(chainId);
4408
- const numericId = chainId == null ? void 0 : Number(chainId);
4409
- if (numericId == null || !Number.isFinite(numericId)) return base;
4410
- const plugin = getPluginConfig();
4411
- let override;
4412
- if (numericId === SEPOLIA_CHAIN_ID && plugin.sepoliaRpcUrl) {
4413
- override = plugin.sepoliaRpcUrl;
4414
- } else if (numericId === COTI_TESTNET_CHAIN_ID && plugin.cotiTestnetRpcUrl) {
4415
- override = plugin.cotiTestnetRpcUrl;
4416
- }
4417
- if (!override) return base;
4418
- return [.../* @__PURE__ */ new Set([override, ...base])];
4419
- };
4420
- var collectErrorText = (error) => {
4421
- if (!error) return "";
4422
- if (typeof error === "string") return error;
4423
- if (error instanceof Error) return error.message;
4424
- try {
4425
- return JSON.stringify(error);
4426
- } catch {
4427
- return String(error);
4428
- }
4429
- };
4430
- var readNestedRpcCode = (error) => {
4431
- const e = error;
4432
- return e.code ?? e.error?.code ?? e.info?.error?.code;
4433
- };
4434
- var readNestedHttpStatus = (error) => {
4435
- const e = error;
4436
- return e.data?.httpStatus ?? e.error?.data?.httpStatus ?? e.info?.responseStatus;
4437
- };
4438
- var isTransientRpcError = (error) => {
4439
- const text = collectErrorText(error);
4440
- const lower = text.toLowerCase();
4441
- 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")) {
4442
- return true;
4443
- }
4444
- if (error && typeof error === "object") {
4445
- const code = readNestedRpcCode(error);
4446
- if (code === "SERVER_ERROR" || code === "TIMEOUT" || code === "NETWORK_ERROR" || code === -32005 || code === "-32005") {
4447
- return true;
4448
- }
4449
- const httpStatus = readNestedHttpStatus(error);
4450
- if (httpStatus === 429 || httpStatus === "429") {
4451
- return true;
4452
- }
4453
- }
4454
- return false;
4455
- };
4456
- var createJsonRpcProvider = (url, chainId) => new import_ethers16.ethers.JsonRpcProvider(url, chainId);
4457
- var createResilientJsonRpcProvider = async (chainId) => {
4458
- const urls = resolveRpcUrlsForChain(chainId);
4459
- let lastError;
4460
- for (const url of urls) {
4461
- const provider = createJsonRpcProvider(url, chainId);
4462
- try {
4463
- await provider.getNetwork();
4464
- return provider;
4465
- } catch (error) {
4466
- lastError = error;
4467
- if (!isTransientRpcError(error)) throw error;
4468
- logger.warn(`[rpc] ${url} unavailable for chain ${chainId}, trying fallback`);
4469
- }
4470
- }
4471
- throw lastError instanceof Error ? lastError : new Error(`No RPC available for chain ${chainId}`);
4472
- };
4473
- var withRpcFallback = async (chainId, fn) => {
4474
- const urls = resolveRpcUrlsForChain(chainId);
4475
- let lastError;
4476
- for (const url of urls) {
4477
- const provider = createJsonRpcProvider(url, chainId);
4478
- try {
4479
- return await fn(provider);
4480
- } catch (error) {
4481
- lastError = error;
4482
- if (!isTransientRpcError(error)) throw error;
4483
- logger.warn(`[rpc] ${url} request failed for chain ${chainId}, trying fallback`);
4484
- }
4485
- }
4486
- throw lastError instanceof Error ? lastError : new Error(`All RPC endpoints failed for chain ${chainId}`);
4487
- };
4488
-
4489
4590
  // src/hooks/usePrivateTokenBalance.ts
4591
+ init_rpcProvider();
4490
4592
  init_plugin();
4491
4593
  init_logger();
4492
4594
  var PLAIN_BALANCE_ABI = [
@@ -4599,6 +4701,7 @@ var usePrivateTokenBalance = () => {
4599
4701
  var import_react4 = require("react");
4600
4702
  var import_ethers19 = require("ethers");
4601
4703
  init_config();
4704
+ init_rpcProvider();
4602
4705
 
4603
4706
  // src/lib/utils.ts
4604
4707
  var TOKEN_BALANCE_DISPLAY_DECIMALS = {
@@ -4692,6 +4795,7 @@ var import_ethers18 = require("ethers");
4692
4795
  init_aesKey();
4693
4796
  init_logger();
4694
4797
  init_config();
4798
+ init_rpcProvider();
4695
4799
  var ROUND_TRIP_TEST_VALUE = 0x0123456789abcdefn;
4696
4800
  var FLAT_BALANCE_ABI2 = [
4697
4801
  "function balanceOf(address) view returns (tuple(uint256 ciphertextHigh, uint256 ciphertextLow))"
@@ -5410,6 +5514,7 @@ init_config();
5410
5514
  init_executePodPortalTransaction();
5411
5515
  init_chains();
5412
5516
  init_logger();
5517
+ init_rpcProvider();
5413
5518
  init_encryptValue256();
5414
5519
  init_utils();
5415
5520
  init_ethereum();
@@ -6389,7 +6494,9 @@ var usePrivacyBridgeAllowance = ({
6389
6494
  }]
6390
6495
  });
6391
6496
  logger.log("\u{1F510} [Approve] Tx submitted, waiting for confirmation", { txHash: shortHash(rawTxHash) });
6392
- await provider.waitForTransaction(rawTxHash);
6497
+ await waitForTransactionResilient(currentChainId, rawTxHash, {
6498
+ primary: provider
6499
+ });
6393
6500
  logger.log("\u{1F510} [Approve] Tx confirmed, refreshing allowance...");
6394
6501
  setIsApproving(false);
6395
6502
  setToastState((prev) => ({ ...prev, visible: false }));
@@ -6406,7 +6513,9 @@ var usePrivacyBridgeAllowance = ({
6406
6513
  title: "Approving...",
6407
6514
  message: "Waiting for allowance confirmation..."
6408
6515
  });
6409
- await tx.wait();
6516
+ await waitForTransactionResilient(currentChainId, tx.hash, {
6517
+ primary: provider
6518
+ });
6410
6519
  await checkAllowance();
6411
6520
  setIsApproving(false);
6412
6521
  setToastState((prev) => ({ ...prev, visible: false }));
@@ -6450,6 +6559,7 @@ init_config();
6450
6559
  init_executePodPortalTransaction();
6451
6560
  init_chains();
6452
6561
  init_logger();
6562
+ init_rpcProvider();
6453
6563
  init_utils();
6454
6564
  var usePrivacyBridgeExecutor = ({
6455
6565
  walletAddress,
@@ -6698,7 +6808,9 @@ var usePrivacyBridgeExecutor = ({
6698
6808
  logger.log("ERC20 deposit tx sent", { txHash: shortHash(rawDepositTxHash) });
6699
6809
  tx = {
6700
6810
  hash: rawDepositTxHash,
6701
- wait: async () => await provider.waitForTransaction(rawDepositTxHash)
6811
+ wait: async () => await waitForTransactionResilient(currentChainId, rawDepositTxHash, {
6812
+ primary: provider
6813
+ })
6702
6814
  };
6703
6815
  } else {
6704
6816
  logger.log("\u{1F504} Executing Native COTI Deposit...");
@@ -6855,7 +6967,9 @@ var usePrivacyBridgeExecutor = ({
6855
6967
  logger.log("Withdraw tx sent", { txHash: shortHash(rawWithdrawTxHash) });
6856
6968
  tx = {
6857
6969
  hash: rawWithdrawTxHash,
6858
- wait: async () => await provider.waitForTransaction(rawWithdrawTxHash)
6970
+ wait: async () => await waitForTransactionResilient(currentChainId, rawWithdrawTxHash, {
6971
+ primary: provider
6972
+ })
6859
6973
  };
6860
6974
  } catch (e) {
6861
6975
  setIsBridgingLoading(false);
@@ -6871,12 +6985,13 @@ var usePrivacyBridgeExecutor = ({
6871
6985
  title: "Processing Transaction",
6872
6986
  message: "Transaction sent to network. Waiting for confirmation..."
6873
6987
  });
6874
- const receipt = await tx.wait();
6988
+ const receipt = await waitForTransactionResilient(currentChainId, tx.hash, {
6989
+ primary: provider
6990
+ });
6875
6991
  logger.log("Transaction confirmed", {
6876
6992
  status: receipt.status,
6877
6993
  blockNumber: receipt.blockNumber,
6878
- gasUsed: receipt.gasUsed?.toString(),
6879
- gasLimit: receipt.gasLimit?.toString() ?? "n/a"
6994
+ gasUsed: receipt.gasUsed?.toString()
6880
6995
  });
6881
6996
  if (receipt.status !== 1) {
6882
6997
  const gasUsed = receipt.gasUsed ? Number(receipt.gasUsed) : 0;
@@ -6891,11 +7006,12 @@ var usePrivacyBridgeExecutor = ({
6891
7006
  const replayProvider = new import_ethers23.ethers.JsonRpcProvider(
6892
7007
  getRpcUrlForChain(Number(network2.chainId))
6893
7008
  );
7009
+ const broadcastTx = await replayProvider.getTransaction(txHashStr);
6894
7010
  await replayProvider.call({
6895
- to: receipt.to,
6896
- from: receipt.from,
6897
- data: receipt.data || void 0,
6898
- value: receipt.value || void 0
7011
+ to: broadcastTx?.to ?? receipt.to,
7012
+ from: broadcastTx?.from ?? receipt.from,
7013
+ data: broadcastTx?.data,
7014
+ value: broadcastTx?.value
6899
7015
  });
6900
7016
  } catch (replayErr) {
6901
7017
  const errorName = replayErr.errorName || replayErr.revert?.name;
@@ -7821,7 +7937,7 @@ async function fetchEncryptedBackupProbe(address, chainId) {
7821
7937
  return null;
7822
7938
  }
7823
7939
  }
7824
- var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7940
+ var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
7825
7941
  function resolveAesKeyChainId(currentChainId, overrideChainId) {
7826
7942
  const configuredChainId = getPluginConfig().aesKeyChainId;
7827
7943
  assertAesKeyChainId(configuredChainId);
@@ -7841,7 +7957,7 @@ async function probeSnapKeyWithRetry(hasAesKeyInSnap, address, retries, confirmS
7841
7957
  for (let attempt = 0; attempt <= retries; attempt += 1) {
7842
7958
  const result = await hasAesKeyInSnap(address);
7843
7959
  if (result !== null) return result;
7844
- if (attempt < retries) await sleep(250);
7960
+ if (attempt < retries) await sleep2(250);
7845
7961
  }
7846
7962
  if (confirmSnapInstalled && !await confirmSnapInstalled()) {
7847
7963
  return false;
@@ -8134,7 +8250,7 @@ function toBigInt(value, fallback2) {
8134
8250
  if (value === void 0) return fallback2;
8135
8251
  return (0, import_ethers26.getBigInt)(value);
8136
8252
  }
8137
- var sleep2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
8253
+ var sleep3 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
8138
8254
  function useAesKeyProvider(walletTypeInfo) {
8139
8255
  const [isOnboarding, setIsOnboarding] = (0, import_react17.useState)(false);
8140
8256
  const [onboardingError, setOnboardingError] = (0, import_react17.useState)(null);
@@ -8379,7 +8495,7 @@ function useAesKeyProvider(walletTypeInfo) {
8379
8495
  const timeoutMs = config.onboardingGrantTimeoutMs ?? 6e4;
8380
8496
  const startedAt = Date.now();
8381
8497
  while (nativeBalance < requiredBalanceWei && Date.now() - startedAt < timeoutMs) {
8382
- await sleep2(pollIntervalMs);
8498
+ await sleep3(pollIntervalMs);
8383
8499
  nativeBalance = await provider.getBalance(address);
8384
8500
  logger.log("[AesKeyProvider] Native COTI balance while waiting for grant", {
8385
8501
  address,