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

Commit 679ccce

Browse files
authored
ERC-7562 compliance (part 1) (#360)
1 parent fe14adb commit 679ccce

39 files changed

+1303
-541
lines changed

.github/workflows/compliance.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ jobs:
3434
repository: hazim-j/bundler-spec-tests
3535
ref: develop
3636
path: ./bundler-spec-tests
37+
fetch-depth: 0
3738
submodules: true
3839

3940
- name: Setup bundler spec test
4041
working-directory: ./bundler-spec-tests
4142
run: |
4243
pdm install && \
4344
cd @account-abstraction && \
45+
git checkout v0.6.0 && \
4446
yarn install --frozen-lockfile && \
4547
yarn compile && \
4648
cd ../spec && \
@@ -94,7 +96,6 @@ jobs:
9496
ERC4337_BUNDLER_ETH_CLIENT_URL: http://localhost:8545/
9597
ERC4337_BUNDLER_PORT: 3000
9698
ERC4337_BUNDLER_DEBUG_MODE: true
97-
ERC4337_BUNDLER_MAX_BATCH_GAS_LIMIT: 12000000
9899
# This key is for testing purposes only. Do not use for anything else.
99100
ERC4337_BUNDLER_PRIVATE_KEY: c6cbc5ffad570fdad0544d1b5358a36edeb98d163b6567912ac4754e144d4edb
100101

.github/workflows/e2e.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,6 @@ jobs:
110110
env:
111111
ERC4337_BUNDLER_ETH_CLIENT_URL: http://localhost:8545/
112112
ERC4337_BUNDLER_DEBUG_MODE: true
113-
ERC4337_BUNDLER_MAX_BATCH_GAS_LIMIT: 12000000
114113
# This key is for testing purposes only. Do not use for anything else.
115114
ERC4337_BUNDLER_PRIVATE_KEY: c6cbc5ffad570fdad0544d1b5358a36edeb98d163b6567912ac4754e144d4edb
116115

e2e/README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ Lastly, run the bundler with the following config:
5151
```
5252
ERC4337_BUNDLER_ETH_CLIENT_URL=http://localhost:8545
5353
ERC4337_BUNDLER_PRIVATE_KEY=c6cbc5ffad570fdad0544d1b5358a36edeb98d163b6567912ac4754e144d4edb
54-
ERC4337_BUNDLER_MAX_BATCH_GAS_LIMIT=12000000
5554
ERC4337_BUNDLER_DEBUG_MODE=true
5655
```
5756

internal/config/mempool.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package config
2+
3+
import (
4+
"github.com/spf13/viper"
5+
"github.com/stackup-wallet/stackup-bundler/pkg/modules/entities"
6+
)
7+
8+
func NewReputationConstantsFromEnv() *entities.ReputationConstants {
9+
viper.SetDefault("erc4337_bundler_min_unstake_delay", 86400)
10+
viper.SetDefault("erc4337_bundler_min_stake_value", 2000000000000000)
11+
viper.SetDefault("erc4337_same_sender_mempool_count", 4)
12+
viper.SetDefault("erc4337_same_unstaked_entity_mempool_count", 11)
13+
viper.SetDefault("erc4337_throttled_entity_mempool_count", 4)
14+
viper.SetDefault("erc4337_throttled_entity_live_blocks", 10)
15+
viper.SetDefault("erc4337_throttled_entity_bundle_count", 4)
16+
viper.SetDefault("erc4337_min_inclusion_rate_denominator", 10)
17+
viper.SetDefault("erc4337_inclusion_rate_factor", 10)
18+
viper.SetDefault("erc4337_throttling_slack", 10)
19+
viper.SetDefault("erc4337_ban_slack", 50)
20+
21+
_ = viper.BindEnv("erc4337_bundler_min_unstake_delay")
22+
_ = viper.BindEnv("erc4337_bundler_min_stake_value")
23+
_ = viper.BindEnv("erc4337_same_sender_mempool_count")
24+
_ = viper.BindEnv("erc4337_same_unstaked_entity_mempool_count")
25+
_ = viper.BindEnv("erc4337_throttled_entity_mempool_count")
26+
_ = viper.BindEnv("erc4337_throttled_entity_live_blocks")
27+
_ = viper.BindEnv("erc4337_throttled_entity_bundle_count")
28+
_ = viper.BindEnv("erc4337_min_inclusion_rate_denominator")
29+
_ = viper.BindEnv("erc4337_inclusion_rate_factor")
30+
_ = viper.BindEnv("erc4337_throttling_slack")
31+
_ = viper.BindEnv("erc4337_ban_slack")
32+
33+
return &entities.ReputationConstants{
34+
MinUnstakeDelay: viper.GetInt("erc4337_bundler_min_unstake_delay"),
35+
MinStakeValue: viper.GetInt64("erc4337_bundler_min_stake_value"),
36+
SameSenderMempoolCount: viper.GetInt("erc4337_same_sender_mempool_count"),
37+
SameUnstakedEntityMempoolCount: viper.GetInt("erc4337_same_unstaked_entity_mempool_count"),
38+
ThrottledEntityMempoolCount: viper.GetInt("erc4337_throttled_entity_mempool_count"),
39+
ThrottledEntityLiveBlocks: viper.GetInt("erc4337_throttled_entity_live_blocks"),
40+
ThrottledEntityBundleCount: viper.GetInt("erc4337_throttled_entity_bundle_count"),
41+
MinInclusionRateDenominator: viper.GetInt("erc4337_min_inclusion_rate_denominator"),
42+
InclusionRateFactor: viper.GetInt("erc4337_inclusion_rate_factor"),
43+
ThrottlingSlack: viper.GetInt("erc4337_throttling_slack"),
44+
BanSlack: viper.GetInt("erc4337_ban_slack"),
45+
}
46+
}

internal/config/values.go

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,22 @@ import (
99
"github.com/ethereum/go-ethereum/common"
1010
"github.com/gin-gonic/gin"
1111
"github.com/spf13/viper"
12+
"github.com/stackup-wallet/stackup-bundler/pkg/modules/entities"
1213
"github.com/stackup-wallet/stackup-bundler/pkg/signer"
1314
)
1415

1516
type Values struct {
1617
// Documented variables.
17-
PrivateKey string
18-
EthClientUrl string
19-
Port int
20-
DataDirectory string
21-
SupportedEntryPoints []common.Address
22-
MaxVerificationGas *big.Int
23-
MaxBatchGasLimit *big.Int
24-
MaxOpTTL time.Duration
25-
MaxOpsForUnstakedSender int
26-
Beneficiary string
18+
PrivateKey string
19+
EthClientUrl string
20+
Port int
21+
DataDirectory string
22+
SupportedEntryPoints []common.Address
23+
MaxVerificationGas *big.Int
24+
MaxBatchGasLimit *big.Int
25+
MaxOpTTL time.Duration
26+
Beneficiary string
27+
ReputationConstants *entities.ReputationConstants
2728

2829
// Searcher mode variables.
2930
EthBuilderUrls []string
@@ -84,10 +85,9 @@ func GetValues() *Values {
8485
viper.SetDefault("erc4337_bundler_port", 4337)
8586
viper.SetDefault("erc4337_bundler_data_directory", "/tmp/stackup_bundler")
8687
viper.SetDefault("erc4337_bundler_supported_entry_points", "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789")
87-
viper.SetDefault("erc4337_bundler_max_verification_gas", 3000000)
88-
viper.SetDefault("erc4337_bundler_max_batch_gas_limit", 25000000)
88+
viper.SetDefault("erc4337_bundler_max_verification_gas", 6000000)
89+
viper.SetDefault("erc4337_bundler_max_batch_gas_limit", 18000000)
8990
viper.SetDefault("erc4337_bundler_max_op_ttl_seconds", 180)
90-
viper.SetDefault("erc4337_bundler_max_ops_for_unstaked_sender", 4)
9191
viper.SetDefault("erc4337_bundler_blocks_in_the_future", 6)
9292
viper.SetDefault("erc4337_bundler_otel_insecure_mode", false)
9393
viper.SetDefault("erc4337_bundler_debug_mode", false)
@@ -116,7 +116,6 @@ func GetValues() *Values {
116116
_ = viper.BindEnv("erc4337_bundler_max_verification_gas")
117117
_ = viper.BindEnv("erc4337_bundler_max_batch_gas_limit")
118118
_ = viper.BindEnv("erc4337_bundler_max_op_ttl_seconds")
119-
_ = viper.BindEnv("erc4337_bundler_max_ops_for_unstaked_sender")
120119
_ = viper.BindEnv("erc4337_bundler_eth_builder_urls")
121120
_ = viper.BindEnv("erc4337_bundler_blocks_in_the_future")
122121
_ = viper.BindEnv("erc4337_bundler_otel_service_name")
@@ -174,7 +173,6 @@ func GetValues() *Values {
174173
maxVerificationGas := big.NewInt(int64(viper.GetInt("erc4337_bundler_max_verification_gas")))
175174
maxBatchGasLimit := big.NewInt(int64(viper.GetInt("erc4337_bundler_max_batch_gas_limit")))
176175
maxOpTTL := time.Second * viper.GetDuration("erc4337_bundler_max_op_ttl_seconds")
177-
maxOpsForUnstakedSender := viper.GetInt("erc4337_bundler_max_ops_for_unstaked_sender")
178176
ethBuilderUrls := envArrayToStringSlice(viper.GetString("erc4337_bundler_eth_builder_urls"))
179177
blocksInTheFuture := viper.GetInt("erc4337_bundler_blocks_in_the_future")
180178
otelServiceName := viper.GetString("erc4337_bundler_otel_service_name")
@@ -186,25 +184,25 @@ func GetValues() *Values {
186184
debugMode := viper.GetBool("erc4337_bundler_debug_mode")
187185
ginMode := viper.GetString("erc4337_bundler_gin_mode")
188186
return &Values{
189-
PrivateKey: privateKey,
190-
EthClientUrl: ethClientUrl,
191-
Port: port,
192-
DataDirectory: dataDirectory,
193-
SupportedEntryPoints: supportedEntryPoints,
194-
Beneficiary: beneficiary,
195-
MaxVerificationGas: maxVerificationGas,
196-
MaxBatchGasLimit: maxBatchGasLimit,
197-
MaxOpTTL: maxOpTTL,
198-
MaxOpsForUnstakedSender: maxOpsForUnstakedSender,
199-
EthBuilderUrls: ethBuilderUrls,
200-
BlocksInTheFuture: blocksInTheFuture,
201-
OTELServiceName: otelServiceName,
202-
OTELCollectorHeaders: otelCollectorHeader,
203-
OTELCollectorUrl: otelCollectorUrl,
204-
OTELInsecureMode: otelInsecureMode,
205-
AltMempoolIPFSGateway: altMempoolIPFSGateway,
206-
AltMempoolIds: altMempoolIds,
207-
DebugMode: debugMode,
208-
GinMode: ginMode,
187+
PrivateKey: privateKey,
188+
EthClientUrl: ethClientUrl,
189+
Port: port,
190+
DataDirectory: dataDirectory,
191+
SupportedEntryPoints: supportedEntryPoints,
192+
Beneficiary: beneficiary,
193+
MaxVerificationGas: maxVerificationGas,
194+
MaxBatchGasLimit: maxBatchGasLimit,
195+
MaxOpTTL: maxOpTTL,
196+
ReputationConstants: NewReputationConstantsFromEnv(),
197+
EthBuilderUrls: ethBuilderUrls,
198+
BlocksInTheFuture: blocksInTheFuture,
199+
OTELServiceName: otelServiceName,
200+
OTELCollectorHeaders: otelCollectorHeader,
201+
OTELCollectorUrl: otelCollectorUrl,
202+
OTELInsecureMode: otelInsecureMode,
203+
AltMempoolIPFSGateway: altMempoolIPFSGateway,
204+
AltMempoolIds: altMempoolIds,
205+
DebugMode: debugMode,
206+
GinMode: ginMode,
209207
}
210208
}

internal/start/private.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@ import (
1818
"github.com/stackup-wallet/stackup-bundler/pkg/altmempools"
1919
"github.com/stackup-wallet/stackup-bundler/pkg/bundler"
2020
"github.com/stackup-wallet/stackup-bundler/pkg/client"
21+
"github.com/stackup-wallet/stackup-bundler/pkg/entrypoint/stake"
2122
"github.com/stackup-wallet/stackup-bundler/pkg/gas"
2223
"github.com/stackup-wallet/stackup-bundler/pkg/jsonrpc"
2324
"github.com/stackup-wallet/stackup-bundler/pkg/mempool"
2425
"github.com/stackup-wallet/stackup-bundler/pkg/modules/batch"
2526
"github.com/stackup-wallet/stackup-bundler/pkg/modules/checks"
27+
"github.com/stackup-wallet/stackup-bundler/pkg/modules/entities"
2628
"github.com/stackup-wallet/stackup-bundler/pkg/modules/expire"
2729
"github.com/stackup-wallet/stackup-bundler/pkg/modules/gasprice"
28-
"github.com/stackup-wallet/stackup-bundler/pkg/modules/paymaster"
2930
"github.com/stackup-wallet/stackup-bundler/pkg/modules/relay"
3031
"github.com/stackup-wallet/stackup-bundler/pkg/signer"
3132
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
@@ -114,14 +115,14 @@ func PrivateMode() {
114115
alt,
115116
conf.MaxVerificationGas,
116117
conf.MaxBatchGasLimit,
117-
conf.MaxOpsForUnstakedSender,
118+
conf.ReputationConstants,
118119
)
119120

120121
exp := expire.New(conf.MaxOpTTL)
121122

122123
relayer := relay.New(eoa, eth, chain, beneficiary, logr)
123124

124-
paymaster := paymaster.New(db)
125+
rep := entities.New(db, eth, conf.ReputationConstants)
125126

126127
// Init Client
127128
c := client.New(mem, ov, chain, conf.SupportedEntryPoints)
@@ -131,12 +132,14 @@ func PrivateMode() {
131132
client.GetGasEstimateWithEthClient(rpc, ov, chain, conf.MaxBatchGasLimit),
132133
)
133134
c.SetGetUserOpByHashFunc(client.GetUserOpByHashWithEthClient(eth))
135+
c.SetGetStakeFunc(stake.GetStakeWithEthClient(eth))
134136
c.UseLogger(logr)
135137
c.UseModules(
138+
rep.CheckStatus(),
139+
rep.ValidateOpLimit(),
136140
check.ValidateOpValues(),
137-
paymaster.CheckStatus(),
138141
check.SimulateOp(),
139-
paymaster.IncOpsSeen(),
142+
rep.IncOpsSeen(),
140143
)
141144

142145
// Init Bundler
@@ -156,8 +159,9 @@ func PrivateMode() {
156159
batch.MaintainGasLimit(conf.MaxBatchGasLimit),
157160
check.CodeHashes(),
158161
check.PaymasterDeposit(),
162+
check.SimulateBatch(),
159163
relayer.SendUserOperation(),
160-
paymaster.IncOpsIncluded(),
164+
rep.IncOpsIncluded(),
161165
check.Clean(),
162166
)
163167
if err := b.Run(); err != nil {
@@ -167,7 +171,7 @@ func PrivateMode() {
167171
// init Debug
168172
var d *client.Debug
169173
if conf.DebugMode {
170-
d = client.NewDebug(eoa, eth, mem, b, chain, conf.SupportedEntryPoints[0], beneficiary)
174+
d = client.NewDebug(eoa, eth, mem, rep, b, chain, conf.SupportedEntryPoints[0], beneficiary)
171175
b.SetMaxBatch(1)
172176
relayer.SetWaitTimeout(0)
173177
}

internal/start/searcher.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,16 @@ import (
1919
"github.com/stackup-wallet/stackup-bundler/pkg/altmempools"
2020
"github.com/stackup-wallet/stackup-bundler/pkg/bundler"
2121
"github.com/stackup-wallet/stackup-bundler/pkg/client"
22+
"github.com/stackup-wallet/stackup-bundler/pkg/entrypoint/stake"
2223
"github.com/stackup-wallet/stackup-bundler/pkg/gas"
2324
"github.com/stackup-wallet/stackup-bundler/pkg/jsonrpc"
2425
"github.com/stackup-wallet/stackup-bundler/pkg/mempool"
2526
"github.com/stackup-wallet/stackup-bundler/pkg/modules/batch"
2627
"github.com/stackup-wallet/stackup-bundler/pkg/modules/builder"
2728
"github.com/stackup-wallet/stackup-bundler/pkg/modules/checks"
29+
"github.com/stackup-wallet/stackup-bundler/pkg/modules/entities"
2830
"github.com/stackup-wallet/stackup-bundler/pkg/modules/expire"
2931
"github.com/stackup-wallet/stackup-bundler/pkg/modules/gasprice"
30-
"github.com/stackup-wallet/stackup-bundler/pkg/modules/paymaster"
3132
"github.com/stackup-wallet/stackup-bundler/pkg/signer"
3233
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
3334
"go.opentelemetry.io/otel"
@@ -110,15 +111,15 @@ func SearcherMode() {
110111
alt,
111112
conf.MaxVerificationGas,
112113
conf.MaxBatchGasLimit,
113-
conf.MaxOpsForUnstakedSender,
114+
conf.ReputationConstants,
114115
)
115116

116117
exp := expire.New(conf.MaxOpTTL)
117118

118119
// TODO: Create separate go-routine for tracking transactions sent to the block builder.
119120
builder := builder.New(eoa, eth, fb, beneficiary, conf.BlocksInTheFuture)
120121

121-
paymaster := paymaster.New(db)
122+
rep := entities.New(db, eth, conf.ReputationConstants)
122123

123124
// Init Client
124125
c := client.New(mem, ov, chain, conf.SupportedEntryPoints)
@@ -128,13 +129,15 @@ func SearcherMode() {
128129
client.GetGasEstimateWithEthClient(rpc, ov, chain, conf.MaxBatchGasLimit),
129130
)
130131
c.SetGetUserOpByHashFunc(client.GetUserOpByHashWithEthClient(eth))
132+
c.SetGetStakeFunc(stake.GetStakeWithEthClient(eth))
131133
c.UseLogger(logr)
132134
c.UseModules(
135+
rep.CheckStatus(),
136+
rep.ValidateOpLimit(),
133137
check.ValidateOpValues(),
134-
paymaster.CheckStatus(),
135138
check.SimulateOp(),
136139
// TODO: add p2p propagation module
137-
paymaster.IncOpsSeen(),
140+
rep.IncOpsSeen(),
138141
)
139142

140143
// Init Bundler
@@ -154,8 +157,9 @@ func SearcherMode() {
154157
batch.MaintainGasLimit(conf.MaxBatchGasLimit),
155158
check.CodeHashes(),
156159
check.PaymasterDeposit(),
160+
check.SimulateBatch(),
157161
builder.SendUserOperation(),
158-
paymaster.IncOpsIncluded(),
162+
rep.IncOpsIncluded(),
159163
check.Clean(),
160164
)
161165
if err := b.Run(); err != nil {
@@ -165,7 +169,7 @@ func SearcherMode() {
165169
// init Debug
166170
var d *client.Debug
167171
if conf.DebugMode {
168-
d = client.NewDebug(eoa, eth, mem, b, chain, conf.SupportedEntryPoints[0], beneficiary)
172+
d = client.NewDebug(eoa, eth, mem, rep, b, chain, conf.SupportedEntryPoints[0], beneficiary)
169173
b.SetMaxBatch(1)
170174
}
171175

internal/testutils/checksmock.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"math/big"
55

66
"github.com/ethereum/go-ethereum/common"
7-
"github.com/stackup-wallet/stackup-bundler/pkg/entrypoint"
87
)
98

109
func MockGetCode(addr common.Address) ([]byte, error) {
@@ -15,22 +14,6 @@ func MockGetCodeZero(addr common.Address) ([]byte, error) {
1514
return []byte{}, nil
1615
}
1716

18-
func MockGetStake(addr common.Address) (*entrypoint.IStakeManagerDepositInfo, error) {
19-
return StakedDepositInfo, nil
20-
}
21-
22-
func MockGetStakeZeroDeposit(addr common.Address) (*entrypoint.IStakeManagerDepositInfo, error) {
23-
return StakedZeroDepositInfo, nil
24-
}
25-
26-
func MockGetNotStake(addr common.Address) (*entrypoint.IStakeManagerDepositInfo, error) {
27-
return NonStakedDepositInfo, nil
28-
}
29-
30-
func MockGetNotStakeZeroDeposit(addr common.Address) (*entrypoint.IStakeManagerDepositInfo, error) {
31-
return NonStakedZeroDepositInfo, nil
32-
}
33-
3417
func GetMockBaseFeeFunc(val *big.Int) func() (*big.Int, error) {
3518
return func() (*big.Int, error) {
3619
return val, nil

internal/testutils/constants.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ var (
1717
ValidAddress1 = common.HexToAddress("0x7357b8a705328FC283dF72D7Ac546895B596DC12")
1818
ValidAddress2 = common.HexToAddress("0x7357c9504B8686c008CCcD6ea47f1c21B7475dE3")
1919
ValidAddress3 = common.HexToAddress("0x7357C8D931e8cde8ea1b777Cf8578f4A7071f100")
20+
ValidAddress4 = common.HexToAddress("0x73574a159D05d20FF50D5504057D5C86f2d02a45")
21+
ValidAddress5 = common.HexToAddress("0x7357C1Fc72a14399cb845f2f71421B4CE7eCE608")
2022
ChainID = big.NewInt(1)
2123
MaxOpsForUnstakedSender = 1
2224
StakedDepositInfo = &entrypoint.IStakeManagerDepositInfo{

0 commit comments

Comments
 (0)