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