multiversx_sc_meta_lib/contract/generate_snippets/
snippet_template_gen.rs1use std::{fs::File, io::Write};
2
3use multiversx_sc::abi::ContractAbi;
4
5use super::snippet_gen_common::write_newline;
6
7pub(crate) fn write_snippet_imports(file: &mut File) {
8 writeln!(
9 file,
10 "#![allow(non_snake_case)]
11
12pub mod config;
13mod proxy;
14
15use config::Config;
16use multiversx_sc_snippets::imports::*;
17use serde::{{Deserialize, Serialize}};
18use std::{{
19 io::{{Read, Write}},
20 path::Path,
21}};"
22 )
23 .unwrap();
24
25 write_newline(file);
26}
27
28pub(crate) fn write_snippet_constants(file: &mut File) {
29 writeln!(file, "const STATE_FILE: &str = \"state.toml\";").unwrap();
30}
31
32pub(crate) fn write_snippet_main_function(file: &mut File, abi: &ContractAbi, crate_name: &str) {
33 writeln!(
34 file,
35 "
36pub async fn {crate_name}_cli() {{
37 env_logger::init();
38
39 let mut args = std::env::args();
40 let _ = args.next();
41 let cmd = args.next().expect(\"at least one argument required\");
42 let config = Config::new();
43 let mut interact = ContractInteract::new(config).await;
44 match cmd.as_str() {{"
45 )
46 .unwrap();
47
48 writeln!(file, r#" "deploy" => interact.deploy().await,"#).unwrap();
50
51 for upgrade_endpoint in &abi.upgrade_constructors {
52 writeln!(
53 file,
54 r#" "{}" => interact.{}().await,"#,
55 upgrade_endpoint.name, upgrade_endpoint.rust_method_name
56 )
57 .unwrap();
58 }
59
60 for endpoint in &abi.endpoints {
61 writeln!(
62 file,
63 r#" "{}" => interact.{}().await,"#,
64 endpoint.name, endpoint.rust_method_name
65 )
66 .unwrap();
67 }
68
69 writeln!(
71 file,
72 " _ => panic!(\"unknown command: {{}}\", &cmd),
73 }}
74}}"
75 )
76 .unwrap();
77}
78
79pub(crate) fn write_interact_struct_declaration(file: &mut File) {
80 writeln!(
81 file,
82 "pub struct ContractInteract {{
83 interactor: Interactor,
84 wallet_address: Address,
85 contract_code: BytesValue,
86 state: State
87}}"
88 )
89 .unwrap();
90
91 write_newline(file);
92}
93
94pub(crate) fn write_state_struct_declaration(file: &mut File) {
95 writeln!(
96 file,
97 "
98#[derive(Debug, Default, Serialize, Deserialize)]
99pub struct State {{
100 contract_address: Option<Bech32Address>
101}}"
102 )
103 .unwrap();
104
105 write_newline(file);
106}
107
108pub(crate) fn write_snippet_state_impl(file: &mut File) {
109 writeln!(
110 file,
111 r#"impl State {{
112 // Deserializes state from file
113 pub fn load_state() -> Self {{
114 if Path::new(STATE_FILE).exists() {{
115 let mut file = std::fs::File::open(STATE_FILE).unwrap();
116 let mut content = String::new();
117 file.read_to_string(&mut content).unwrap();
118 toml::from_str(&content).unwrap()
119 }} else {{
120 Self::default()
121 }}
122 }}
123
124 /// Sets the contract address
125 pub fn set_address(&mut self, address: Bech32Address) {{
126 self.contract_address = Some(address);
127 }}
128
129 /// Returns the contract address
130 pub fn current_address(&self) -> &Bech32Address {{
131 self.contract_address
132 .as_ref()
133 .expect("no known contract, deploy first")
134 }}
135 }}
136
137 impl Drop for State {{
138 // Serializes state to file
139 fn drop(&mut self) {{
140 let mut file = std::fs::File::create(STATE_FILE).unwrap();
141 file.write_all(toml::to_string(self).unwrap().as_bytes())
142 .unwrap();
143 }}
144 }}"#
145 )
146 .unwrap();
147
148 write_newline(file);
149}
150
151pub(crate) fn write_config_imports(file: &mut File) {
152 writeln!(
153 file,
154 "#![allow(unused)]
155
156use serde::Deserialize;
157use std::io::Read;
158"
159 )
160 .unwrap();
161}
162
163pub(crate) fn write_config_constants(file: &mut File) {
164 writeln!(
165 file,
166 "/// Config file
167const CONFIG_FILE: &str = \"config.toml\";
168"
169 )
170 .unwrap();
171}
172
173pub(crate) fn write_config_struct_declaration(file: &mut File) {
174 writeln!(
175 file,
176 r#"#[derive(Debug, Deserialize)]
177#[serde(rename_all = "lowercase")]
178pub enum ChainType {{
179 Real,
180 Simulator,
181}}
182
183/// Contract Interact configuration
184#[derive(Debug, Deserialize)]
185pub struct Config {{
186 pub gateway_uri: String,
187 pub chain_type: ChainType,
188}}
189"#
190 )
191 .unwrap();
192}
193
194pub(crate) fn write_config_struct_impl(file: &mut File) {
195 writeln!(
196 file,
197 r#"impl Config {{
198 // Deserializes config from file
199 pub fn new() -> Self {{
200 let mut file = std::fs::File::open(CONFIG_FILE).unwrap();
201 let mut content = String::new();
202 file.read_to_string(&mut content).unwrap();
203 toml::from_str(&content).unwrap()
204 }}
205
206 pub fn chain_simulator_config() -> Self {{
207 Config {{
208 gateway_uri: "http://localhost:8085".to_owned(),
209 chain_type: ChainType::Simulator,
210 }}
211 }}
212
213 // Returns the gateway URI
214 pub fn gateway_uri(&self) -> &str {{
215 &self.gateway_uri
216 }}
217
218 // Returns if chain type is chain simulator
219 pub fn use_chain_simulator(&self) -> bool {{
220 match self.chain_type {{
221 ChainType::Real => false,
222 ChainType::Simulator => true,
223 }}
224 }}
225}}"#
226 )
227 .unwrap();
228}
229
230pub(crate) fn write_chain_sim_test_to_file(file: &mut File, crate_name: &str) {
231 writeln!(
232 file,
233 r#"use multiversx_sc_snippets::imports::*;
234use rust_interact::{{config::Config, ContractInteract}};
235
236// Simple deploy test that runs using the chain simulator configuration.
237// In order for this test to work, make sure that the `config.toml` file contains the chain simulator config (or choose it manually)
238// The chain simulator should already be installed and running before attempting to run this test.
239// The chain-simulator-tests feature should be present in Cargo.toml.
240// Can be run with `sc-meta test -c`.
241#[tokio::test]
242#[cfg_attr(not(feature = "chain-simulator-tests"), ignore)]
243async fn deploy_test_{crate_name}_cs() {{
244 let mut interactor = ContractInteract::new(Config::chain_simulator_config()).await;
245
246 interactor.deploy().await;
247}}"#
248 ).unwrap()
249}
250
251pub(crate) fn write_interactor_test_to_file(file: &mut File, crate_name: &str) {
252 writeln!(
253 file,
254 r#"use multiversx_sc_snippets::imports::*;
255use rust_interact::{{config::Config, ContractInteract}};
256
257// Simple deploy test that runs on the real blockchain configuration.
258// In order for this test to work, make sure that the `config.toml` file contains the real blockchain config (or choose it manually)
259// Can be run with `sc-meta test`.
260#[tokio::test]
261#[ignore = "run on demand, relies on real blockchain state"]
262async fn deploy_test_{crate_name}() {{
263 let mut interactor = ContractInteract::new(Config::new()).await;
264
265 interactor.deploy().await;
266}}"#
267 ).unwrap()
268}