@sidhujag/sysweb3-keyring 1.0.563 → 1.0.565

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.
@@ -21,6 +21,10 @@ const providers_1 = require("../providers");
21
21
  const types_1 = require("../types");
22
22
  class EthereumTransactions {
23
23
  constructor(getNetwork, getDecryptedPrivateKey, getState, ledgerSigner, trezorSigner) {
24
+ // Allow manual override of gas parameters when automatic estimation fails
25
+ this.gasOverrides = {};
26
+ // zkSync specific settings
27
+ this.isZkSyncNetwork = false;
24
28
  this.signTypedData = async (addr, typedData, version) => {
25
29
  const { address, decryptedPrivateKey } = this.getDecryptedPrivateKey();
26
30
  const { activeAccountType, accounts, activeAccountId } = this.getState();
@@ -370,23 +374,115 @@ class EthereumTransactions {
370
374
  this.getFeeDataWithDynamicMaxPriorityFeePerGas = async () => {
371
375
  let maxFeePerGas = this.toBigNumber(0);
372
376
  let maxPriorityFeePerGas = this.toBigNumber(0);
377
+ // Special handling for zkSync networks
378
+ if (this.isZkSyncNetwork) {
379
+ try {
380
+ // zkSync uses a different fee model
381
+ const gasPrice = await this.web3Provider.getGasPrice();
382
+ // zkSync recommends using gasPrice for both maxFeePerGas and maxPriorityFeePerGas
383
+ // with maxPriorityFeePerGas being a small portion (operator tip)
384
+ maxPriorityFeePerGas = gasPrice.div(100); // 1% as operator tip
385
+ maxFeePerGas = gasPrice.mul(120).div(100); // 20% buffer on gas price
386
+ console.log('[zkSync] Fee data:', {
387
+ maxFeePerGas: maxFeePerGas.toString(),
388
+ maxPriorityFeePerGas: maxPriorityFeePerGas.toString()
389
+ });
390
+ return { maxFeePerGas, maxPriorityFeePerGas };
391
+ }
392
+ catch (error) {
393
+ console.error('zkSync fee estimation failed:', error);
394
+ // Fallback for zkSync
395
+ return {
396
+ maxFeePerGas: bignumber_1.BigNumber.from('250000000'), // 0.25 gwei
397
+ maxPriorityFeePerGas: bignumber_1.BigNumber.from('2500000') // 0.0025 gwei
398
+ };
399
+ }
400
+ }
373
401
  try {
402
+ // First, try to get the current gas price as a baseline
403
+ const currentGasPrice = await this.web3Provider.getGasPrice();
374
404
  const block = await this.web3Provider.getBlock('latest');
375
405
  if (block && block.baseFeePerGas) {
376
406
  try {
407
+ // Some networks don't support this RPC method
377
408
  const ethMaxPriorityFee = await this.web3Provider.send('eth_maxPriorityFeePerGas', []);
378
409
  maxPriorityFeePerGas = bignumber_1.BigNumber.from(ethMaxPriorityFee);
379
- maxFeePerGas = block.baseFeePerGas.mul(2).add(maxPriorityFeePerGas);
410
+ // Apply minimum priority fee override if set
411
+ if (this.gasOverrides.minPriorityFee && maxPriorityFeePerGas.lt(this.gasOverrides.minPriorityFee)) {
412
+ maxPriorityFeePerGas = this.gasOverrides.minPriorityFee;
413
+ }
414
+ if (maxPriorityFeePerGas.isZero()) {
415
+ throw new Error('Max priority fee is zero');
416
+ }
417
+ // For networks with validation issues, use current gas price as baseline
418
+ // This ensures we're not setting fees that the network will reject
419
+ const baselineMaxFee = currentGasPrice.mul(120).div(100); // 20% above current gas price
420
+ // Calculate standard maxFeePerGas
421
+ const multiplier = this.gasOverrides.feeMultiplier || 250;
422
+ const calculatedMaxFee = block.baseFeePerGas.mul(multiplier).div(100).add(maxPriorityFeePerGas);
423
+ // Use the higher of the two to ensure transaction goes through
424
+ maxFeePerGas = calculatedMaxFee.gt(baselineMaxFee) ? calculatedMaxFee : baselineMaxFee;
380
425
  }
381
426
  catch (e) {
382
- maxPriorityFeePerGas = bignumber_1.BigNumber.from('1500000000');
383
- maxFeePerGas = block.baseFeePerGas.mul(2).add(maxPriorityFeePerGas);
427
+ // Use a more aggressive fallback strategy with higher priority fees
428
+ // Check if we can get fee history for better estimation
429
+ try {
430
+ const feeHistory = await this.web3Provider.send('eth_feeHistory', [
431
+ '0x5', // Last 5 blocks
432
+ 'latest',
433
+ [25, 50, 75] // Percentiles for priority fees
434
+ ]);
435
+ if (feeHistory && feeHistory.reward && feeHistory.reward.length > 0) {
436
+ // Use median of the 50th percentile from recent blocks
437
+ const recentFees = feeHistory.reward
438
+ .map((r) => r[1]) // Get 50th percentile
439
+ .filter((f) => f && f !== '0x0')
440
+ .map((f) => bignumber_1.BigNumber.from(f));
441
+ if (recentFees.length > 0) {
442
+ // Use the median value with a 50% buffer for better reliability
443
+ const sortedFees = recentFees.sort((a, b) => a.sub(b).isNegative() ? -1 : 1);
444
+ const medianFee = sortedFees[Math.floor(sortedFees.length / 2)];
445
+ maxPriorityFeePerGas = medianFee.mul(150).div(100); // Add 50% buffer
446
+ }
447
+ else {
448
+ // Fallback with higher default (5 gwei for better validation)
449
+ maxPriorityFeePerGas = bignumber_1.BigNumber.from('5000000000');
450
+ }
451
+ }
452
+ else {
453
+ // Fallback with higher default (5 gwei for better validation)
454
+ maxPriorityFeePerGas = bignumber_1.BigNumber.from('5000000000');
455
+ }
456
+ }
457
+ catch (feeHistoryError) {
458
+ // If fee history fails, use current gas price as reference
459
+ console.warn('Fee history not available, using gas price based estimation');
460
+ // Use 10% of current gas price as priority fee
461
+ const currentGasPrice = await this.web3Provider.getGasPrice();
462
+ maxPriorityFeePerGas = currentGasPrice.mul(10).div(100);
463
+ // Ensure minimum of 1 gwei
464
+ const minPriority = bignumber_1.BigNumber.from('1000000000');
465
+ if (maxPriorityFeePerGas.lt(minPriority)) {
466
+ maxPriorityFeePerGas = minPriority;
467
+ }
468
+ }
469
+ // Calculate maxFeePerGas based on current network conditions
470
+ const currentGasPrice = await this.web3Provider.getGasPrice();
471
+ const baselineMaxFee = currentGasPrice.mul(120).div(100);
472
+ const calculatedMaxFee = block.baseFeePerGas.mul(250).div(100).add(maxPriorityFeePerGas);
473
+ maxFeePerGas = calculatedMaxFee.gt(baselineMaxFee) ? calculatedMaxFee : baselineMaxFee;
474
+ }
475
+ // Ensure maxFeePerGas is at least 20% higher than maxPriorityFeePerGas
476
+ const minMaxFee = maxPriorityFeePerGas.mul(120).div(100);
477
+ if (maxFeePerGas.lt(minMaxFee)) {
478
+ maxFeePerGas = minMaxFee;
384
479
  }
385
480
  return { maxFeePerGas, maxPriorityFeePerGas };
386
481
  }
387
482
  else if (block && !block.baseFeePerGas) {
388
- console.error('Chain doesnt support EIP1559');
389
- return { maxFeePerGas, maxPriorityFeePerGas };
483
+ // For non-EIP1559 chains, return zeros to indicate legacy transaction should be used
484
+ console.log('Chain does not support EIP1559, use legacy transactions');
485
+ return { maxFeePerGas: bignumber_1.BigNumber.from(0), maxPriorityFeePerGas: bignumber_1.BigNumber.from(0) };
390
486
  }
391
487
  else if (!block)
392
488
  throw new Error('Block not found');
@@ -676,6 +772,63 @@ class EthereumTransactions {
676
772
  this.sendFormattedTransaction = async (params, isLegacy) => {
677
773
  const { activeAccountType, activeAccountId, accounts, activeNetwork } = this.getState();
678
774
  const activeAccount = accounts[activeAccountType][activeAccountId];
775
+ // zkSync specific handling
776
+ if (this.isZkSyncNetwork) {
777
+ // zkSync uses EIP-712 transactions but we can still use EIP-1559 format
778
+ // Ensure proper gas configuration for zkSync
779
+ if (!params.gasLimit || bignumber_1.BigNumber.from(params.gasLimit).lt(bignumber_1.BigNumber.from('500000'))) {
780
+ // zkSync typically needs higher gas limits
781
+ params.gasLimit = bignumber_1.BigNumber.from('1000000'); // 1M gas default for zkSync
782
+ console.log('[zkSync] Setting gas limit to 1M');
783
+ }
784
+ // Ensure we're using EIP-1559 for zkSync (not legacy)
785
+ if (isLegacy || params.gasPrice) {
786
+ console.log('[zkSync] Converting to EIP-1559 format');
787
+ isLegacy = false;
788
+ // Convert legacy to EIP-1559 for zkSync
789
+ const gasPrice = params.gasPrice ? bignumber_1.BigNumber.from(params.gasPrice) : await this.web3Provider.getGasPrice();
790
+ params.maxFeePerGas = gasPrice.mul(120).div(100); // 20% buffer
791
+ params.maxPriorityFeePerGas = gasPrice.div(100); // 1% operator tip for zkSync
792
+ delete params.gasPrice;
793
+ }
794
+ // Ensure proper fee structure for zkSync
795
+ if (params.maxFeePerGas && params.maxPriorityFeePerGas) {
796
+ const maxFee = bignumber_1.BigNumber.from(params.maxFeePerGas);
797
+ const priorityFee = bignumber_1.BigNumber.from(params.maxPriorityFeePerGas);
798
+ // zkSync requires maxPriorityFeePerGas to be much lower than maxFeePerGas
799
+ // Typically 1% or less of the maxFeePerGas
800
+ if (priorityFee.gt(maxFee.div(50))) {
801
+ params.maxPriorityFeePerGas = maxFee.div(100); // Set to 1% of maxFeePerGas
802
+ console.log('[zkSync] Adjusted priority fee to 1% of max fee');
803
+ }
804
+ }
805
+ }
806
+ // Check if we should force legacy transactions for non-zkSync networks
807
+ // Some networks have issues with EIP-1559 validation
808
+ if (!this.isZkSyncNetwork && !isLegacy && params.maxFeePerGas && params.maxPriorityFeePerGas) {
809
+ const maxFee = bignumber_1.BigNumber.from(params.maxFeePerGas);
810
+ const priorityFee = bignumber_1.BigNumber.from(params.maxPriorityFeePerGas);
811
+ // If fees are zero or network doesn't support EIP-1559, use legacy
812
+ if (maxFee.isZero() || priorityFee.isZero()) {
813
+ console.log('Switching to legacy transaction due to zero fees');
814
+ isLegacy = true;
815
+ // Convert to legacy by using gasPrice
816
+ const gasPrice = await this.web3Provider.getGasPrice();
817
+ params.gasPrice = gasPrice.mul(110).div(100); // 10% buffer
818
+ // @ts-ignore
819
+ delete params.maxFeePerGas;
820
+ // @ts-ignore
821
+ delete params.maxPriorityFeePerGas;
822
+ }
823
+ }
824
+ // Ensure minimum gas limit for validation
825
+ if (params.gasLimit) {
826
+ const minGasLimit = this.gasOverrides.minGasLimit || bignumber_1.BigNumber.from('65000');
827
+ const currentGasLimit = bignumber_1.BigNumber.from(params.gasLimit);
828
+ if (currentGasLimit.lt(minGasLimit)) {
829
+ params.gasLimit = minGasLimit;
830
+ }
831
+ }
679
832
  const sendEVMLedgerTransaction = async () => {
680
833
  const transactionNonce = await this.getRecommendedNonce(activeAccount.address);
681
834
  const formatParams = isLegacy
@@ -1837,11 +1990,73 @@ class EthereumTransactions {
1837
1990
  }
1838
1991
  };
1839
1992
  this.getTxGasLimit = async (tx) => {
1993
+ // Special handling for zkSync
1994
+ if (this.isZkSyncNetwork) {
1995
+ try {
1996
+ // zkSync requires special gas estimation
1997
+ // Use zks_estimateFee for more accurate estimation
1998
+ try {
1999
+ const zkEstimate = await this.web3Provider.send('zks_estimateFee', [{
2000
+ from: tx.from,
2001
+ to: tx.to,
2002
+ data: tx.data || '0x',
2003
+ value: tx.value ? `0x${bignumber_1.BigNumber.from(tx.value).toHexString().slice(2)}` : '0x0'
2004
+ }]);
2005
+ if (zkEstimate && zkEstimate.gas_limit) {
2006
+ const gasLimit = bignumber_1.BigNumber.from(zkEstimate.gas_limit);
2007
+ // Add 50% buffer for zkSync validation
2008
+ const withBuffer = gasLimit.mul(150).div(100);
2009
+ console.log('[zkSync] Gas limit estimated:', withBuffer.toString());
2010
+ return withBuffer;
2011
+ }
2012
+ }
2013
+ catch (zkError) {
2014
+ console.log('zks_estimateFee not available, using standard estimation');
2015
+ }
2016
+ // Fallback to standard estimation with higher buffer for zkSync
2017
+ const estimated = await this.web3Provider.estimateGas(tx);
2018
+ // zkSync needs more buffer for validation
2019
+ const withBuffer = estimated.mul(200).div(100); // 100% buffer
2020
+ console.log('[zkSync] Standard gas limit with buffer:', withBuffer.toString());
2021
+ return withBuffer;
2022
+ }
2023
+ catch (error) {
2024
+ console.warn('zkSync gas estimation failed, using high default');
2025
+ // zkSync typically needs more gas
2026
+ return bignumber_1.BigNumber.from('1000000'); // 1M gas for zkSync
2027
+ }
2028
+ }
1840
2029
  try {
1841
- return this.web3Provider.estimateGas(tx);
2030
+ // First attempt: standard estimation
2031
+ const estimated = await this.web3Provider.estimateGas(tx);
2032
+ // Apply override if set
2033
+ if (this.gasOverrides.minGasLimit && estimated.lt(this.gasOverrides.minGasLimit)) {
2034
+ return this.gasOverrides.minGasLimit;
2035
+ }
2036
+ // Add 20% buffer to the estimated gas
2037
+ const withBuffer = estimated.mul(120).div(100);
2038
+ // Ensure minimum of 65k for validation
2039
+ const minGas = bignumber_1.BigNumber.from('65000');
2040
+ return withBuffer.gt(minGas) ? withBuffer : minGas;
1842
2041
  }
1843
2042
  catch (error) {
1844
- throw error;
2043
+ console.warn('Gas estimation failed:', error);
2044
+ // Try a simpler estimation for basic transfers
2045
+ try {
2046
+ const simpleEstimate = await this.web3Provider.estimateGas({
2047
+ to: tx.to,
2048
+ from: tx.from,
2049
+ value: tx.value || '0x0'
2050
+ });
2051
+ const withBuffer = simpleEstimate.mul(150).div(100); // 50% buffer for failed estimations
2052
+ const minGas = this.gasOverrides.minGasLimit || bignumber_1.BigNumber.from('100000');
2053
+ return withBuffer.gt(minGas) ? withBuffer : minGas;
2054
+ }
2055
+ catch (secondError) {
2056
+ // Ultimate fallback
2057
+ console.warn('Simple estimation also failed, using default', secondError);
2058
+ return this.gasOverrides.minGasLimit || bignumber_1.BigNumber.from('100000');
2059
+ }
1845
2060
  }
1846
2061
  };
1847
2062
  this.getRecommendedGasPrice = async (formatted) => {
@@ -1884,6 +2099,50 @@ class EthereumTransactions {
1884
2099
  const account = new wallet_1.Wallet(privateKey);
1885
2100
  return account;
1886
2101
  };
2102
+ // Method to get safe fee data that works around network-specific validation issues
2103
+ this.getSafeFeeData = async (forceLegacy = false) => {
2104
+ if (forceLegacy) {
2105
+ // For legacy transactions, just return gas price
2106
+ const gasPrice = await this.web3Provider.getGasPrice();
2107
+ const bufferedGasPrice = gasPrice.mul(110).div(100); // 10% buffer
2108
+ return {
2109
+ gasPrice: bufferedGasPrice,
2110
+ maxFeePerGas: undefined,
2111
+ maxPriorityFeePerGas: undefined
2112
+ };
2113
+ }
2114
+ try {
2115
+ // Try EIP-1559 fees first
2116
+ const feeData = await this.getFeeDataWithDynamicMaxPriorityFeePerGas();
2117
+ // If fees are zero or too low, fallback to legacy
2118
+ if (!feeData.maxFeePerGas || feeData.maxFeePerGas.isZero() ||
2119
+ !feeData.maxPriorityFeePerGas || feeData.maxPriorityFeePerGas.isZero()) {
2120
+ console.log('EIP-1559 fees invalid, falling back to legacy gas price');
2121
+ const gasPrice = await this.web3Provider.getGasPrice();
2122
+ const bufferedGasPrice = gasPrice.mul(110).div(100);
2123
+ return {
2124
+ gasPrice: bufferedGasPrice,
2125
+ maxFeePerGas: undefined,
2126
+ maxPriorityFeePerGas: undefined
2127
+ };
2128
+ }
2129
+ return {
2130
+ gasPrice: undefined,
2131
+ maxFeePerGas: feeData.maxFeePerGas,
2132
+ maxPriorityFeePerGas: feeData.maxPriorityFeePerGas
2133
+ };
2134
+ }
2135
+ catch (error) {
2136
+ console.warn('Failed to get EIP-1559 fees, using legacy:', error);
2137
+ const gasPrice = await this.web3Provider.getGasPrice();
2138
+ const bufferedGasPrice = gasPrice.mul(110).div(100);
2139
+ return {
2140
+ gasPrice: bufferedGasPrice,
2141
+ maxFeePerGas: undefined,
2142
+ maxPriorityFeePerGas: undefined
2143
+ };
2144
+ }
2145
+ };
1887
2146
  this.getNetwork = getNetwork;
1888
2147
  this.getDecryptedPrivateKey = getDecryptedPrivateKey;
1889
2148
  this.abortController = new AbortController();
@@ -1922,9 +2181,26 @@ class EthereumTransactions {
1922
2181
  const hasUtxoKind = network.kind === sysweb3_network_1.INetworkType.Syscoin;
1923
2182
  return hasBlockbookUrl || hasUtxoKind;
1924
2183
  }
2184
+ // Helper method to detect zkSync networks
2185
+ detectZkSyncNetwork(network) {
2186
+ // zkSync detection patterns:
2187
+ // 1. Chain ID 324 for zkSync Era mainnet, 280 for zkSync Era testnet, 300 for zkSync Era Sepolia
2188
+ // 2. URL contains 'zksync'
2189
+ // 3. Network name contains 'zkSync'
2190
+ const zkSyncChainIds = [324, 280, 300];
2191
+ const isZkSyncChainId = zkSyncChainIds.includes(network.chainId);
2192
+ const hasZkSyncUrl = network.url?.toLowerCase().includes('zksync');
2193
+ const hasZkSyncName = network.label?.toLowerCase().includes('zksync');
2194
+ return isZkSyncChainId || hasZkSyncUrl || hasZkSyncName;
2195
+ }
1925
2196
  setWeb3Provider(network) {
1926
2197
  this.abortController.abort();
1927
2198
  this.abortController = new AbortController();
2199
+ // Detect if this is a zkSync network
2200
+ this.isZkSyncNetwork = this.detectZkSyncNetwork(network);
2201
+ if (this.isZkSyncNetwork) {
2202
+ console.log('[EthereumTransactions] Detected zkSync network, using zkSync-specific handling');
2203
+ }
1928
2204
  // Check if network is a UTXO network to avoid creating web3 providers for blockbook URLs
1929
2205
  const isUtxoNetwork = this.isUtxoNetwork(network);
1930
2206
  if (isUtxoNetwork) {
@@ -1937,6 +2213,18 @@ class EthereumTransactions {
1937
2213
  this._web3Provider = new providers_1.CustomJsonRpcProvider(this.abortController.signal, network.url);
1938
2214
  }
1939
2215
  }
2216
+ // Method to configure gas overrides for networks with validation issues
2217
+ setGasOverrides(overrides) {
2218
+ this.gasOverrides = {
2219
+ minGasLimit: overrides.minGasLimit ? bignumber_1.BigNumber.from(overrides.minGasLimit) : undefined,
2220
+ minPriorityFee: overrides.minPriorityFee ? bignumber_1.BigNumber.from(overrides.minPriorityFee) : undefined,
2221
+ feeMultiplier: overrides.feeMultiplier
2222
+ };
2223
+ }
2224
+ // Get the current gas overrides
2225
+ getGasOverrides() {
2226
+ return this.gasOverrides;
2227
+ }
1940
2228
  }
1941
2229
  exports.EthereumTransactions = EthereumTransactions;
1942
2230
  //# sourceMappingURL=ethereum.js.map