@@ -1520,25 +1520,20 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
1520
1520
}
1521
1521
}
1522
1522
1523
- const gasLimit = new optionalDeps . ethUtil . BN ( this . setGasLimit ( params . gasLimit ) ) ;
1523
+ // Use default gasLimit for cold and custody wallets
1524
+ let gasLimit =
1525
+ params . gasLimit || userKey . startsWith ( 'xpub' ) || ! userKey
1526
+ ? new optionalDeps . ethUtil . BN ( this . setGasLimit ( params . gasLimit ) )
1527
+ : new optionalDeps . ethUtil . BN ( 0 ) ;
1528
+
1524
1529
const gasPrice = params . eip1559
1525
1530
? new optionalDeps . ethUtil . BN ( params . eip1559 . maxFeePerGas )
1526
- : new optionalDeps . ethUtil . BN ( this . setGasPrice ( params . gasPrice ) ) ;
1531
+ : params . gasPrice
1532
+ ? new optionalDeps . ethUtil . BN ( this . setGasPrice ( params . gasPrice ) )
1533
+ : await this . getGasPriceFromExternalAPI ( ) ;
1527
1534
1528
1535
const bitgoFeeAddressNonce = await this . getAddressNonce ( bitgoFeeAddress ) ;
1529
1536
1530
- // get balance of bitgoFeeAddress to ensure funds are available to pay fees
1531
- const bitgoFeeAddressBalance = await this . queryAddressBalance ( bitgoFeeAddress ) ;
1532
- const totalGasNeeded = gasPrice . mul ( gasLimit ) ;
1533
- const weiToGwei = 10 ** 9 ;
1534
- if ( bitgoFeeAddressBalance . lt ( totalGasNeeded ) ) {
1535
- throw new Error (
1536
- `Fee address ${ bitgoFeeAddress } has balance ${ ( bitgoFeeAddressBalance / weiToGwei ) . toString ( ) } Gwei.` +
1537
- `This address must have a balance of at least ${ ( totalGasNeeded / weiToGwei ) . toString ( ) } ` +
1538
- ` Gwei to perform recoveries. Try sending some ${ this . getChain ( ) } to this address then retry.`
1539
- ) ;
1540
- }
1541
-
1542
1537
if ( tokenContractAddress ) {
1543
1538
return this . recoverEthLikeTokenforEvmBasedRecovery (
1544
1539
params ,
@@ -1588,14 +1583,6 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
1588
1583
await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ;
1589
1584
const sequenceId = await this . querySequenceId ( walletContractAddress ) ;
1590
1585
1591
- const txInfo = {
1592
- recipients : recipients ,
1593
- expireTime : this . getDefaultExpireTime ( ) ,
1594
- contractSequenceId : sequenceId ,
1595
- gasLimit : gasLimit . toString ( 10 ) ,
1596
- isEvmBasedCrossChainRecovery : true ,
1597
- } ;
1598
-
1599
1586
const network = this . getNetwork ( ) ;
1600
1587
const batcherContractAddress = network ?. batcherContractAddress as string ;
1601
1588
@@ -1646,8 +1633,33 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
1646
1633
txBuilder . walletVersion ( 4 ) ;
1647
1634
}
1648
1635
1636
+ // If gasLimit was not passed as a param, then fetch the gasLimit from Explorer
1637
+ if ( ! params . gasLimit && ! userKey . startsWith ( 'xpub' ) ) {
1638
+ const sendData = txBuilder . getSendData ( ) ;
1639
+ gasLimit = await this . getGasLimitFromExternalAPI (
1640
+ params . bitgoFeeAddress as string ,
1641
+ params . walletContractAddress ,
1642
+ sendData
1643
+ ) ;
1644
+ txBuilder . fee ( {
1645
+ ...txFee ,
1646
+ gasLimit : gasLimit . toString ( ) ,
1647
+ } ) ;
1648
+ }
1649
+
1650
+ // Get the balance of bitgoFeeAddress to ensure funds are available to pay fees
1651
+ await this . ensureSufficientBalance ( bitgoFeeAddress , gasPrice , gasLimit ) ;
1652
+
1649
1653
const tx = await txBuilder . build ( ) ;
1650
1654
1655
+ const txInfo = {
1656
+ recipients : recipients ,
1657
+ expireTime : this . getDefaultExpireTime ( ) ,
1658
+ contractSequenceId : sequenceId ,
1659
+ gasLimit : gasLimit . toString ( 10 ) ,
1660
+ isEvmBasedCrossChainRecovery : true ,
1661
+ } ;
1662
+
1651
1663
const response : OfflineVaultTxInfo = {
1652
1664
txHex : tx . toBroadcastFormat ( ) ,
1653
1665
userKey,
@@ -1740,14 +1752,6 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
1740
1752
await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ;
1741
1753
const sequenceId = await this . querySequenceId ( params . walletContractAddress ) ;
1742
1754
1743
- const txInfo = {
1744
- recipients : recipients ,
1745
- expireTime : this . getDefaultExpireTime ( ) ,
1746
- contractSequenceId : sequenceId ,
1747
- gasLimit : gasLimit . toString ( 10 ) ,
1748
- isEvmBasedCrossChainRecovery : true ,
1749
- } ;
1750
-
1751
1755
const txBuilder = this . getTransactionBuilder ( params . common ) as TransactionBuilder ;
1752
1756
txBuilder . counter ( bitgoFeeAddressNonce ) ;
1753
1757
txBuilder . contract ( params . walletContractAddress as string ) ;
@@ -1799,8 +1803,32 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
1799
1803
txBuilder . walletVersion ( 4 ) ;
1800
1804
}
1801
1805
1806
+ if ( ! params . gasLimit && ! userKey . startsWith ( 'xpub' ) ) {
1807
+ const sendData = txBuilder . getSendData ( ) ;
1808
+ gasLimit = await this . getGasLimitFromExternalAPI (
1809
+ params . bitgoFeeAddress as string ,
1810
+ params . walletContractAddress ,
1811
+ sendData
1812
+ ) ;
1813
+ txBuilder . fee ( {
1814
+ ...txFee ,
1815
+ gasLimit : gasLimit . toString ( ) ,
1816
+ } ) ;
1817
+ }
1818
+
1819
+ // Get the balance of bitgoFeeAddress to ensure funds are available to pay fees
1820
+ await this . ensureSufficientBalance ( params . bitgoFeeAddress as string , gasPrice , gasLimit ) ;
1821
+
1802
1822
const tx = await txBuilder . build ( ) ;
1803
1823
1824
+ const txInfo = {
1825
+ recipients : recipients ,
1826
+ expireTime : this . getDefaultExpireTime ( ) ,
1827
+ contractSequenceId : sequenceId ,
1828
+ gasLimit : gasLimit . toString ( 10 ) ,
1829
+ isEvmBasedCrossChainRecovery : true ,
1830
+ } ;
1831
+
1804
1832
const response : OfflineVaultTxInfo = {
1805
1833
txHex : tx . toBroadcastFormat ( ) ,
1806
1834
userKey,
@@ -2599,4 +2627,63 @@ export abstract class AbstractEthLikeNewCoins extends AbstractEthLikeCoin {
2599
2627
}
2600
2628
}
2601
2629
}
2630
+
2631
+ /**
2632
+ * Fetch the gas price from the explorer
2633
+ */
2634
+ async getGasPriceFromExternalAPI ( ) : Promise < BN > {
2635
+ try {
2636
+ const res = await this . recoveryBlockchainExplorerQuery ( {
2637
+ module : 'proxy' ,
2638
+ action : 'eth_gasPrice' ,
2639
+ } ) ;
2640
+ const gasPrice = new BN ( res . result . slice ( 2 ) , 16 ) ;
2641
+ console . log ( ` Got gas price: ${ gasPrice } ` ) ;
2642
+ return gasPrice ;
2643
+ } catch ( e ) {
2644
+ throw new Error ( 'Failed to get gas price' ) ;
2645
+ }
2646
+ }
2647
+
2648
+ /**
2649
+ * Fetch the gas limit from the explorer
2650
+ * @param from
2651
+ * @param to
2652
+ * @param data
2653
+ */
2654
+ async getGasLimitFromExternalAPI ( from : string , to : string , data : string ) : Promise < BN > {
2655
+ try {
2656
+ const res = await this . recoveryBlockchainExplorerQuery ( {
2657
+ module : 'proxy' ,
2658
+ action : 'eth_estimateGas' ,
2659
+ from,
2660
+ to,
2661
+ data,
2662
+ } ) ;
2663
+ const gasLimit = new BN ( res . result . slice ( 2 ) , 16 ) ;
2664
+ console . log ( `Got gas limit: ${ gasLimit } ` ) ;
2665
+ return gasLimit ;
2666
+ } catch ( e ) {
2667
+ throw new Error ( 'Failed to get gas limit: ' ) ;
2668
+ }
2669
+ }
2670
+
2671
+ /**
2672
+ * Get the balance of bitgoFeeAddress to ensure funds are available to pay fees
2673
+ * @param bitgoFeeAddress
2674
+ * @param gasPrice
2675
+ * @param gasLimit
2676
+ */
2677
+ async ensureSufficientBalance ( bitgoFeeAddress : string , gasPrice : BN , gasLimit : BN ) : Promise < void > {
2678
+ const bitgoFeeAddressBalance = await this . queryAddressBalance ( bitgoFeeAddress ) ;
2679
+ const totalGasNeeded = Number ( gasPrice . mul ( gasLimit ) ) ;
2680
+ const weiToGwei = 10 ** 9 ;
2681
+ if ( bitgoFeeAddressBalance . lt ( totalGasNeeded ) ) {
2682
+ throw new Error (
2683
+ `Fee address ${ bitgoFeeAddress } has balance ${ ( bitgoFeeAddressBalance / weiToGwei ) . toString ( ) } Gwei.` +
2684
+ `This address must have a balance of at least ${ ( totalGasNeeded / weiToGwei ) . toString ( ) } ` +
2685
+ ` Gwei to perform recoveries. Try sending some ${ this . getChain ( ) } to this address then retry.`
2686
+ ) ;
2687
+ }
2688
+ }
2602
2689
}
0 commit comments