Skip to content
This repository was archived by the owner on Oct 20, 2024. It is now read-only.

Commit 3494599

Browse files
authored
Only replace ops if both fee values increase by >= 10% (#86)
1 parent 79ab5e8 commit 3494599

File tree

2 files changed

+21
-128
lines changed

2 files changed

+21
-128
lines changed

pkg/modules/checks/pendingops.go

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
package checks
22

33
import (
4-
"errors"
54
"fmt"
65
"math/big"
76

87
"github.com/stackup-wallet/stackup-bundler/pkg/userop"
98
)
109

10+
const minPriceBump = 10
11+
12+
// calcNewThresholds returns new threshold values where newFee = oldFee * (100 + minPriceBump) / 100.
13+
func calcNewThresholds(cap *big.Int, tip *big.Int) (newCap *big.Int, newTip *big.Int) {
14+
a := big.NewInt(100 + minPriceBump)
15+
aFeeCap := big.NewInt(0).Mul(a, cap)
16+
aTip := big.NewInt(0).Mul(a, tip)
17+
18+
b := big.NewInt(100)
19+
newCap = aFeeCap.Div(aFeeCap, b)
20+
newTip = aTip.Div(aTip, b)
21+
22+
return newCap, newTip
23+
}
24+
1125
// ValidatePendingOps checks the pending UserOperations by the same sender and only passes if:
1226
//
1327
// 1. Sender doesn't have another UserOperation already present in the pool.
@@ -33,16 +47,13 @@ func ValidatePendingOps(
3347
}
3448

3549
if oldOp != nil {
36-
if op.MaxPriorityFeePerGas.Cmp(oldOp.MaxPriorityFeePerGas) <= 0 {
37-
return errors.New(
38-
"pending ops: sender has op in mempool with same or higher priority fee",
39-
)
40-
}
50+
newMf, newMpf := calcNewThresholds(oldOp.MaxFeePerGas, oldOp.MaxPriorityFeePerGas)
4151

42-
diff := big.NewInt(0).Sub(op.MaxPriorityFeePerGas, oldOp.MaxPriorityFeePerGas)
43-
mf := big.NewInt(0).Add(oldOp.MaxFeePerGas, diff)
44-
if op.MaxFeePerGas.Cmp(mf) != 0 {
45-
return errors.New("pending ops: replaced op must have an equally higher max fee")
52+
if op.MaxFeePerGas.Cmp(newMf) < 0 || op.MaxPriorityFeePerGas.Cmp(newMpf) < 0 {
53+
return fmt.Errorf(
54+
"pending ops: replacement op must increase maxFeePerGas and MaxPriorityFeePerGas by >= %d%%",
55+
minPriceBump,
56+
)
4657
}
4758
} else if !dep.Staked && len(penOps) >= maxOpsForUnstakedSender {
4859
return fmt.Errorf(

pkg/modules/checks/pendingops_test.go

Lines changed: 0 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -62,121 +62,3 @@ func TestPendingOpsStaked(t *testing.T) {
6262
t.Fatalf("got err %v, want nil", err)
6363
}
6464
}
65-
66-
// TestReplaceOp calls checks.ValidatePendingOps with a valid UserOperation that replaces a pending
67-
// UserOperation. Expect nil.
68-
func TestReplaceOp(t *testing.T) {
69-
penOp := testutils.MockValidInitUserOp()
70-
penOps := []*userop.UserOperation{penOp}
71-
op := testutils.MockValidInitUserOp()
72-
op.MaxPriorityFeePerGas = big.NewInt(0).Add(penOp.MaxPriorityFeePerGas, common.Big1)
73-
op.MaxFeePerGas = big.NewInt(0).Add(penOp.MaxFeePerGas, common.Big1)
74-
err := ValidatePendingOps(
75-
op,
76-
penOps,
77-
testutils.MaxOpsForUnstakedSender,
78-
testutils.MockGetNotStakeZeroDeposit,
79-
)
80-
81-
if err != nil {
82-
t.Fatalf("got err %v, want nil", err)
83-
}
84-
}
85-
86-
// TestReplaceOpLowerMPF calls checks.ValidatePendingOps with a UserOperation that replaces a pending
87-
// UserOperation but has a lower MaxPriorityFeePerGas. Expect error.
88-
func TestReplaceOpLowerMPF(t *testing.T) {
89-
penOp := testutils.MockValidInitUserOp()
90-
penOps := []*userop.UserOperation{penOp}
91-
op := testutils.MockValidInitUserOp()
92-
op.MaxPriorityFeePerGas = big.NewInt(0).Sub(penOp.MaxPriorityFeePerGas, common.Big1)
93-
err := ValidatePendingOps(
94-
op,
95-
penOps,
96-
testutils.MaxOpsForUnstakedSender,
97-
testutils.MockGetNotStakeZeroDeposit,
98-
)
99-
100-
if err == nil {
101-
t.Fatal("got nil, want err")
102-
}
103-
}
104-
105-
// TestReplaceOpEqualMPF calls checks.ValidatePendingOps with a UserOperation that replaces a pending
106-
// UserOperation but has an equal MaxPriorityFeePerGas. Expect error.
107-
func TestReplaceOpEqualMPF(t *testing.T) {
108-
penOp := testutils.MockValidInitUserOp()
109-
penOps := []*userop.UserOperation{penOp}
110-
op := testutils.MockValidInitUserOp()
111-
op.MaxPriorityFeePerGas = big.NewInt(0).Add(penOp.MaxPriorityFeePerGas, common.Big0)
112-
err := ValidatePendingOps(
113-
op,
114-
penOps,
115-
testutils.MaxOpsForUnstakedSender,
116-
testutils.MockGetNotStakeZeroDeposit,
117-
)
118-
119-
if err == nil {
120-
t.Fatal("got nil, want err")
121-
}
122-
}
123-
124-
// TestReplaceOpNotEqualIncMF calls checks.ValidatePendingOps with a UserOperation that replaces a pending
125-
// UserOperation but does not have an equally increasing MaxFeePerGas. Expect error.
126-
func TestReplaceOpNotEqualIncMF(t *testing.T) {
127-
penOp := testutils.MockValidInitUserOp()
128-
penOps := []*userop.UserOperation{penOp}
129-
op := testutils.MockValidInitUserOp()
130-
op.MaxPriorityFeePerGas = big.NewInt(0).Add(penOp.MaxPriorityFeePerGas, common.Big2)
131-
op.MaxFeePerGas = big.NewInt(0).Add(penOp.MaxFeePerGas, common.Big1)
132-
err := ValidatePendingOps(
133-
op,
134-
penOps,
135-
testutils.MaxOpsForUnstakedSender,
136-
testutils.MockGetNotStakeZeroDeposit,
137-
)
138-
139-
if err == nil {
140-
t.Fatal("got nil, want err")
141-
}
142-
}
143-
144-
// TestReplaceOpSameMF calls checks.ValidatePendingOps with a UserOperation that replaces a pending
145-
// UserOperation but does not increase MaxFeePerGas. Expect error.
146-
func TestReplaceOpSameMF(t *testing.T) {
147-
penOp := testutils.MockValidInitUserOp()
148-
penOps := []*userop.UserOperation{penOp}
149-
op := testutils.MockValidInitUserOp()
150-
op.MaxPriorityFeePerGas = big.NewInt(0).Add(penOp.MaxPriorityFeePerGas, common.Big1)
151-
op.MaxFeePerGas = big.NewInt(0).Add(penOp.MaxFeePerGas, common.Big0)
152-
err := ValidatePendingOps(
153-
op,
154-
penOps,
155-
testutils.MaxOpsForUnstakedSender,
156-
testutils.MockGetNotStakeZeroDeposit,
157-
)
158-
159-
if err == nil {
160-
t.Fatal("got nil, want err")
161-
}
162-
}
163-
164-
// TestReplaceOpDecMF calls checks.ValidatePendingOps with a UserOperation that replaces a pending
165-
// UserOperation but has a decreasing MaxFeePerGas. Expect error.
166-
func TestReplaceOpDecMF(t *testing.T) {
167-
penOp := testutils.MockValidInitUserOp()
168-
penOps := []*userop.UserOperation{penOp}
169-
op := testutils.MockValidInitUserOp()
170-
op.MaxPriorityFeePerGas = big.NewInt(0).Add(penOp.MaxPriorityFeePerGas, common.Big1)
171-
op.MaxFeePerGas = big.NewInt(0).Sub(penOp.MaxFeePerGas, common.Big1)
172-
err := ValidatePendingOps(
173-
op,
174-
penOps,
175-
testutils.MaxOpsForUnstakedSender,
176-
testutils.MockGetNotStakeZeroDeposit,
177-
)
178-
179-
if err == nil {
180-
t.Fatal("got nil, want err")
181-
}
182-
}

0 commit comments

Comments
 (0)