@@ -3,6 +3,9 @@ const { powerMonitor } = require('electron')
3
3
const EventEmitter = require ( 'events' )
4
4
const { addHexPrefix } = require ( '@ethereumjs/util' )
5
5
const { Hardfork } = require ( '@ethereumjs/common' )
6
+ const { estimateL1GasCost } = require ( '@eth-optimism/sdk' )
7
+ const { Web3Provider } = require ( '@ethersproject/providers' )
8
+ const BigNumber = require ( 'bignumber.js' )
6
9
const provider = require ( 'eth-provider' )
7
10
const log = require ( 'electron-log' )
8
11
@@ -12,6 +15,7 @@ const { default: chainConfig } = require('./config')
12
15
const { default : GasMonitor } = require ( '../transaction/gasMonitor' )
13
16
const { createGasCalculator } = require ( './gas' )
14
17
const { NETWORK_PRESETS } = require ( '../../resources/constants' )
18
+ const { chainUsesOptimismFees } = require ( '../../resources/utils/chains' )
15
19
16
20
// These chain IDs are known to not support EIP-1559 and will be forced
17
21
// not to use that mechanism
@@ -28,6 +32,17 @@ const resError = (error, payload, res) =>
28
32
error : typeof error === 'string' ? { message : error , code : - 1 } : error
29
33
} )
30
34
35
+ function txEstimate ( gasCost , nativeUSD ) {
36
+ const usd = gasCost . shiftedBy ( - 18 ) . multipliedBy ( nativeUSD ) . toNumber ( )
37
+
38
+ return {
39
+ gasEstimate : addHexPrefix ( gasCost . toString ( 16 ) ) ,
40
+ cost : {
41
+ usd
42
+ }
43
+ }
44
+ }
45
+
31
46
class ChainConnection extends EventEmitter {
32
47
constructor ( type , chainId ) {
33
48
super ( )
@@ -81,6 +96,91 @@ class ChainConnection extends EventEmitter {
81
96
this . emit ( 'connect' )
82
97
}
83
98
99
+ async txEstimates ( type , id , gasPrice , currentSymbol , provider ) {
100
+ const sampleEstimates = [
101
+ {
102
+ label : `Send ${ currentSymbol } ` ,
103
+ txExample : {
104
+ value : '0x8e1bc9bf04000' ,
105
+ data : '0x00' ,
106
+ gasLimit : addHexPrefix ( ( 21000 ) . toString ( 16 ) )
107
+ }
108
+ } ,
109
+ {
110
+ label : 'Send Tokens' ,
111
+ txExample : {
112
+ value : '0x00' ,
113
+ data : '0xa9059cbb000000000000000000000000c1af8ca40dfe1cb43b9c7a8c93df762c2d6ecfd90000000000000000000000000000000000000000000000008ac7230489e80000' ,
114
+ gasLimit : addHexPrefix ( ( 65000 ) . toString ( 16 ) )
115
+ }
116
+ } ,
117
+ {
118
+ label : 'Dex Swap' ,
119
+ txExample : {
120
+ value : '0x13e1e16b2a10c9' ,
121
+ data : '0x049639fb0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee00000000000000000000000042000000000000000000000000000000000000420000000000000000000000000000000000000000000000000013e1e16b2a10c900000000000000000000000000000000000000000000000045575639011cb45400000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000038812aa3caf000000000000000000000000b63aae6c353636d66df13b89ba4425cfe13d10ba00000000000000000000000042000000000000000000000000000000000000060000000000000000000000004200000000000000000000000000000000000042000000000000000000000000b63aae6c353636d66df13b89ba4425cfe13d10ba000000000000000000000000a7ca2c8673bcfa5a26d8ceec2887f2cc2b0db22a0000000000000000000000000000000000000000000000000013e1e16b2a10c900000000000000000000000000000000000000000000000045575639011cb455000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f50000000000000000000000000000000000000000000000000000000001d700a007e5c0d20000000000000000000000000000000000000000000000000001b30001505126a132dab612db5cb9fc9ac426a0cc215a3423f9c942000000000000000000000000000000000000060004f41766d8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011edea400000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000b63aae6c353636d66df13b89ba4425cfe13d10ba0000000000000000000000000000000000000000000000000000000065e75a70000000000000000000000000000000000000000000000000000000000000000100000000000000000000000042000000000000000000000000000000000000060000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c31607000000000000000000000000000000000000000000000000000000000000000102a000000000000000000000000000000000000000000000000045575639011cb455ee63c1e5801d751bc1a723accf1942122ca9aa82d49d08d2ae7f5c764cbc14f9669b88837ca1490cca17c316071111111254eeb25477b68fb85ed929f73a96058200000000000000000000000bd34b36000000000000000000000000000000000000000000000000' ,
122
+ gasLimit : addHexPrefix ( ( 200000 ) . toString ( 16 ) )
123
+ }
124
+ }
125
+ ]
126
+
127
+ const isTestnet = store ( 'main.networks' , type , id , 'isTestnet' )
128
+ const nativeCurrency = store ( 'main.networksMeta' , type , id , 'nativeCurrency' )
129
+ const nativeUSD = BigNumber (
130
+ nativeCurrency && nativeCurrency . usd && ! isTestnet ? nativeCurrency . usd . price : 0
131
+ )
132
+
133
+ let estimates
134
+
135
+ if ( chainUsesOptimismFees ( id ) && ! isTestnet ) {
136
+ estimates = await Promise . all (
137
+ sampleEstimates . map ( async ( { label, txExample } ) => {
138
+ const tx = {
139
+ ...txExample ,
140
+ type : 2 ,
141
+ chainId : id
142
+ }
143
+
144
+ try {
145
+ const l1GasCost = BigNumber ( ( await estimateL1GasCost ( provider , tx ) ) . toHexString ( ) )
146
+ const l2GasCost = BigNumber ( tx . gasLimit ) . multipliedBy ( gasPrice )
147
+ const estimatedGas = l1GasCost . plus ( l2GasCost )
148
+
149
+ return {
150
+ label,
151
+ gasCost : estimatedGas
152
+ }
153
+ } catch ( e ) {
154
+ return {
155
+ label,
156
+ gasCost : BigNumber ( '' )
157
+ }
158
+ }
159
+ } )
160
+ )
161
+ } else {
162
+ estimates = sampleEstimates . map ( ( { label, txExample } ) => ( {
163
+ label,
164
+ gasCost : BigNumber ( txExample . gasLimit ) . multipliedBy ( gasPrice )
165
+ } ) )
166
+ }
167
+
168
+ return estimates . map ( ( { label, gasCost } ) => ( {
169
+ estimates : {
170
+ low : txEstimate ( gasCost , nativeUSD ) ,
171
+ high : txEstimate ( gasCost , nativeUSD )
172
+ } ,
173
+ label
174
+ } ) )
175
+ }
176
+
177
+ async feeEstimatesUSD ( chainId , gasPrice , provider ) {
178
+ const type = 'ethereum'
179
+ const currentSymbol = store ( 'main.networksMeta' , type , chainId , 'nativeCurrency' , 'symbol' ) || 'ETH'
180
+
181
+ return this . txEstimates ( type , chainId , gasPrice , currentSymbol , provider )
182
+ }
183
+
84
184
_createBlockMonitor ( provider ) {
85
185
const monitor = new BlockMonitor ( provider )
86
186
const allowEip1559 = ! legacyChains . includes ( parseInt ( this . chainId ) )
@@ -127,6 +227,19 @@ class ChainConnection extends EventEmitter {
127
227
} )
128
228
}
129
229
230
+ if ( provider . connected ) {
231
+ const gasPrice = store ( 'main.networksMeta' , this . type , this . chainId , 'gas.price.levels.slow' )
232
+ const estimatedGasPrice = feeMarket
233
+ ? BigNumber ( feeMarket . nextBaseFee ) . plus ( BigNumber ( feeMarket . maxPriorityFeePerGas ) )
234
+ : BigNumber ( gasPrice )
235
+
236
+ this . feeEstimatesUSD ( parseInt ( this . chainId ) , estimatedGasPrice , new Web3Provider ( provider ) ) . then (
237
+ ( samples ) => {
238
+ store . addSampleGasCosts ( this . type , this . chainId , samples )
239
+ }
240
+ )
241
+ }
242
+
130
243
store . setGasFees ( this . type , this . chainId , feeMarket )
131
244
store . setBlockHeight ( this . chainId , parseInt ( block . number , 16 ) )
132
245
0 commit comments