@sidhujag/sysweb3-keyring 1.0.615 → 1.0.617

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.
@@ -16,6 +16,55 @@ const evm_local_signer_1 = require("./evm-local-signer");
16
16
  const derivation_paths_1 = require("../utils/derivation-paths");
17
17
  const stripHexPrefix = (value) => value.startsWith('0x') || value.startsWith('0X') ? value.slice(2) : value;
18
18
  const normalizeEthersOverrideValue = (value) => (0, ethers_v6_1.normalizeTxValue)(value);
19
+ const nonNegativeFeeQuantity = (value, label) => {
20
+ // Match the exported BigNumberish object contract without trusting a
21
+ // private marker or BigNumber.from's null/empty-to-zero coercions. Normalize
22
+ // once so validation and conversion use the same integer representation.
23
+ if (value !== null && typeof value === 'object') {
24
+ const objectValue = value;
25
+ value =
26
+ objectValue._hex ??
27
+ objectValue.hex ??
28
+ (typeof objectValue.toString === 'function'
29
+ ? objectValue.toString()
30
+ : undefined);
31
+ if (typeof value !== 'string')
32
+ throw new Error(`Invalid ${label}`);
33
+ }
34
+ if (!((typeof value === 'string' && /^(?:0x[\da-f]+|\d+)$/i.test(value)) ||
35
+ (typeof value === 'number' &&
36
+ Number.isSafeInteger(value) &&
37
+ value >= 0) ||
38
+ (typeof value === 'bigint' && value >= 0n)))
39
+ throw new Error(`Invalid ${label}`);
40
+ const quantity = ethers_v6_1.BigNumber.from(value);
41
+ if (quantity.isNegative())
42
+ throw new Error(`Invalid ${label}`);
43
+ return quantity;
44
+ };
45
+ const isUnsupportedPriorityFeeRpc = (error) => {
46
+ const unsupportedCode = (code) => code === -32601 || code === 4200;
47
+ if (unsupportedCode(error?.code))
48
+ return true;
49
+ // Ethers' HTTP normalizer retains the matched JSON-RPC error and request
50
+ // under one of these two shapes. A generic outer unsupported/network error
51
+ // is not evidence that this particular RPC method is unavailable.
52
+ if (!['UNKNOWN_ERROR', 'UNSUPPORTED_OPERATION'].includes(error?.code)) {
53
+ return false;
54
+ }
55
+ if (error?.operation != null &&
56
+ error.operation !== 'eth_maxPriorityFeePerGas') {
57
+ return false;
58
+ }
59
+ return [
60
+ { cause: error.error, payload: error.payload },
61
+ { cause: error.info?.error, payload: error.info?.payload },
62
+ ].some(({ cause, payload }) => cause?.name !== 'AbortError' &&
63
+ unsupportedCode(cause?.code) &&
64
+ payload?.method === 'eth_maxPriorityFeePerGas' &&
65
+ Array.isArray(payload.params) &&
66
+ payload.params.length === 0);
67
+ };
19
68
  const normalizeEthersOverrides = (overrides) => {
20
69
  const normalized = { ...overrides };
21
70
  for (const field of [
@@ -429,119 +478,68 @@ class EthereumTransactions {
429
478
  }
430
479
  };
431
480
  this.getFeeDataWithDynamicMaxPriorityFeePerGas = async (provider = this.web3Provider) => {
432
- let maxFeePerGas = this.toBigNumber(0);
433
- let maxPriorityFeePerGas = this.toBigNumber(0);
481
+ // Keep the actual legacy-price recommendation separate from the buffered
482
+ // EIP-1559 maximum. A failed read is not evidence of a zero/legacy fee.
483
+ const gasPrice = nonNegativeFeeQuantity(await provider.getGasPrice(), 'gas price');
484
+ const block = await provider.getBlock('latest');
485
+ if (!block)
486
+ throw new Error('Block not found');
487
+ if (block.baseFeePerGas == null) {
488
+ return {
489
+ gasPrice,
490
+ maxFeePerGas: ethers_v6_1.BigNumber.from(0),
491
+ maxPriorityFeePerGas: ethers_v6_1.BigNumber.from(0),
492
+ };
493
+ }
494
+ const baseFeePerGas = nonNegativeFeeQuantity(block.baseFeePerGas, 'base fee');
495
+ let maxPriorityFeePerGas;
434
496
  try {
435
- // First, try to get the current gas price as a baseline
436
- const currentGasPrice = await provider.getGasPrice();
437
- const block = await provider.getBlock('latest');
438
- if (block && block.baseFeePerGas != null) {
439
- const baseFeePerGas = ethers_v6_1.BigNumber.from(block.baseFeePerGas);
440
- try {
441
- // Some networks don't support this RPC method
442
- const ethMaxPriorityFee = await provider.send('eth_maxPriorityFeePerGas', []);
443
- maxPriorityFeePerGas = ethers_v6_1.BigNumber.from(ethMaxPriorityFee);
444
- // Apply minimum priority fee override if set
445
- if (this.gasOverrides.minPriorityFee &&
446
- maxPriorityFeePerGas.lt(this.gasOverrides.minPriorityFee)) {
447
- maxPriorityFeePerGas = this.gasOverrides.minPriorityFee;
448
- }
449
- if (maxPriorityFeePerGas.isZero()) {
450
- throw new Error('Max priority fee is zero');
451
- }
452
- // For networks with validation issues, use current gas price as baseline
453
- // This ensures we're not setting fees that the network will reject
454
- const baselineMaxFee = currentGasPrice.mul(120).div(100); // 20% above current gas price
455
- // Calculate standard maxFeePerGas
456
- const multiplier = this.gasOverrides.feeMultiplier || 250;
457
- const calculatedMaxFee = baseFeePerGas
458
- .mul(multiplier)
459
- .div(100)
460
- .add(maxPriorityFeePerGas);
461
- // Use the higher of the two to ensure transaction goes through
462
- maxFeePerGas = calculatedMaxFee.gt(baselineMaxFee)
463
- ? calculatedMaxFee
464
- : baselineMaxFee;
465
- }
466
- catch (e) {
467
- // Use a more aggressive fallback strategy with higher priority fees
468
- // Check if we can get fee history for better estimation
469
- try {
470
- const feeHistory = await provider.send('eth_feeHistory', [
471
- '0x5', // Last 5 blocks
472
- 'latest',
473
- [25, 50, 75], // Percentiles for priority fees
474
- ]);
475
- if (feeHistory &&
476
- feeHistory.reward &&
477
- feeHistory.reward.length > 0) {
478
- // Use median of the 50th percentile from recent blocks
479
- const recentFees = feeHistory.reward
480
- .map((r) => r[1]) // Get 50th percentile
481
- .filter((f) => f && f !== '0x0')
482
- .map((f) => ethers_v6_1.BigNumber.from(f));
483
- if (recentFees.length > 0) {
484
- // Use the median value with a 50% buffer for better reliability
485
- const sortedFees = recentFees.sort((a, b) => a.sub(b).isNegative() ? -1 : 1);
486
- const medianFee = sortedFees[Math.floor(sortedFees.length / 2)];
487
- maxPriorityFeePerGas = medianFee.mul(150).div(100); // Add 50% buffer
488
- }
489
- else {
490
- // Fallback with higher default (5 gwei for better validation)
491
- maxPriorityFeePerGas = ethers_v6_1.BigNumber.from('5000000000');
492
- }
493
- }
494
- else {
495
- // Fallback with higher default (5 gwei for better validation)
496
- maxPriorityFeePerGas = ethers_v6_1.BigNumber.from('5000000000');
497
- }
498
- }
499
- catch (feeHistoryError) {
500
- // If fee history fails, use current gas price as reference
501
- console.warn('Fee history not available, using gas price based estimation');
502
- // Use 10% of current gas price as priority fee
503
- const currentGasPrice = await provider.getGasPrice();
504
- maxPriorityFeePerGas = currentGasPrice.mul(10).div(100);
505
- // Ensure minimum of 1 gwei
506
- const minPriority = ethers_v6_1.BigNumber.from('1000000000');
507
- if (maxPriorityFeePerGas.lt(minPriority)) {
508
- maxPriorityFeePerGas = minPriority;
509
- }
510
- }
511
- // Calculate maxFeePerGas based on current network conditions
512
- const currentGasPrice = await provider.getGasPrice();
513
- const baselineMaxFee = currentGasPrice.mul(120).div(100);
514
- const calculatedMaxFee = baseFeePerGas
515
- .mul(250)
516
- .div(100)
517
- .add(maxPriorityFeePerGas);
518
- maxFeePerGas = calculatedMaxFee.gt(baselineMaxFee)
519
- ? calculatedMaxFee
520
- : baselineMaxFee;
521
- }
522
- // Ensure maxFeePerGas is at least 20% higher than maxPriorityFeePerGas
523
- const minMaxFee = maxPriorityFeePerGas.mul(120).div(100);
524
- if (maxFeePerGas.lt(minMaxFee)) {
525
- maxFeePerGas = minMaxFee;
526
- }
527
- return { maxFeePerGas, maxPriorityFeePerGas };
528
- }
529
- else if (block && block.baseFeePerGas == null) {
530
- // For non-EIP1559 chains, return zeros to indicate legacy transaction should be used
531
- console.log('Chain does not support EIP1559, use legacy transactions');
532
- return {
533
- maxFeePerGas: ethers_v6_1.BigNumber.from(0),
534
- maxPriorityFeePerGas: ethers_v6_1.BigNumber.from(0),
535
- };
536
- }
537
- else if (!block)
538
- throw new Error('Block not found');
539
- return { maxFeePerGas, maxPriorityFeePerGas };
497
+ maxPriorityFeePerGas = nonNegativeFeeQuantity(await provider.send('eth_maxPriorityFeePerGas', []), 'priority fee');
540
498
  }
541
499
  catch (error) {
542
- console.error(error);
543
- return { maxFeePerGas, maxPriorityFeePerGas };
544
- }
500
+ if (error?.code === 'SYSWEB3_RPC_RESPONSE_INVALID' ||
501
+ error?.name === 'AbortError' ||
502
+ this.abortController.signal.aborted ||
503
+ provider.signal?.aborted ||
504
+ !isUnsupportedPriorityFeeRpc(error))
505
+ throw error;
506
+ // An explicitly unsupported method may use actual observed history,
507
+ // including zero rewards. Missing/corrupt history never invents a tip.
508
+ const history = await provider.send('eth_feeHistory', [
509
+ '0x5',
510
+ 'latest',
511
+ [25, 50, 75],
512
+ ]);
513
+ if (!Array.isArray(history?.reward) || history.reward.length === 0)
514
+ throw new Error('Priority fee history unavailable');
515
+ const recentFees = history.reward
516
+ .map((reward) => {
517
+ if (!Array.isArray(reward) || reward.length !== 3)
518
+ throw new Error('Invalid priority fee history');
519
+ return nonNegativeFeeQuantity(reward[1], 'priority fee history');
520
+ })
521
+ .sort((a, b) => (a.lt(b) ? -1 : a.gt(b) ? 1 : 0));
522
+ maxPriorityFeePerGas = recentFees[Math.floor(recentFees.length / 2)]
523
+ .mul(150)
524
+ .div(100);
525
+ }
526
+ if (this.gasOverrides.minPriorityFee &&
527
+ maxPriorityFeePerGas.lt(this.gasOverrides.minPriorityFee))
528
+ maxPriorityFeePerGas = this.gasOverrides.minPriorityFee;
529
+ const baselineMaxFee = gasPrice.mul(120).div(100);
530
+ const calculatedMaxFee = baseFeePerGas
531
+ .mul(this.gasOverrides.feeMultiplier || 250)
532
+ .div(100)
533
+ .add(maxPriorityFeePerGas);
534
+ let maxFeePerGas = calculatedMaxFee.gt(baselineMaxFee)
535
+ ? calculatedMaxFee
536
+ : baselineMaxFee;
537
+ const minMaxFee = maxPriorityFeePerGas.mul(120).div(100);
538
+ if (maxFeePerGas.lt(minMaxFee))
539
+ maxFeePerGas = minMaxFee;
540
+ if (maxFeePerGas.isZero())
541
+ throw new Error('Invalid EIP-1559 maximum fee');
542
+ return { gasPrice, baseFeePerGas, maxFeePerGas, maxPriorityFeePerGas };
545
543
  };
546
544
  this.calculateNewGasValues = (oldTxsParams, isForCancel, isLegacy) => {
547
545
  const newGasValues = {
@@ -584,13 +582,22 @@ class EthereumTransactions {
584
582
  this.cancelSentTransaction = async (txHash, isLegacy, fallbackNonce) => {
585
583
  const { activeAccountType, activeAccountId, accounts, activeNetwork } = this.getState();
586
584
  const activeAccount = accounts[activeAccountType][activeAccountId];
585
+ const currentEip1559Fees = async () => {
586
+ const feeData = await this.getFeeDataWithDynamicMaxPriorityFeePerGas();
587
+ const maxFeePerGas = nonNegativeFeeQuantity(feeData.maxFeePerGas, 'cancellation maximum fee');
588
+ const maxPriorityFeePerGas = nonNegativeFeeQuantity(feeData.maxPriorityFeePerGas, 'cancellation priority fee');
589
+ if (maxFeePerGas.isZero() || maxPriorityFeePerGas.gt(maxFeePerGas)) {
590
+ throw new Error('Invalid cancellation EIP-1559 fees');
591
+ }
592
+ return { maxFeePerGas, maxPriorityFeePerGas };
593
+ };
587
594
  let tx = (await this.web3Provider.getTransaction(txHash));
588
595
  // If transaction not found, create a minimal tx object with current gas prices
589
596
  // This handles cases where tx with 0 gas never made it to the mempool
590
597
  if (!tx && fallbackNonce !== undefined) {
591
598
  // Fetch current network gas prices for the cancellation
592
599
  if (isLegacy) {
593
- const currentGasPrice = await this.web3Provider.getGasPrice();
600
+ const currentGasPrice = nonNegativeFeeQuantity(await this.web3Provider.getGasPrice(), 'cancellation gas price');
594
601
  tx = {
595
602
  from: activeAccount.address,
596
603
  to: activeAccount.address,
@@ -602,14 +609,14 @@ class EthereumTransactions {
602
609
  };
603
610
  }
604
611
  else {
605
- const feeData = await this.getFeeDataWithDynamicMaxPriorityFeePerGas();
612
+ const feeData = await currentEip1559Fees();
606
613
  tx = {
607
614
  from: activeAccount.address,
608
615
  to: activeAccount.address,
609
616
  value: ethers_v6_1.Zero,
610
617
  nonce: fallbackNonce,
611
- maxFeePerGas: ethers_v6_1.BigNumber.from(feeData.maxFeePerGas || 0),
612
- maxPriorityFeePerGas: ethers_v6_1.BigNumber.from(feeData.maxPriorityFeePerGas || 0),
618
+ maxFeePerGas: feeData.maxFeePerGas,
619
+ maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
613
620
  gasLimit: ethers_v6_1.BigNumber.from(42000),
614
621
  data: '0x',
615
622
  };
@@ -630,7 +637,10 @@ class EthereumTransactions {
630
637
  gasLimit: tx.gasLimit,
631
638
  };
632
639
  if (isLegacy) {
633
- const currentGasPrice = await this.web3Provider.getGasPrice();
640
+ const currentGasPrice = nonNegativeFeeQuantity(await this.web3Provider.getGasPrice(), 'cancellation gas price');
641
+ if (oldTxsGasValues.gasPrice != null) {
642
+ oldTxsGasValues.gasPrice = nonNegativeFeeQuantity(oldTxsGasValues.gasPrice, 'original gas price');
643
+ }
634
644
  if (!oldTxsGasValues.gasPrice ||
635
645
  oldTxsGasValues.gasPrice.isZero() ||
636
646
  oldTxsGasValues.gasPrice.lt(currentGasPrice)) {
@@ -638,13 +648,13 @@ class EthereumTransactions {
638
648
  }
639
649
  }
640
650
  else {
641
- const currentGasPrice = await this.web3Provider.getGasPrice();
642
- const feeData = await this.getFeeDataWithDynamicMaxPriorityFeePerGas();
643
- const currentMaxFeePerGas = ethers_v6_1.BigNumber.from(feeData.maxFeePerGas || 0);
644
- const currentPriorityFeePerGas = ethers_v6_1.BigNumber.from(feeData.maxPriorityFeePerGas || 0);
645
- const currentMaxPriorityFeePerGas = currentPriorityFeePerGas.isZero()
646
- ? currentGasPrice
647
- : currentPriorityFeePerGas;
651
+ const { maxFeePerGas: currentMaxFeePerGas, maxPriorityFeePerGas: currentMaxPriorityFeePerGas, } = await currentEip1559Fees();
652
+ if (oldTxsGasValues.maxFeePerGas != null) {
653
+ oldTxsGasValues.maxFeePerGas = nonNegativeFeeQuantity(oldTxsGasValues.maxFeePerGas, 'original maximum fee');
654
+ }
655
+ if (oldTxsGasValues.maxPriorityFeePerGas != null) {
656
+ oldTxsGasValues.maxPriorityFeePerGas = nonNegativeFeeQuantity(oldTxsGasValues.maxPriorityFeePerGas, 'original priority fee');
657
+ }
648
658
  if (!oldTxsGasValues.maxFeePerGas ||
649
659
  oldTxsGasValues.maxFeePerGas.isZero() ||
650
660
  oldTxsGasValues.maxFeePerGas.lt(currentMaxFeePerGas)) {
@@ -658,7 +668,24 @@ class EthereumTransactions {
658
668
  oldTxsGasValues.maxFeePerGas = oldTxsGasValues.maxPriorityFeePerGas;
659
669
  }
660
670
  }
661
- const newGasValues = this.calculateNewGasValues(oldTxsGasValues, true, isLegacy || false);
671
+ // Preserve the existing 20% replacement policy with exact integer math.
672
+ // Nodes also require a strictly larger cap and tip than an old pending
673
+ // transaction; zero/small fees therefore need at least a one-wei bump.
674
+ // This is a replacement bump, not a fabricated network priority floor.
675
+ const bumpCancelFee = (fee) => {
676
+ const percentageBump = fee.mul(120).div(100);
677
+ const strictBump = fee.add(1);
678
+ return percentageBump.gt(strictBump) ? percentageBump : strictBump;
679
+ };
680
+ const newGasValues = {
681
+ gasLimit: ethers_v6_1.BigNumber.from(42000),
682
+ ...(isLegacy
683
+ ? { gasPrice: bumpCancelFee(oldTxsGasValues.gasPrice) }
684
+ : {
685
+ maxFeePerGas: bumpCancelFee(oldTxsGasValues.maxFeePerGas),
686
+ maxPriorityFeePerGas: bumpCancelFee(oldTxsGasValues.maxPriorityFeePerGas),
687
+ }),
688
+ };
662
689
  // Base cancel transaction parameters (same for all wallet types)
663
690
  const baseCancelTx = {
664
691
  nonce: tx.nonce,
@@ -847,24 +874,24 @@ class EthereumTransactions {
847
874
  this.sendFormattedTransactionInternal = async (params, isLegacy, beforeBroadcast) => {
848
875
  const { activeAccountType, activeAccountId, accounts, activeNetwork } = this.getState();
849
876
  const activeAccount = accounts[activeAccountType][activeAccountId];
850
- // Check if we should force legacy transactions for networks with EIP-1559 issues
851
- // Some networks have issues with EIP-1559 validation
852
- if (!isLegacy && params.maxFeePerGas && params.maxPriorityFeePerGas) {
853
- const maxFee = ethers_v6_1.BigNumber.from(params.maxFeePerGas);
854
- const priorityFee = ethers_v6_1.BigNumber.from(params.maxPriorityFeePerGas);
855
- // If fees are zero or network doesn't support EIP-1559, use legacy
856
- if (maxFee.isZero() || priorityFee.isZero()) {
857
- console.log('Switching to legacy transaction due to zero fees');
858
- isLegacy = true;
859
- // Convert to legacy by using gasPrice
860
- const gasPrice = await this.web3Provider.getGasPrice();
861
- params.gasPrice = gasPrice.mul(110).div(100); // 10% buffer
862
- // @ts-ignore
863
- delete params.maxFeePerGas;
864
- // @ts-ignore
865
- delete params.maxPriorityFeePerGas;
866
- }
867
- }
877
+ const explicitEip1559 = params.type != null && ethers_v6_1.BigNumber.from(params.type).eq(2);
878
+ const requestedEip1559 = explicitEip1559 ||
879
+ params.maxFeePerGas != null ||
880
+ params.maxPriorityFeePerGas != null;
881
+ if (isLegacy && requestedEip1559)
882
+ throw new Error('EIP-1559 fees conflict with legacy pricing');
883
+ const validateEip1559Fees = () => {
884
+ const maximum = nonNegativeFeeQuantity(params.maxFeePerGas, 'maximum fee');
885
+ const priority = nonNegativeFeeQuantity(params.maxPriorityFeePerGas, 'priority fee');
886
+ if (maximum.isZero() || priority.gt(maximum))
887
+ throw new Error('Invalid EIP-1559 fees');
888
+ params.maxFeePerGas = maximum;
889
+ params.maxPriorityFeePerGas = priority;
890
+ };
891
+ if (!isLegacy &&
892
+ params.maxFeePerGas != null &&
893
+ params.maxPriorityFeePerGas != null)
894
+ validateEip1559Fees();
868
895
  // Only apply a minimum gas limit when a network-specific override is set.
869
896
  // Otherwise keep the user/dapp-approved gas limit unchanged.
870
897
  if (params.gasLimit && this.gasOverrides.minGasLimit) {
@@ -891,20 +918,24 @@ class EthereumTransactions {
891
918
  params.gasPrice = await this.web3Provider.getGasPrice();
892
919
  }
893
920
  }
894
- else if (!params.maxFeePerGas || params.maxPriorityFeePerGas == null) {
921
+ else if (params.maxFeePerGas == null ||
922
+ params.maxPriorityFeePerGas == null) {
895
923
  const feeData = await this.web3Provider.getFeeData();
896
- params.maxFeePerGas =
897
- params.maxFeePerGas || feeData.maxFeePerGas || feeData.gasPrice;
924
+ params.maxFeePerGas = params.maxFeePerGas ?? feeData.maxFeePerGas;
898
925
  params.maxPriorityFeePerGas =
899
926
  params.maxPriorityFeePerGas ?? feeData.maxPriorityFeePerGas;
900
- if (!params.maxFeePerGas || params.maxPriorityFeePerGas == null) {
927
+ if (params.maxFeePerGas == null || params.maxPriorityFeePerGas == null) {
928
+ if (requestedEip1559)
929
+ throw new Error('EIP-1559 fee data unavailable');
901
930
  isLegacy = true;
902
931
  params.gasPrice =
903
- feeData.gasPrice || (await this.web3Provider.getGasPrice());
932
+ feeData.gasPrice ?? (await this.web3Provider.getGasPrice());
904
933
  delete params.maxFeePerGas;
905
934
  delete params.maxPriorityFeePerGas;
906
935
  }
907
936
  }
937
+ if (!isLegacy)
938
+ validateEip1559Fees();
908
939
  const sendEVMLedgerTransaction = async () => {
909
940
  const transactionNonce = await this.getRecommendedNonce(activeAccount.address);
910
941
  const formatParams = isLegacy
@@ -2119,6 +2150,10 @@ class EthereumTransactions {
2119
2150
  return withBuffer;
2120
2151
  }
2121
2152
  catch (error) {
2153
+ if (error?.code === 'SYSWEB3_RPC_RESPONSE_INVALID' ||
2154
+ error?.name === 'AbortError' ||
2155
+ this.abortController.signal.aborted)
2156
+ throw error;
2122
2157
  console.warn('Gas estimation failed:', error);
2123
2158
  if (hasCalldata) {
2124
2159
  const calldataFallback = ethers_v6_1.BigNumber.from('100000');
@@ -2143,6 +2178,11 @@ class EthereumTransactions {
2143
2178
  return withBuffer;
2144
2179
  }
2145
2180
  catch (secondError) {
2181
+ if (secondError?.code === 'SYSWEB3_RPC_RESPONSE_INVALID' ||
2182
+ secondError?.name === 'AbortError' ||
2183
+ this.abortController.signal.aborted) {
2184
+ throw secondError;
2185
+ }
2146
2186
  // Ultimate fallback
2147
2187
  console.warn('Simple estimation also failed, using default', secondError);
2148
2188
  return this.gasOverrides.minGasLimit || ethers_v6_1.BigNumber.from('100000');
@@ -2192,39 +2232,21 @@ class EthereumTransactions {
2192
2232
  maxPriorityFeePerGas: undefined,
2193
2233
  };
2194
2234
  }
2195
- try {
2196
- // Try EIP-1559 fees first
2197
- const feeData = await this.getFeeDataWithDynamicMaxPriorityFeePerGas();
2198
- // If fees are zero or too low, fallback to legacy
2199
- if (!feeData.maxFeePerGas ||
2200
- feeData.maxFeePerGas.isZero() ||
2201
- !feeData.maxPriorityFeePerGas ||
2202
- feeData.maxPriorityFeePerGas.isZero()) {
2203
- console.log('EIP-1559 fees invalid, falling back to legacy gas price');
2204
- const gasPrice = await this.web3Provider.getGasPrice();
2205
- const bufferedGasPrice = gasPrice.mul(110).div(100);
2206
- return {
2207
- gasPrice: bufferedGasPrice,
2208
- maxFeePerGas: undefined,
2209
- maxPriorityFeePerGas: undefined,
2210
- };
2211
- }
2212
- return {
2213
- gasPrice: undefined,
2214
- maxFeePerGas: feeData.maxFeePerGas,
2215
- maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
2216
- };
2217
- }
2218
- catch (error) {
2219
- console.warn('Failed to get EIP-1559 fees, using legacy:', error);
2220
- const gasPrice = await this.web3Provider.getGasPrice();
2221
- const bufferedGasPrice = gasPrice.mul(110).div(100);
2235
+ const feeData = await this.getFeeDataWithDynamicMaxPriorityFeePerGas();
2236
+ if (feeData.baseFeePerGas === undefined) {
2237
+ // Only an actual pre-London header authorizes legacy selection.
2238
+ const bufferedGasPrice = feeData.gasPrice.mul(110).div(100);
2222
2239
  return {
2223
2240
  gasPrice: bufferedGasPrice,
2224
2241
  maxFeePerGas: undefined,
2225
2242
  maxPriorityFeePerGas: undefined,
2226
2243
  };
2227
2244
  }
2245
+ return {
2246
+ gasPrice: undefined,
2247
+ maxFeePerGas: feeData.maxFeePerGas,
2248
+ maxPriorityFeePerGas: feeData.maxPriorityFeePerGas,
2249
+ };
2228
2250
  };
2229
2251
  this.getNetwork = getNetwork;
2230
2252
  this.getDecryptedPrivateKey = getDecryptedPrivateKey;