|
1 | 1 | package gas
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "context" |
| 5 | + "math" |
4 | 6 | "math/big"
|
5 | 7 |
|
6 | 8 | "github.com/ethereum/go-ethereum/common"
|
7 | 9 | "github.com/ethereum/go-ethereum/common/hexutil"
|
8 | 10 | "github.com/ethereum/go-ethereum/crypto"
|
| 11 | + "github.com/ethereum/go-ethereum/ethclient" |
9 | 12 | "github.com/ethereum/go-ethereum/rpc"
|
10 | 13 | "github.com/stackup-wallet/stackup-bundler/pkg/arbitrum/nodeinterface"
|
11 | 14 | "github.com/stackup-wallet/stackup-bundler/pkg/entrypoint"
|
12 | 15 | "github.com/stackup-wallet/stackup-bundler/pkg/entrypoint/methods"
|
| 16 | + "github.com/stackup-wallet/stackup-bundler/pkg/entrypoint/transaction" |
| 17 | + "github.com/stackup-wallet/stackup-bundler/pkg/optimism/gaspriceoracle" |
13 | 18 | "github.com/stackup-wallet/stackup-bundler/pkg/signer"
|
14 | 19 | "github.com/stackup-wallet/stackup-bundler/pkg/userop"
|
15 | 20 | )
|
@@ -76,3 +81,70 @@ func CalcArbitrumPVGWithEthClient(
|
76 | 81 | return big.NewInt(0).Add(static, big.NewInt(int64(gas.GasEstimateForL1))), nil
|
77 | 82 | }
|
78 | 83 | }
|
| 84 | + |
| 85 | +// CalcOptimismPVGWithEthClient uses Optimism's Gas Price Oracle precompile to get an estimate for |
| 86 | +// preVerificationGas that takes into account the L1 gas component. |
| 87 | +func CalcOptimismPVGWithEthClient( |
| 88 | + rpc *rpc.Client, |
| 89 | + chainID *big.Int, |
| 90 | + entryPoint common.Address, |
| 91 | +) CalcPreVerificationGasFunc { |
| 92 | + pk, _ := crypto.GenerateKey() |
| 93 | + dummy, _ := signer.New(hexutil.Encode(crypto.FromECDSA(pk))[2:]) |
| 94 | + return func(op *userop.UserOperation, static *big.Int) (*big.Int, error) { |
| 95 | + // Create Raw HandleOps Transaction |
| 96 | + eth := ethclient.NewClient(rpc) |
| 97 | + head, err := eth.HeaderByNumber(context.Background(), nil) |
| 98 | + if err != nil { |
| 99 | + return nil, err |
| 100 | + } |
| 101 | + tx, err := transaction.CreateRawHandleOps( |
| 102 | + dummy, |
| 103 | + eth, |
| 104 | + chainID, |
| 105 | + entryPoint, |
| 106 | + []*userop.UserOperation{op}, |
| 107 | + dummy.Address, |
| 108 | + math.MaxUint64, |
| 109 | + head.BaseFee, |
| 110 | + ) |
| 111 | + if err != nil { |
| 112 | + return nil, err |
| 113 | + } |
| 114 | + |
| 115 | + // Encode function data for GetL1Fee |
| 116 | + data, err := hexutil.Decode(tx) |
| 117 | + if err != nil { |
| 118 | + return nil, err |
| 119 | + } |
| 120 | + ge, err := gaspriceoracle.GetL1FeeMethod.Inputs.Pack(data) |
| 121 | + if err != nil { |
| 122 | + return nil, err |
| 123 | + } |
| 124 | + |
| 125 | + // Use eth_call to call the Gas Price Oracle precompile |
| 126 | + req := map[string]any{ |
| 127 | + "from": common.HexToAddress("0x"), |
| 128 | + "to": gaspriceoracle.PrecompileAddress, |
| 129 | + "data": hexutil.Encode(append(gaspriceoracle.GetL1FeeMethod.ID, ge...)), |
| 130 | + } |
| 131 | + var out any |
| 132 | + if err := rpc.Call(&out, "eth_call", &req, "latest"); err != nil { |
| 133 | + return nil, err |
| 134 | + } |
| 135 | + |
| 136 | + // Get L1Fee and L2Price |
| 137 | + l1fee, err := gaspriceoracle.DecodeGetL1FeeMethodOutput(out) |
| 138 | + if err != nil { |
| 139 | + return nil, err |
| 140 | + } |
| 141 | + l2price := op.MaxFeePerGas |
| 142 | + l2priority := big.NewInt(0).Add(op.MaxPriorityFeePerGas, head.BaseFee) |
| 143 | + if l2priority.Cmp(l2price) == -1 { |
| 144 | + l2price = l2priority |
| 145 | + } |
| 146 | + |
| 147 | + // Return static + L1 buffer as PVG. L1 buffer is equal to L1Fee/L2Price. |
| 148 | + return big.NewInt(0).Add(static, big.NewInt(0).Div(l1fee, l2price)), nil |
| 149 | + } |
| 150 | +} |
0 commit comments