Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support loading private key #314

Merged
merged 2 commits into from
Jun 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
106 changes: 102 additions & 4 deletions bin/silius/src/cli/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::utils::{
parse_u256, parse_uopool_mode,
};
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, group = "account")]
pub private_key: Option<String>,

/// Flashbots private key
#[clap(long, 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
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
Loading