Skip to content

Commit

Permalink
migration of sc-meta all snippets to unified
Browse files Browse the repository at this point in the history
  • Loading branch information
mihaicalinluca committed May 8, 2024
1 parent 4785465 commit 95db7a2
Show file tree
Hide file tree
Showing 7 changed files with 184 additions and 130 deletions.
3 changes: 2 additions & 1 deletion framework/meta/src/cmd/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ pub fn cli_main<AbiObj: ContractAbiProvider>() {
ContractCliAction::Clean => meta_config_opt.clean(),
ContractCliAction::Update => meta_config_opt.update(),
ContractCliAction::GenerateSnippets(gs_arg) => {
meta_config_opt.generate_rust_snippets(&gs_arg)
meta_config_opt.generate_rust_snippets(&gs_arg);
meta_config_opt.generate_proxy()
},
ContractCliAction::GenerateProxies => meta_config_opt.generate_proxy(),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ path = ".."
[dependencies.multiversx-sc-snippets]
version = "0.49.0"
[dependencies.multiversx-sc]
version = "0.49.0"
[dependencies]
clap = {{ version = "4.4.7", features = ["derive"] }}
serde = {{ version = "1.0", features = ["derive"] }}
toml = "0.8.6"
# [workspace]
"#
Expand All @@ -96,3 +104,27 @@ pub(crate) fn create_and_get_lib_file(snippets_folder_path: &str, overwrite: boo
}
}
}

