@@ -3,20 +3,73 @@ package gas
3
3
import (
4
4
"math/big"
5
5
6
- "github.com/ethereum/go-ethereum/ethclient"
6
+ "github.com/ethereum/go-ethereum/common"
7
+ "github.com/ethereum/go-ethereum/common/hexutil"
8
+ "github.com/ethereum/go-ethereum/crypto"
9
+ "github.com/ethereum/go-ethereum/rpc"
10
+ "github.com/stackup-wallet/stackup-bundler/pkg/arbitrum/nodeinterface"
11
+ "github.com/stackup-wallet/stackup-bundler/pkg/entrypoint"
12
+ "github.com/stackup-wallet/stackup-bundler/pkg/entrypoint/methods"
13
+ "github.com/stackup-wallet/stackup-bundler/pkg/signer"
7
14
"github.com/stackup-wallet/stackup-bundler/pkg/userop"
8
15
)
9
16
10
- type CalcPreVerificationGasFunc = func (op * userop.UserOperation ) * big.Int
17
+ type CalcPreVerificationGasFunc = func (op * userop.UserOperation ) ( * big.Int , error )
11
18
12
19
func calcPVGFuncNoop () CalcPreVerificationGasFunc {
13
- return func (op * userop.UserOperation ) * big.Int {
14
- return nil
20
+ return func (op * userop.UserOperation ) ( * big.Int , error ) {
21
+ return nil , nil
15
22
}
16
23
}
17
24
18
- func CalcArbitrumPVGWithEthClient (eth * ethclient.Client ) CalcPreVerificationGasFunc {
19
- return func (op * userop.UserOperation ) * big.Int {
20
- return big .NewInt (0 )
25
+ // CalcArbitrumPVGWithEthClient uses Arbitrum's NodeInterface precompile to get an estimate for
26
+ // preVerificationGas that takes into account the L1 gas component. see
27
+ // https://medium.com/offchainlabs/understanding-arbitrum-2-dimensional-fees-fd1d582596c9.
28
+ func CalcArbitrumPVGWithEthClient (
29
+ rpc * rpc.Client ,
30
+ ) CalcPreVerificationGasFunc {
31
+ pk , _ := crypto .GenerateKey ()
32
+ dummy , _ := signer .New (hexutil .Encode (crypto .FromECDSA (pk ))[2 :])
33
+ return func (op * userop.UserOperation ) (* big.Int , error ) {
34
+ // Pack handleOps method inputs
35
+ ho , err := methods .HandleOpsMethod .Inputs .Pack (
36
+ []entrypoint.UserOperation {entrypoint .UserOperation (* op )},
37
+ dummy .Address ,
38
+ )
39
+ if err != nil {
40
+ return nil , err
41
+ }
42
+
43
+ // Encode function data for gasEstimateL1Component
44
+ create := false
45
+ if op .Nonce .Cmp (common .Big0 ) == 0 {
46
+ create = true
47
+ }
48
+ ge , err := nodeinterface .GasEstimateL1ComponentMethod .Inputs .Pack (
49
+ nodeinterface .ERC4337GasHelperAddress ,
50
+ create ,
51
+ append (methods .HandleOpsMethod .ID , ho ... ),
52
+ )
53
+ if err != nil {
54
+ return nil , err
55
+ }
56
+
57
+ // Use eth_call to call the NodeInterface precompile
58
+ req := map [string ]any {
59
+ "from" : common .HexToAddress ("0x" ),
60
+ "to" : nodeinterface .PrecompileAddress ,
61
+ "data" : hexutil .Encode (append (nodeinterface .GasEstimateL1ComponentMethod .ID , ge ... )),
62
+ }
63
+ var out any
64
+ if err := rpc .Call (& out , "eth_call" , & req , "latest" ); err != nil {
65
+ return nil , err
66
+ }
67
+
68
+ // Return GasEstimateForL1 as PVG
69
+ gas , err := nodeinterface .DecodeGasEstimateL1ComponentOutput (out )
70
+ if err != nil {
71
+ return nil , err
72
+ }
73
+ return big .NewInt (int64 (gas .GasEstimateForL1 )), nil
21
74
}
22
75
}
0 commit comments