1
1
use alloy_primitives:: { hex, Address } ;
2
2
use alloy_signer:: { k256:: ecdsa:: SigningKey , utils:: secret_key_to_address} ;
3
3
use alloy_signer_local:: PrivateKeySigner ;
4
- use clap:: { builder :: TypedValueParser , Parser } ;
4
+ use clap:: Parser ;
5
5
use eyre:: Result ;
6
+ use itertools:: Either ;
6
7
use rayon:: iter:: { self , ParallelIterator } ;
7
8
use regex:: Regex ;
8
9
use serde:: { Deserialize , Serialize } ;
@@ -19,16 +20,11 @@ pub type GeneratedWallet = (SigningKey, Address);
19
20
#[ derive( Clone , Debug , Parser ) ]
20
21
pub struct VanityArgs {
21
22
/// Prefix regex pattern or hex string.
22
- #[ arg(
23
- long,
24
- required_unless_present = "ends_with" ,
25
- value_parser = HexAddressValidator ,
26
- value_name = "HEX"
27
- ) ]
23
+ #[ arg( long, value_name = "PATTERN" , required_unless_present = "ends_with" ) ]
28
24
pub starts_with : Option < String > ,
29
25
30
26
/// Suffix regex pattern or hex string.
31
- #[ arg( long, value_parser = HexAddressValidator , value_name = "HEX " ) ]
27
+ #[ arg( long, value_name = "PATTERN " ) ]
32
28
pub ends_with : Option < String > ,
33
29
34
30
// 2^64-1 is max possible nonce per [eip-2681](https://eips.ethereum.org/EIPS/eip-2681).
@@ -74,24 +70,22 @@ impl WalletData {
74
70
impl VanityArgs {
75
71
pub fn run ( self ) -> Result < PrivateKeySigner > {
76
72
let Self { starts_with, ends_with, nonce, save_path } = self ;
73
+
77
74
let mut left_exact_hex = None ;
78
75
let mut left_regex = None ;
79
- let mut right_exact_hex = None ;
80
- let mut right_regex = None ;
81
-
82
76
if let Some ( prefix) = starts_with {
83
- if let Ok ( decoded) = hex:: decode ( & prefix) {
84
- left_exact_hex = Some ( decoded)
85
- } else {
86
- left_regex = Some ( Regex :: new ( & format ! ( r"^{prefix}" ) ) ?) ;
77
+ match parse_pattern ( & prefix, true ) ? {
78
+ Either :: Left ( left) => left_exact_hex = Some ( left) ,
79
+ Either :: Right ( re) => left_regex = Some ( re) ,
87
80
}
88
81
}
89
82
83
+ let mut right_exact_hex = None ;
84
+ let mut right_regex = None ;
90
85
if let Some ( suffix) = ends_with {
91
- if let Ok ( decoded) = hex:: decode ( & suffix) {
92
- right_exact_hex = Some ( decoded)
93
- } else {
94
- right_regex = Some ( Regex :: new ( & format ! ( r"{suffix}$" ) ) ?) ;
86
+ match parse_pattern ( & suffix, false ) ? {
87
+ Either :: Left ( right) => right_exact_hex = Some ( right) ,
88
+ Either :: Right ( re) => right_regex = Some ( re) ,
95
89
}
96
90
}
97
91
@@ -331,29 +325,15 @@ impl VanityMatcher for RegexMatcher {
331
325
}
332
326
}
333
327
334
- /// Parse 40 byte addresses
335
- #[ derive( Clone , Copy , Debug , Default ) ]
336
- pub struct HexAddressValidator ;
337
-
338
- impl TypedValueParser for HexAddressValidator {
339
- type Value = String ;
340
-
341
- fn parse_ref (
342
- & self ,
343
- _cmd : & clap:: Command ,
344
- _arg : Option < & clap:: Arg > ,
345
- value : & std:: ffi:: OsStr ,
346
- ) -> Result < Self :: Value , clap:: Error > {
347
- if value. len ( ) > 40 {
348
- return Err ( clap:: Error :: raw (
349
- clap:: error:: ErrorKind :: InvalidValue ,
350
- "vanity patterns length exceeded. cannot be more than 40 characters" ,
351
- ) )
328
+ fn parse_pattern ( pattern : & str , is_start : bool ) -> Result < Either < Vec < u8 > , Regex > > {
329
+ if let Ok ( decoded) = hex:: decode ( pattern) {
330
+ if decoded. len ( ) > 20 {
331
+ return Err ( eyre:: eyre!( "Hex pattern must be less than 20 bytes" ) ) ;
352
332
}
353
- let value = value . to_str ( ) . ok_or_else ( || {
354
- clap :: Error :: raw ( clap :: error :: ErrorKind :: InvalidUtf8 , "address must be valid utf8" )
355
- } ) ? ;
356
- Ok ( value . to_string ( ) )
333
+ Ok ( Either :: Left ( decoded ) )
334
+ } else {
335
+ let ( prefix , suffix ) = if is_start { ( "^" , "" ) } else { ( "" , "$" ) } ;
336
+ Ok ( Either :: Right ( Regex :: new ( & format ! ( "{prefix}{pattern}{suffix}" ) ) ? ) )
357
337
}
358
338
}
359
339
0 commit comments