pub(crate) fn create_sc_config_file(overwrite: bool) {
let sc_config_path = "../sc-config.toml";
let mut file = if overwrite {
File::create(sc_config_path).unwrap()
} else {
match File::options()
.create_new(true)
.write(true)
.open(sc_config_path)
{
Ok(f) => f,
Err(_) => return,
}
};

writeln!(
&mut file,
r#"[[proxy]]
path = "interact-rs/src/proxy.rs"
"#
)
.unwrap();
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,26 @@ use crate::cli_args::GenerateSnippetsArgs;
use super::{
super::meta_config::MetaConfig,
snippet_crate_gen::{
create_and_get_lib_file, create_snippets_cargo_toml, create_snippets_folder,
create_snippets_gitignore, create_src_folder,
create_and_get_lib_file, create_sc_config_file, create_snippets_cargo_toml,
create_snippets_folder, create_snippets_gitignore, create_src_folder,
},
snippet_sc_functions_gen::write_state_struct_impl,
snippet_sc_functions_gen::write_interact_struct_impl,
snippet_template_gen::{
write_contract_type_alias, write_snippet_constants, write_snippet_imports,
write_snippet_main_function, write_state_struct_declaration,
write_interact_struct_declaration, write_snippet_constants, write_snippet_imports,
write_snippet_main_function, write_snippet_state_impl, write_state_struct_declaration,
},
};

impl MetaConfig {
pub fn generate_rust_snippets(&self, args: &GenerateSnippetsArgs) {
let main_contract = self.sc_config.main_contract();
let crate_name = &main_contract.contract_name;
let snake_case_name = &main_contract.public_name_snake_case();
let wasm_output_file_path_expr = format!("\"mxsc:../output/{crate_name}.mxsc.json\"");
let file =
create_snippets_crate_and_get_lib_file(&self.snippets_dir, crate_name, args.overwrite);
write_snippets_to_file(
file,
&self.original_contract_abi,
snake_case_name,
&wasm_output_file_path_expr,
);
}
Expand All @@ -44,19 +42,16 @@ fn create_snippets_crate_and_get_lib_file(
create_snippets_gitignore(snippets_folder_path, overwrite);
create_snippets_cargo_toml(snippets_folder_path, contract_crate_name, overwrite);
create_src_folder(snippets_folder_path);
create_sc_config_file(overwrite);
create_and_get_lib_file(snippets_folder_path, overwrite)
}

fn write_snippets_to_file(
mut file: File,
abi: &ContractAbi,
snake_case_name: &str,
wasm_output_file_path_expr: &str,
) {
write_snippet_imports(&mut file, snake_case_name);
fn write_snippets_to_file(mut file: File, abi: &ContractAbi, wasm_output_file_path_expr: &str) {
write_snippet_imports(&mut file);
write_snippet_constants(&mut file);
write_contract_type_alias(&mut file, snake_case_name);
write_snippet_main_function(&mut file, abi);
write_state_struct_declaration(&mut file);
write_state_struct_impl(&mut file, abi, wasm_output_file_path_expr);
write_snippet_state_impl(&mut file);
write_interact_struct_declaration(&mut file);
write_interact_struct_impl(&mut file, abi, wasm_output_file_path_expr);
}
Original file line number Diff line number Diff line change
@@ -1,75 +1,72 @@
use std::{fs::File, io::Write};

use multiversx_sc::abi::{ContractAbi, EndpointAbi, EndpointMutabilityAbi, InputAbi, OutputAbi};
use multiversx_sc::abi::{ContractAbi, EndpointAbi, EndpointMutabilityAbi, InputAbi};

use super::{snippet_gen_common::write_newline, snippet_type_map::map_abi_type_to_rust_type};

pub(crate) fn write_state_struct_impl(
pub(crate) fn write_interact_struct_impl(
file: &mut File,
abi: &ContractAbi,
wasm_output_file_path_expr: &str,
) {
writeln!(
file,
r#"impl State {{
r#"impl ContractInteract {{
async fn new() -> Self {{
let mut interactor = Interactor::new(GATEWAY).await;
let wallet_address = interactor.register_wallet(Wallet::from_pem_file(PEM).unwrap());
let sc_addr_expr = if SC_ADDRESS == "" {{
DEFAULT_ADDRESS_EXPR.to_string()
}} else {{
"bech32:".to_string() + SC_ADDRESS
}};
let wallet_address = interactor.register_wallet(test_wallets::alice());
let contract_code = BytesValue::interpret_from(
{},
&InterpreterContext::default(),
);
let contract = ContractType::new(sc_addr_expr);
State {{
ContractInteract {{
interactor,
wallet_address,
contract_code,
contract,
state: State::load_state()
}}
}}
"#,
wasm_output_file_path_expr,
)
.unwrap();

write_deploy_method_impl(file, &abi.constructors[0]);
write_deploy_method_impl(file, &abi.constructors[0], &abi.name);

for endpoint_abi in &abi.endpoints {
write_endpoint_impl(file, endpoint_abi);
write_endpoint_impl(file, endpoint_abi, &abi.name);
}

// close impl block brackets
writeln!(file, "}}").unwrap();
}

fn write_deploy_method_impl(file: &mut File, init_abi: &EndpointAbi) {
fn write_deploy_method_impl(file: &mut File, init_abi: &EndpointAbi, name: &String) {
write_method_declaration(file, "deploy");
write_endpoint_args_declaration(file, &init_abi.inputs);
let proxy_name = format!("{}Proxy", name);

let output_type = map_output_types_to_rust_types(&init_abi.outputs);
writeln!(
file,
r#" let (new_address, _) = self
r#" let new_address = self
.interactor
.sc_deploy_get_result::<_, {}>(
ScDeployStep::new()
.call(self.contract.{}({}))
.from(&self.wallet_address)
.code(&self.contract_code)
.expect(TxExpect::ok().additional_error_message("deploy failed: ")),
)
.tx()
.from(&self.wallet_address)
.typed(proxy::{})
.init({})
.code(&self.contract_code)
.returns(ReturnsNewAddress)
.prepare_async()
.run()
.await;
s
let new_address_bech32 = bech32::encode(&new_address);
self.state
.set_address(Bech32Address::from_bech32_string(new_address_bech32.clone()));
println!("new address: {{new_address_bech32}}");"#,
output_type,
init_abi.rust_method_name,
proxy_name,
endpoint_args_when_called(init_abi.inputs.as_slice()),
)
.unwrap();
Expand All @@ -79,14 +76,14 @@ s
write_newline(file);
}

fn write_endpoint_impl(file: &mut File, endpoint_abi: &EndpointAbi) {
fn write_endpoint_impl(file: &mut File, endpoint_abi: &EndpointAbi, name: &String) {
write_method_declaration(file, &endpoint_abi.rust_method_name);
write_payments_declaration(file, &endpoint_abi.payable_in_tokens);
write_endpoint_args_declaration(file, &endpoint_abi.inputs);
if matches!(endpoint_abi.mutability, EndpointMutabilityAbi::Readonly) {
write_contract_query(file, endpoint_abi);
write_contract_query(file, endpoint_abi, name);
} else {
write_contract_call(file, endpoint_abi);
write_contract_call(file, endpoint_abi, name);
}

// close method block brackets
Expand Down Expand Up @@ -116,7 +113,7 @@ fn write_payments_declaration(file: &mut File, accepted_tokens: &[String]) {
} else {
writeln!(
file,
" let token_id = b\"\";
" let token_id = String::new();
let token_nonce = 0u64;
let token_amount = {};",
biguint_default.get_default_value_expr()
Expand Down Expand Up @@ -157,80 +154,56 @@ fn endpoint_args_when_called(inputs: &[InputAbi]) -> String {
result
}

fn write_contract_call(file: &mut File, endpoint_abi: &EndpointAbi) {
fn write_contract_call(file: &mut File, endpoint_abi: &EndpointAbi, name: &String) {
let payment_snippet = if endpoint_abi.payable_in_tokens.is_empty() {
""
} else if endpoint_abi.payable_in_tokens[0] == "EGLD" {
"\n .egld_value(egld_amount)"
"\n .egld(egld_amount)"
} else {
"\n .esdt_transfer(token_id.to_vec(), token_nonce, token_amount)"
"\n .payment((TokenIdentifier::from(token_id.as_str()), token_nonce, token_amount))"
};

let output_type = map_output_types_to_rust_types(&endpoint_abi.outputs);
writeln!(
file,
r#" let response: TypedResponse<{}> = self
r#" let response = self
.interactor
.sc_call_use_result(
ScCallStep::new()
.call(self.contract.{}({}))
.from(&self.wallet_address){}
.expect(TxExpect::ok().additional_error_message("SC call failed: ")),
)
.tx()
.from(&self.wallet_address)
.to(self.state.current_address())
.typed(proxy::{}Proxy)
.{}({}){}
.returns(ReturnsRawResult)
.prepare_async()
.run()
.await;
let result = response.result.unwrap();
println!("Result: {{result:?}}");"#,
output_type,
println!("Result: {{response:?}}");"#,
name,
endpoint_abi.rust_method_name,
endpoint_args_when_called(endpoint_abi.inputs.as_slice()),
payment_snippet,
)
.unwrap();
}

fn write_contract_query(file: &mut File, endpoint_abi: &EndpointAbi) {
let output_type = map_output_types_to_rust_types(&endpoint_abi.outputs);
fn write_contract_query(file: &mut File, endpoint_abi: &EndpointAbi, name: &String) {
writeln!(
file,
r#" let result_value: {} = self
r#" let result_value = self
.interactor
.vm_query(self.contract.{}({}))
.query()
.to(self.state.current_address())
.typed(proxy::{}Proxy)
.{}({})
.returns(ReturnsResult)
.prepare_async()
.run()
.await;
"#,
output_type,
println!("Result: {{result_value:?}}");"#,
name,
endpoint_abi.rust_method_name,
endpoint_args_when_called(endpoint_abi.inputs.as_slice()),
)
.unwrap();
}

pub fn map_output_types_to_rust_types(outputs: &[OutputAbi]) -> String {
let results_len = outputs.len();
if results_len == 0 {
return "()".to_string();
}

// format to be the same as when multi-value is an argument
// for results, each type is a different array entry
let mut input_str = String::new();
if results_len > 1 {
input_str += "multi";
input_str += "<";
}

for (i, output) in outputs.iter().enumerate() {
input_str += &output.type_names.abi;

if i < results_len - 1 {
input_str += ",";
}
}

if results_len > 1 {
input_str += ">";
}

let output_rust_type = map_abi_type_to_rust_type(input_str);
output_rust_type.get_type_name().to_string()
}
Loading

0 comments on commit 95db7a2

Please sign in to comment.