Skip to content

Commit

Permalink
feat: support loading private key
Browse files Browse the repository at this point in the history
  • Loading branch information
malm0d authored and Vid201 committed Jun 15, 2024
1 parent 356ea8a commit 01a47bd
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 14 deletions.
42 changes: 34 additions & 8 deletions bin/silius/src/bundler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,15 +121,41 @@ where
let chain_conn = Chain::from(chain_id);

let wallet: Wallet;
if args.send_bundle_mode == SendStrategy::Flashbots {
wallet = Wallet::from_file(args.mnemonic_file.into(), chain_id, true)
.map_err(|error| eyre::format_err!("Could not load mnemonic file: {}", error))?;
info!("Wallet Signer {:?}", wallet.signer);
info!("Flashbots Signer {:?}", wallet.flashbots_signer);

if let Some(mnemonic_file) = args.mnemonic_file {
if args.send_bundle_mode == SendStrategy::Flashbots {
wallet = Wallet::from_file(mnemonic_file.into(), chain_id, true)
.map_err(|error| eyre::format_err!("Could not load mnemonic file: {}", error))?;
info!("Wallet Signer {:?}", wallet.signer);
info!("Flashbots Signer {:?}", wallet.flashbots_signer);
} else {
wallet = Wallet::from_file(mnemonic_file.into(), chain_id, false)
.map_err(|error| eyre::format_err!("Could not load mnemonic file: {}", error))?;
info!("{:?}", wallet.signer);
}
} else if let Some(private_key) = args.private_key {
if args.send_bundle_mode == SendStrategy::Flashbots {
wallet = Wallet::from_private_key(
private_key.as_str(),
chain_id,
true,
args.flashbots_private_key.as_deref(),
)
.map_err(|error| {
eyre::format_err!("Could not load from private key or flashbots key: {}", error)
})?;
info!("Wallet Signer {:?}", wallet.signer);
info!("Flashbots Signer {:?}", wallet.flashbots_signer);
} else {
if args.flashbots_private_key.is_some() {
info!("Flashbots key is ignored since send bundle mode is not Flashbots");
}
wallet = Wallet::from_private_key(private_key.as_str(), chain_id, false, None)
.map_err(|error| eyre::format_err!("Could not load from private key: {}", error))?;
info!("{:?}", wallet.signer);
}
} else {
wallet = Wallet::from_file(args.mnemonic_file.into(), chain_id, false)
.map_err(|error| eyre::format_err!("Could not load mnemonic file: {}", error))?;
info!("{:?}", wallet.signer);
panic!("Neither mnemonic file nor private key was found");
}

info!("Connecting to uopool gRPC service...");
Expand Down
108 changes: 103 additions & 5 deletions bin/silius/src/cli/args.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::utils::{
parse_address, parse_duration, parse_enr, parse_label_value, parse_send_bundle_mode,
parse_u256, parse_uopool_mode,
parse_u256, parse_uopool_mode, validate_private_key,
};
use alloy_chains::{Chain, NamedChain};
use clap::{Parser, ValueEnum};
use clap::{ArgGroup, Parser, ValueEnum};
use discv5::Enr;
use ethers::types::{Address, U256};
use expanded_pathbuf::ExpandedPathBuf;
Expand Down Expand Up @@ -37,6 +37,7 @@ pub enum StorageType {

/// Bundler CLI args
#[derive(Debug, Clone, Parser, PartialEq)]
#[clap(group(ArgGroup::new("account").required(true).args(&["mnemonic_file", "private_key"])))]
pub struct BundlerArgs {
/// Bundler gRPC address to listen on.
#[clap(long = "bundler.addr", default_value_t = IpAddr::V4(Ipv4Addr::LOCALHOST))]
Expand All @@ -47,8 +48,16 @@ pub struct BundlerArgs {
pub bundler_port: u16,

/// Path to the mnemonic file.
#[clap(long)]
pub mnemonic_file: PathBuf,
#[clap(long, group = "account")]
pub mnemonic_file: Option<PathBuf>,

/// Private key for the wallet
#[clap(long, value_parser=validate_private_key, group = "account")]
pub private_key: Option<String>,

/// Flashbots private key
#[clap(long, value_parser=validate_private_key, conflicts_with = "mnemonic_file")]
pub flashbots_private_key: Option<String>,

/// The bundler beneficiary address.
#[clap(long, value_parser=parse_address)]
Expand Down Expand Up @@ -364,8 +373,97 @@ mod tests {
];
assert_eq!(
BundlerArgs {
mnemonic_file: PathBuf::from(
mnemonic_file: Some(PathBuf::from(
"~/.silius/0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990"
)),
private_key: None,
flashbots_private_key: None,
beneficiary: Address::from_str("0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990")
.unwrap(),
min_balance: U256::from(100000000000000000_u64),
bundle_interval: 10,
send_bundle_mode: SendStrategy::EthereumClient,
bundler_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
bundler_port: 3002,
enable_access_list: false,
},
BundlerArgs::try_parse_from(args).unwrap()
);
}

#[test]
fn bundler_args_private_key() {
let args = vec![
"bundlerargs",
"--private-key",
"4c5e5d3076c425e8d8affe9c2a0da32b779820ef008fdda02d5c7b783674d8c4",
"--beneficiary",
"0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990",
"--min-balance",
"100000000000000000",
"--bundler.addr",
"127.0.0.1",
"--bundler.port",
"3002",
"--bundle-interval",
"10",
];
assert_eq!(
BundlerArgs {
mnemonic_file: None,
private_key: Some(
String::from_str(
"4c5e5d3076c425e8d8affe9c2a0da32b779820ef008fdda02d5c7b783674d8c4"
)
.unwrap()
),
flashbots_private_key: None,
beneficiary: Address::from_str("0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990")
.unwrap(),
min_balance: U256::from(100000000000000000_u64),
bundle_interval: 10,
send_bundle_mode: SendStrategy::EthereumClient,
bundler_addr: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
bundler_port: 3002,
enable_access_list: false,
},
BundlerArgs::try_parse_from(args).unwrap()
);
}

#[test]
fn bundler_args_private_key_flashbots_private_key() {
let args = vec![
"bundlerargs",
"--private-key",
"4c5e5d3076c425e8d8affe9c2a0da32b779820ef008fdda02d5c7b783674d8c4",
"--flashbots-private-key",
"df218be02efd744fc91f93d7f3c49676fb99b296e99c1410fccd65be79d608a7",
"--beneficiary",
"0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990",
"--min-balance",
"100000000000000000",
"--bundler.addr",
"127.0.0.1",
"--bundler.port",
"3002",
"--bundle-interval",
"10",
];
assert_eq!(
BundlerArgs {
mnemonic_file: None,
private_key: Some(
String::from_str(
"4c5e5d3076c425e8d8affe9c2a0da32b779820ef008fdda02d5c7b783674d8c4"
)
.unwrap()
),
flashbots_private_key: Some(
String::from_str(
"df218be02efd744fc91f93d7f3c49676fb99b296e99c1410fccd65be79d608a7"
)
.unwrap()
),
beneficiary: Address::from_str("0x690B9A9E9aa1C9dB991C7721a92d351Db4FaC990")
.unwrap(),
Expand Down
16 changes: 16 additions & 0 deletions bin/silius/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,19 @@ where

Ok(())
}

pub fn validate_private_key(hex_string: &str) -> Result<String, String> {
let chars = hex_string.chars();

if chars.clone().count() != 64 {
return Err(format!("{hex_string} is not a valid private key"));
}

for c in chars {
if !c.is_ascii_hexdigit() {
return Err(format!("{hex_string} is not a valid hexadecimal string"));
}
}

Ok(String::from(hex_string))
}
31 changes: 30 additions & 1 deletion crates/primitives/src/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use crate::{UserOperation, UserOperationSigned};
use ethers::{
prelude::{k256::ecdsa::SigningKey, rand},
prelude::{k256::ecdsa::SigningKey, rand, LocalWallet},
signers::{coins_bip39::English, MnemonicBuilder, Signer},
types::Address,
};
Expand Down Expand Up @@ -140,6 +140,35 @@ impl Wallet {
}
}

/// Create a new wallet from the given private key
/// if `flashbots_key` is true, then `flashbots_private_key` must be provided
///
/// # Arguments
/// * `private_key` - The private key
/// * `chain_id` - The chain id of the blockchain network to be used
/// * `flashbots_key` - Whether to create a Flashbots key
/// * `flashbots_private_key` - The private key for the Flashbots wallet
///
/// # Returns
/// * `Self` - A new `Wallet` instance
pub fn from_private_key(
private_key: &str,
chain_id: u64,
flashbots_key: bool,
flashbots_private_key: Option<&str>,
) -> eyre::Result<Self> {
let wallet = private_key.parse::<LocalWallet>()?.with_chain_id(chain_id);
if flashbots_key {
let flashbots_wallet = flashbots_private_key
.expect("Flashbots private key is required")
.parse::<LocalWallet>()?
.with_chain_id(chain_id);
Ok(Self { signer: wallet, flashbots_signer: Some(flashbots_wallet) })
} else {
Ok(Self { signer: wallet, flashbots_signer: None })
}
}

/// Signs the user operation
///
/// # Arguments
Expand Down

0 comments on commit 01a47bd

Please sign in to comment.