@@ -11,6 +11,8 @@ import (
1111 "github.com/ethereum/go-ethereum/common"
1212)
1313
14+ const basefeeWiggleMultiplier = 2
15+
1416type GasFeeCalculator struct {
1517 client IChainClient
1618 config * ChainConfig
@@ -35,15 +37,9 @@ func (m *GasFeeCalculator) Apply(ctx context.Context, txOpts *bind.TransactOpts)
3537 }
3638 switch m .config .TxType {
3739 case TxTypeLegacy :
38- gasPrice , err := m .client . SuggestGasPrice (ctx )
40+ gasPrice , err := m .calculateGasPrice (ctx , oldTx , minFeeCap )
3941 if err != nil {
40- return fmt .Errorf ("failed to suggest gas price: %v" , err )
41- }
42- if oldTx != nil && oldTx .GasPrice != nil && oldTx .GasPrice .ToInt ().Cmp (gasPrice ) > 0 {
43- return fmt .Errorf ("old tx's gasPrice(%v) is higher than suggestion(%v)" , oldTx .GasPrice .ToInt (), gasPrice )
44- }
45- if gasPrice .Cmp (minFeeCap ) < 0 {
46- gasPrice = minFeeCap
42+ return fmt .Errorf ("failed to calculate gas price: %v" , err )
4743 }
4844 txOpts .GasPrice = gasPrice
4945 return nil
@@ -59,22 +55,14 @@ func (m *GasFeeCalculator) Apply(ctx context.Context, txOpts *bind.TransactOpts)
5955 m .config .DynamicTxGasConfig .BaseFeeRate .Mul (gasFeeCap )
6056 gasFeeCap .Add (gasFeeCap , gasTipCap )
6157
62- if oldTx != nil && oldTx .GasFeeCap != nil && oldTx .GasTipCap != nil {
63- if oldTx .GasFeeCap .ToInt ().Cmp (gasFeeCap ) >= 0 && oldTx .GasTipCap .ToInt ().Cmp (gasTipCap ) >= 0 {
64- return fmt .Errorf ("old tx's gasFeeCap(%v) and gasTipCap(%v) are greater than or equal to suggestion(%v, %v)" , oldTx .GasFeeCap .ToInt (), oldTx .GasTipCap .ToInt (), gasFeeCap , gasTipCap )
65- }
58+ gasTipCap , gasFeeCap , err = m .applyMinGasCaps (oldTx , gasTipCap , gasFeeCap , minTipCap , minFeeCap )
59+ if err != nil {
60+ return fmt .Errorf ("failed to apply min gas caps: %v" , err )
6661 }
6762
68- if gasTipCap .Cmp (minTipCap ) < 0 {
69- gasTipCap = minTipCap
70- }
7163 if l := m .config .DynamicTxGasConfig .GetLimitPriorityFeePerGas (); l .Sign () > 0 && gasTipCap .Cmp (l ) > 0 {
7264 gasTipCap = l
7365 }
74-
75- if gasFeeCap .Cmp (minFeeCap ) < 0 {
76- gasFeeCap = minFeeCap
77- }
7866 if l := m .config .DynamicTxGasConfig .GetLimitFeePerGas (); l .Sign () > 0 && gasFeeCap .Cmp (l ) > 0 {
7967 gasFeeCap = l
8068 }
@@ -85,11 +73,62 @@ func (m *GasFeeCalculator) Apply(ctx context.Context, txOpts *bind.TransactOpts)
8573 txOpts .GasFeeCap = gasFeeCap
8674 txOpts .GasTipCap = gasTipCap
8775 return nil
76+ case TxTypeAuto :
77+ // Calculate gas options in the same way as bind.BoundContract.transact
78+ head , err := m .client .HeaderByNumber (ctx , nil )
79+ if err != nil {
80+ return fmt .Errorf ("failed to get latest header: %v" , err )
81+ }
82+
83+ if head .BaseFee == nil {
84+ gasPrice , err := m .calculateGasPrice (ctx , oldTx , minFeeCap )
85+ if err != nil {
86+ return fmt .Errorf ("failed to calculate gas price: %v" , err )
87+ }
88+ txOpts .GasPrice = gasPrice
89+ return nil
90+ } else {
91+ gasTipCap , err := m .client .SuggestGasTipCap (ctx )
92+ if err != nil {
93+ return fmt .Errorf ("failed to suggest gas tip cap: %v" , err )
94+ }
95+ gasFeeCap := new (big.Int ).Add (
96+ gasTipCap ,
97+ new (big.Int ).Mul (head .BaseFee , big .NewInt (basefeeWiggleMultiplier )),
98+ )
99+
100+ gasTipCap , gasFeeCap , err = m .applyMinGasCaps (oldTx , gasTipCap , gasFeeCap , minTipCap , minFeeCap )
101+ if err != nil {
102+ return fmt .Errorf ("failed to apply min gas caps: %v" , err )
103+ }
104+
105+ txOpts .GasFeeCap = gasFeeCap
106+ txOpts .GasTipCap = gasTipCap
107+ return nil
108+ }
88109 default :
89- return nil
110+ panic ( "unsupported tx type" )
90111 }
91112}
92113
114+ func (m * GasFeeCalculator ) calculateGasPrice (ctx context.Context , oldTx * txpool.RPCTransaction , minFeeCap * big.Int ) (* big.Int , error ) {
115+ gasPrice , err := m .client .SuggestGasPrice (ctx )
116+ if err != nil {
117+ return nil , fmt .Errorf ("failed to suggest gas price: %v" , err )
118+ }
119+ if oldTx != nil && oldTx .GasPrice != nil && oldTx .GasPrice .ToInt ().Cmp (gasPrice ) > 0 {
120+ // Since the old tx's gas price is already higher than the suggested value,
121+ // the gas price is not the reason the old tx has not been processed.
122+ // To avoid raising it indefinitely, return an error.
123+ return nil , fmt .Errorf ("old tx's gasPrice(%v) is higher than suggestion(%v)" , oldTx .GasPrice .ToInt (), gasPrice )
124+ }
125+ if gasPrice .Cmp (minFeeCap ) < 0 {
126+ gasPrice = minFeeCap
127+ }
128+
129+ return gasPrice , nil
130+ }
131+
93132func (m * GasFeeCalculator ) feeHistory (ctx context.Context ) (* big.Int , * big.Int , error ) {
94133 rewardPercentile := float64 (m .config .DynamicTxGasConfig .FeeHistoryRewardPercentile )
95134 maxRetry := m .config .DynamicTxGasConfig .MaxRetryForFeeHistory
@@ -125,3 +164,33 @@ func getFeeInfo(v *ethereum.FeeHistory) (*big.Int, *big.Int, bool) {
125164 baseFee := v .BaseFee [0 ]
126165 return gasTipCap , baseFee , true
127166}
167+
168+ func (m * GasFeeCalculator ) applyMinGasCaps (
169+ oldTx * txpool.RPCTransaction ,
170+ gasTipCap * big.Int ,
171+ gasFeeCap * big.Int ,
172+ minTipCap * big.Int ,
173+ minFeeCap * big.Int ,
174+ ) (* big.Int , * big.Int , error ) {
175+ if oldTx != nil && oldTx .GasFeeCap != nil && oldTx .GasTipCap != nil {
176+ if oldTx .GasFeeCap .ToInt ().Cmp (gasFeeCap ) >= 0 && oldTx .GasTipCap .ToInt ().Cmp (gasTipCap ) >= 0 {
177+ // Since the old tx's gas parameters are already higher than the suggested values,
178+ // the gas parameters are not the reason the old tx has not been processed.
179+ // To avoid raising them indefinitely, return an error.
180+ return nil , nil , fmt .Errorf ("old tx's gasFeeCap(%v) and gasTipCap(%v) are greater than or equal to suggestion(%v, %v)" , oldTx .GasFeeCap .ToInt (), oldTx .GasTipCap .ToInt (), gasFeeCap , gasTipCap )
181+ }
182+ }
183+
184+ if gasTipCap .Cmp (minTipCap ) < 0 {
185+ gasTipCap = minTipCap
186+ }
187+ if gasFeeCap .Cmp (minFeeCap ) < 0 {
188+ gasFeeCap = minFeeCap
189+ }
190+
191+ if gasFeeCap .Cmp (gasTipCap ) < 0 {
192+ return nil , nil , fmt .Errorf ("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)" , gasFeeCap , gasTipCap )
193+ }
194+
195+ return gasTipCap , gasFeeCap , nil
196+ }
0 commit comments