pm_utils_cli/
client.rs

1use miden_client::{
2    account::{
3        component::{BasicWallet, RpoFalcon512},
4        Account, AccountBuilder, AccountStorageMode, AccountType,
5    },
6    auth::AuthSecretKey,
7    crypto::{FeltRng, RpoRandomCoin, SecretKey},
8    rpc::{Endpoint, TonicRpcClient},
9    store::{sqlite_store::SqliteStore, StoreAuthenticator},
10    Client, ClientError, Felt, Word,
11};
12use rand::Rng;
13use std::{path::PathBuf, sync::Arc};
14
15// Client Setup
16// ================================================================================================
17
18pub async fn setup_client(path: PathBuf) -> Result<Client<RpoRandomCoin>, ClientError> {
19    let exec_dir = PathBuf::new();
20    let store_config = exec_dir.join(path);
21    // RPC endpoint and timeout
22    let endpoint = Endpoint::new("http".to_string(), "localhost".to_string(), Some(57291));
23    let timeout_ms = 10_000;
24
25    let rpc_api = Box::new(TonicRpcClient::new(endpoint, timeout_ms));
26
27    let mut seed_rng = rand::thread_rng();
28    let coin_seed: [u64; 4] = seed_rng.gen();
29
30    let rng = RpoRandomCoin::new(coin_seed.map(Felt::new));
31
32    let store = SqliteStore::new(store_config.into())
33        .await
34        .map_err(ClientError::StoreError)?;
35    let arc_store = Arc::new(store);
36
37    let authenticator = StoreAuthenticator::new_with_rng(arc_store.clone(), rng.clone());
38
39    let client = Client::new(rpc_api, rng, arc_store, Arc::new(authenticator), true);
40
41    Ok(client)
42}
43
44pub async fn initialize_testnet_client() -> Result<Client<RpoRandomCoin>, ClientError> {
45    // RPC endpoint and timeout
46    let endpoint = Endpoint::new(
47        "https".to_string(),
48        "rpc.testnet.miden.io".to_string(),
49        Some(443),
50    );
51    let timeout_ms = 10_000;
52
53    // Build RPC client
54    let rpc_api = Box::new(TonicRpcClient::new(endpoint, timeout_ms));
55
56    // Seed RNG
57    let mut seed_rng = rand::thread_rng();
58    let coin_seed: [u64; 4] = seed_rng.gen();
59
60    // Create random coin instance
61    let rng = RpoRandomCoin::new(coin_seed.map(Felt::new));
62
63    // SQLite path
64    let store_path = "store.sqlite3";
65
66    // Initialize SQLite store
67    let store = SqliteStore::new(store_path.into())
68        .await
69        .map_err(ClientError::StoreError)?;
70    let arc_store = Arc::new(store);
71
72    // Create authenticator referencing the store and RNG
73    let authenticator = StoreAuthenticator::new_with_rng(arc_store.clone(), rng.clone());
74
75    // Instantiate client (toggle debug mode as needed)
76    let client = Client::new(rpc_api, rng, arc_store, Arc::new(authenticator), true);
77
78    Ok(client)
79}
80
81pub async fn create_wallet(
82    client: &mut Client<impl FeltRng>,
83    storage_mode: AccountStorageMode,
84) -> Result<(Account, Word), ClientError> {
85    let mut init_seed = [0u8; 32];
86    client.rng().fill_bytes(&mut init_seed);
87    let anchor_block = client.get_latest_epoch_block().await.unwrap();
88    let key_pair = SecretKey::with_rng(client.rng());
89    let (account, seed) = AccountBuilder::new(init_seed)
90        .anchor((&anchor_block).try_into().unwrap())
91        .account_type(AccountType::RegularAccountImmutableCode)
92        .storage_mode(storage_mode)
93        .with_component(RpoFalcon512::new(key_pair.public_key()))
94        .with_component(BasicWallet)
95        .build()
96        .unwrap();
97
98    client
99        .add_account(
100            &account,
101            Some(seed),
102            &AuthSecretKey::RpoFalcon512(key_pair.clone()),
103            false,
104        )
105        .await?;
106    Ok((account, seed))
107}