reth_e2e_test_utils/
wallet.rs1use crate::transaction::TransactionTestContext;
2use alloy_eips::BlockId;
3use alloy_network::Network;
4use alloy_primitives::{Address, Bytes};
5use alloy_provider::Provider;
6use alloy_rpc_types_eth::TransactionRequest;
7use alloy_signer::Signer;
8use alloy_signer_local::{coins_bip39::English, MnemonicBuilder, PrivateKeySigner};
9
10pub const TEST_MNEMONIC: &str = "test test test test test test test test test test test junk";
12
13#[derive(Debug)]
15pub struct Wallet {
16 pub inner: PrivateKeySigner,
18 pub inner_nonce: u64,
20 pub chain_id: u64,
22 amount: usize,
23}
24
25impl Wallet {
26 pub fn new(amount: usize) -> Self {
28 Self { inner: test_signer(0), chain_id: 1, amount, inner_nonce: 0 }
29 }
30
31 pub const fn with_chain_id(mut self, chain_id: u64) -> Self {
33 self.chain_id = chain_id;
34 self
35 }
36
37 pub fn wallet_gen(&self) -> Vec<PrivateKeySigner> {
39 (0..self.amount as u32).map(|idx| self.signer(idx)).collect()
40 }
41
42 pub fn signer(&self, index: u32) -> PrivateKeySigner {
44 test_signer(index).with_chain_id(Some(self.chain_id))
45 }
46
47 pub fn account(&self, index: u32) -> TestAccount {
49 TestAccount::new(self.signer(index), self.chain_id)
50 }
51}
52
53impl Default for Wallet {
54 fn default() -> Self {
55 Self::new(1)
56 }
57}
58
59pub fn test_signer(index: u32) -> PrivateKeySigner {
62 MnemonicBuilder::<English>::default()
63 .phrase(TEST_MNEMONIC)
64 .index(index)
65 .expect("valid derivation index")
66 .build()
67 .expect("valid test mnemonic")
68}
69
70#[derive(Debug, Clone)]
76pub struct TestAccount {
77 signer: PrivateKeySigner,
78 chain_id: u64,
79 nonce: u64,
80}
81
82impl TestAccount {
83 pub const DEFAULT_GAS_LIMIT: u64 = 1_000_000;
85
86 pub const DEFAULT_MAX_FEE_PER_GAS: u128 = 1_000_000_000_000;
90
91 pub const DEFAULT_MAX_PRIORITY_FEE_PER_GAS: u128 = 1_000_000_000;
94
95 pub const fn new(signer: PrivateKeySigner, chain_id: u64) -> Self {
97 Self { signer, chain_id, nonce: 0 }
98 }
99
100 pub const fn signer(&self) -> &PrivateKeySigner {
102 &self.signer
103 }
104
105 pub const fn address(&self) -> Address {
107 self.signer.address()
108 }
109
110 pub const fn chain_id(&self) -> u64 {
112 self.chain_id
113 }
114
115 pub const fn nonce(&self) -> u64 {
117 self.nonce
118 }
119
120 pub const fn next_nonce(&mut self) -> u64 {
122 let nonce = self.nonce;
123 self.nonce += 1;
124 nonce
125 }
126
127 pub async fn sync_nonce<N: Network>(
130 &mut self,
131 provider: &impl Provider<N>,
132 ) -> eyre::Result<u64> {
133 self.nonce =
134 provider.get_transaction_count(self.address()).block_id(BlockId::pending()).await?;
135 Ok(self.nonce)
136 }
137
138 pub async fn sign_tx_bytes(&mut self, mut tx: TransactionRequest) -> Bytes {
151 if tx.nonce.is_none() {
152 tx.nonce = Some(self.next_nonce());
153 }
154 tx.chain_id.get_or_insert(self.chain_id);
155 tx.gas.get_or_insert(Self::DEFAULT_GAS_LIMIT);
156 if tx.gas_price.is_none() {
157 tx.max_fee_per_gas.get_or_insert(Self::DEFAULT_MAX_FEE_PER_GAS);
158 tx.max_priority_fee_per_gas.get_or_insert(Self::DEFAULT_MAX_PRIORITY_FEE_PER_GAS);
159 }
160 TransactionTestContext::sign_tx_bytes(self.signer.clone(), tx).await
161 }
162}