multiversx_sc_snippets/interactor/
interactor_base.rs1use crate::sdk::{data::network_config::NetworkConfig, wallet::Wallet};
2use multiversx_sc_scenario::{
3 imports::{Bech32Address, ScenarioRunner},
4 mandos_system::{run_list::ScenarioRunnerList, run_trace::ScenarioTraceFile},
5 meta::tools::find_current_workspace,
6 multiversx_sc::types::Address,
7};
8use multiversx_sdk::gateway::{GatewayAsyncService, NetworkConfigRequest, SetStateAccount};
9use std::{
10 collections::HashMap,
11 fs::File,
12 io::BufReader,
13 path::{Path, PathBuf},
14 time::Duration,
15};
16
17use crate::{account_tool::retrieve_account_as_scenario_set_state, Sender};
18
19pub const INTERACTOR_SCENARIO_TRACE_PATH: &str = "interactor_trace.scen.json";
20pub const INTERACTOR_SET_STATE_PATH: &str = "set_state.json";
21
22pub struct InteractorBase<GatewayProxy>
23where
24 GatewayProxy: GatewayAsyncService,
25{
26 pub proxy: GatewayProxy,
27 pub use_chain_simulator: bool,
28 pub network_config: NetworkConfig,
29 pub sender_map: HashMap<Address, Sender>,
30
31 pub waiting_time_ms: u64,
32 pub pre_runners: ScenarioRunnerList,
33 pub post_runners: ScenarioRunnerList,
34
35 pub current_dir: PathBuf,
36}
37
38impl<GatewayProxy> InteractorBase<GatewayProxy>
39where
40 GatewayProxy: GatewayAsyncService,
41{
42 pub async fn new(gateway_uri: &str) -> Self {
44 let proxy = GatewayProxy::from_uri(gateway_uri);
45 let network_config = proxy.request(NetworkConfigRequest).await.unwrap();
46 Self {
47 proxy,
48 use_chain_simulator: false,
49 network_config,
50 sender_map: HashMap::new(),
51 waiting_time_ms: 0,
52 pre_runners: ScenarioRunnerList::empty(),
53 post_runners: ScenarioRunnerList::empty(),
54 current_dir: PathBuf::default(),
55 }
56 }
57
58 pub fn use_chain_simulator(mut self, use_chain_simulator: bool) -> Self {
59 self.use_chain_simulator = use_chain_simulator;
60 self
61 }
62
63 pub async fn register_wallet(&mut self, wallet: Wallet) -> Address {
64 let address = wallet.to_address();
65
66 self.send_user_funds(&address.to_bech32(self.get_hrp()))
67 .await
68 .unwrap();
69 self.generate_blocks(1).await.unwrap();
70 self.sender_map.insert(
71 address.clone(),
72 Sender {
73 address: address.clone(),
74 hrp: self.network_config.address_hrp.clone(),
75 wallet,
76 current_nonce: None,
77 },
78 );
79 address
80 }
81
82 pub async fn sleep(&mut self, duration: Duration) {
83 let millis = duration.as_millis() as u64;
84 self.waiting_time_ms += millis;
85 self.proxy.sleep(millis).await;
86 }
87
88 pub async fn with_tracer<P: AsRef<Path>>(mut self, path: P) -> Self {
89 self.post_runners.push(ScenarioTraceFile::new(path));
90 self
91 }
92
93 pub async fn retrieve_account(&mut self, wallet_address: &Bech32Address) {
94 let (set_state_account, set_state_step) =
95 retrieve_account_as_scenario_set_state(&self.proxy, wallet_address).await;
96 self.pre_runners.run_set_state_step(&set_state_step);
97 self.post_runners.run_set_state_step(&set_state_step);
98
99 let path = self.get_state_file_path();
100 set_state_account.add_to_state_file(path.as_path());
101 }
102
103 pub fn get_state_file_path(&self) -> PathBuf {
104 self.current_dir.join(INTERACTOR_SET_STATE_PATH)
105 }
106
107 pub fn get_hrp(&self) -> &str {
108 &self.network_config.address_hrp
109 }
110
111 pub fn get_accounts_from_file(&self) -> Vec<SetStateAccount> {
112 let file_path = self.get_state_file_path();
113
114 if !file_path.exists() {
115 return Vec::new();
116 }
117
118 let file = File::open(file_path).expect("Failed to open state file");
119 let reader = BufReader::new(file);
120
121 serde_json::from_reader(reader).unwrap_or_else(|_| {
122 println!("Failed to parse state file; returning an empty list of accounts");
123 Vec::new()
124 })
125 }
126
127 pub fn set_current_dir_from_workspace(&mut self, relative_path: &str) -> &mut Self {
130 let mut path = find_current_workspace().unwrap();
131 path.push(relative_path);
132 self.current_dir = path;
133 self
134 }
135}