fuels_test_helpers/
accounts.rs1use std::mem::size_of;
2
3use fuel_crypto::SecretKey;
4use fuels_accounts::wallet::WalletUnlocked;
5use fuels_core::types::errors::Result;
6
7use crate::{
8 node_types::{ChainConfig, NodeConfig},
9 setup_custom_assets_coins, setup_test_provider,
10 wallets_config::*,
11};
12
13pub async fn launch_provider_and_get_wallet() -> Result<WalletUnlocked> {
27 let mut wallets =
28 launch_custom_provider_and_get_wallets(WalletsConfig::new(Some(1), None, None), None, None)
29 .await?;
30
31 Ok(wallets.pop().expect("should have one wallet"))
32}
33
34pub async fn launch_custom_provider_and_get_wallets(
54 wallet_config: WalletsConfig,
55 node_config: Option<NodeConfig>,
56 chain_config: Option<ChainConfig>,
57) -> Result<Vec<WalletUnlocked>> {
58 const SIZE_SECRET_KEY: usize = size_of::<SecretKey>();
59 const PADDING_BYTES: usize = SIZE_SECRET_KEY - size_of::<u64>();
60 let mut secret_key: [u8; SIZE_SECRET_KEY] = [0; SIZE_SECRET_KEY];
61
62 let mut wallets: Vec<_> = (1..=wallet_config.num_wallets())
63 .map(|wallet_counter| {
64 secret_key[PADDING_BYTES..].copy_from_slice(&wallet_counter.to_be_bytes());
65
66 WalletUnlocked::new_from_private_key(
67 SecretKey::try_from(secret_key.as_slice())
68 .expect("This should never happen as we provide a [u8; SIZE_SECRET_KEY] array"),
69 None,
70 )
71 })
72 .collect();
73
74 let all_coins = wallets
75 .iter()
76 .flat_map(|wallet| setup_custom_assets_coins(wallet.address(), wallet_config.assets()))
77 .collect::<Vec<_>>();
78
79 let provider = setup_test_provider(all_coins, vec![], node_config, chain_config).await?;
80
81 for wallet in &mut wallets {
82 wallet.set_provider(provider.clone());
83 }
84
85 Ok(wallets)
86}
87
88#[cfg(test)]
89mod tests {
90 use fuel_core_chain_config::ChainConfig;
91 use fuel_tx::{ConsensusParameters, TxParameters};
92 use fuel_types::AssetId;
93 use fuels_accounts::ViewOnlyAccount;
94 use fuels_core::types::{coin_type::CoinType, errors::Result};
95 use rand::Fill;
96
97 use crate::{launch_custom_provider_and_get_wallets, AssetConfig, WalletsConfig};
98
99 #[tokio::test]
100 async fn test_wallet_config() -> Result<()> {
101 let num_wallets = 2;
102 let num_coins = 3;
103 let amount = 100;
104 let config = WalletsConfig::new(Some(num_wallets), Some(num_coins), Some(amount));
105
106 let wallets = launch_custom_provider_and_get_wallets(config, None, None).await?;
107 let provider = wallets.first().unwrap().try_provider()?;
108 let consensus_parameters = provider.consensus_parameters().await?;
109
110 assert_eq!(wallets.len(), num_wallets as usize);
111
112 for wallet in &wallets {
113 let coins = wallet
114 .get_coins(*consensus_parameters.base_asset_id())
115 .await?;
116
117 assert_eq!(coins.len(), num_coins as usize);
118
119 for coin in &coins {
120 assert_eq!(coin.amount, amount);
121 }
122 }
123 Ok(())
124 }
125
126 #[tokio::test]
127 async fn test_wallet_config_multiple_assets(
128 ) -> std::result::Result<(), Box<dyn std::error::Error>> {
129 let mut rng = rand::thread_rng();
130 let num_wallets = 3;
131
132 let asset_base = AssetConfig {
133 id: AssetId::zeroed(),
134 num_coins: 2,
135 coin_amount: 4,
136 };
137
138 let mut asset_id_1 = AssetId::zeroed();
139 asset_id_1.try_fill(&mut rng)?;
140 let asset_1 = AssetConfig {
141 id: asset_id_1,
142 num_coins: 6,
143 coin_amount: 8,
144 };
145
146 let mut asset_id_2 = AssetId::zeroed();
147 asset_id_2.try_fill(&mut rng)?;
148 let asset_2 = AssetConfig {
149 id: asset_id_2,
150 num_coins: 10,
151 coin_amount: 12,
152 };
153
154 let assets = vec![asset_base, asset_1, asset_2];
155
156 let config = WalletsConfig::new_multiple_assets(num_wallets, assets.clone());
157 let wallets = launch_custom_provider_and_get_wallets(config, None, None).await?;
158 assert_eq!(wallets.len(), num_wallets as usize);
159
160 for asset in assets {
161 for wallet in &wallets {
162 let resources = wallet
163 .get_spendable_resources(asset.id, asset.num_coins * asset.coin_amount, None)
164 .await?;
165 assert_eq!(resources.len() as u64, asset.num_coins);
166
167 for resource in resources {
168 assert_eq!(resource.amount(), asset.coin_amount);
169 match resource {
170 CoinType::Coin(coin) => {
171 assert_eq!(&coin.owner, wallet.address())
172 }
173 CoinType::Message(_) => panic!("resources contained messages"),
174 CoinType::Unknown => panic!("resources contained unknown coins"),
175 }
176 }
177 }
178 }
179 Ok(())
180 }
181
182 #[tokio::test]
183 async fn generated_wallets_are_deterministic() -> Result<()> {
184 let num_wallets = 32;
185 let num_coins = 1;
186 let amount = 100;
187 let config = WalletsConfig::new(Some(num_wallets), Some(num_coins), Some(amount));
188
189 let wallets = launch_custom_provider_and_get_wallets(config, None, None).await?;
190
191 assert_eq!(
192 wallets.get(31).unwrap().address().to_string(),
193 "fuel1rsjlwjzx0px3zu2al05jdlzp4j5quqzlk7pzyk4g45x6m7r3elzsz9dwh4".to_string()
194 );
195 Ok(())
196 }
197
198 #[tokio::test]
199 async fn generated_wallets_with_custom_chain_config() -> Result<()> {
200 let mut consensus_parameters = ConsensusParameters::default();
201
202 let block_gas_limit = 10_000_000_000;
203 consensus_parameters.set_block_gas_limit(block_gas_limit);
204
205 let max_gas_per_tx = 10_000_000_000;
206 let tx_params = TxParameters::default().with_max_gas_per_tx(max_gas_per_tx);
207 consensus_parameters.set_tx_params(tx_params);
208
209 let chain_config = ChainConfig {
210 consensus_parameters,
211 ..ChainConfig::default()
212 };
213
214 let num_wallets = 4;
215 let num_coins = 3;
216 let coin_amount = 2_000_000_000;
217 let wallets = launch_custom_provider_and_get_wallets(
218 WalletsConfig::new(Some(num_wallets), Some(num_coins), Some(coin_amount)),
219 None,
220 Some(chain_config),
221 )
222 .await?;
223
224 assert_eq!(wallets.len() as u64, num_wallets);
225
226 for wallet in wallets.into_iter() {
227 assert_eq!(
228 wallet
229 .try_provider()?
230 .consensus_parameters()
231 .await?
232 .tx_params()
233 .max_gas_per_tx(),
234 max_gas_per_tx
235 );
236 assert_eq!(
237 wallet.get_coins(AssetId::zeroed()).await?.len() as u64,
238 num_coins
239 );
240 assert_eq!(
241 *wallet
242 .get_balances()
243 .await?
244 .get("0000000000000000000000000000000000000000000000000000000000000000")
245 .expect("failed to get value"),
246 (num_coins * coin_amount) as u128
247 );
248 }
249
250 Ok(())
251 }
252}