Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: split calldata and provider call #2852

Merged
merged 1 commit into from
Dec 31, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 103 additions & 71 deletions crates/dojo/bindgen/src/plugins/typescript/generator/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,88 +35,107 @@
buffer.iter().position(|b| b.contains(fn_wrapper)).unwrap()
}

/// Generate string template to build function calldata.
/// * namespace - &str - Token namespace
/// * contract_name - &str - Token contract_name avoid name clashing between different systems
/// * token - &Function - cairo function token
fn build_function_calldata(&self, contract_name: &str, token: &Function) -> String {
format!(
"\tconst build_{contract_name}_{}_calldata = ({}) => {{
\t\treturn {{
\t\t\tcontractName: \"{contract_name}\",
\t\t\tentrypoint: \"{}\",
\t\t\tcalldata: [{}],
\t\t}};
\t}};
",
token.name.to_case(Case::Camel),
self.get_function_input_args(token).join(", "),
token.name,
self.format_function_calldata(token),
)
}

/// Generate string template to build system function
/// We call different methods depending if token is View or External
/// * namespace - &str - Token namespace
/// * contract_name - &str - Token contract_name avoid name clashing between different systems
/// * token - &Function - cairo function token
fn generate_system_function(
&self,
namespace: &str,
contract_name: &str,
token: &Function,
) -> String {
match token.state_mutability {
let function_calldata = self.build_function_calldata(contract_name, token);
let function_name = format!("{contract_name}_{}", token.name.to_case(Case::Camel));
let function_call = match token.state_mutability {
StateMutability::External => format!(
"\tconst {contract_name}_{} = async ({}) => {{
"\tconst {function_name} = async ({}) => {{
\t\ttry {{
\t\t\treturn await provider.execute(
\t\t\t\tsnAccount,
\t\t\t\t{{
\t\t\t\t\tcontractName: \"{contract_name}\",
\t\t\t\t\tentrypoint: \"{}\",
\t\t\t\t\tcalldata: [{}],
\t\t\t\t}},
\t\t\t\tbuild_{function_name}_calldata({}),
\t\t\t\t\"{namespace}\",
\t\t\t);
\t\t}} catch (error) {{
\t\t\tconsole.error(error);
\t\t\tthrow error;
\t\t}}
\t}};\n",
token.name.to_case(Case::Camel),
self.format_function_inputs(token),
token.name,
self.format_function_calldata(token)
self.format_function_calldata(token),
),
StateMutability::View => format!(
"\tconst {contract_name}_{} = async ({}) => {{
"\tconst {function_name} = async ({}) => {{

Check warning on line 90 in crates/dojo/bindgen/src/plugins/typescript/generator/function.rs

View check run for this annotation

Codecov / codecov/patch

crates/dojo/bindgen/src/plugins/typescript/generator/function.rs#L90

Added line #L90 was not covered by tests
\t\ttry {{
\t\t\treturn await provider.call(\"{namespace}\", {{
\t\t\t\tcontractName: \"{contract_name}\",
\t\t\t\tentrypoint: \"{}\",
\t\t\t\tcalldata: [{}],
\t\t\t}});
\t\t\treturn await provider.call(\"{namespace}\", build_{function_name}_calldata({});

Check warning on line 92 in crates/dojo/bindgen/src/plugins/typescript/generator/function.rs

View check run for this annotation

Codecov / codecov/patch

crates/dojo/bindgen/src/plugins/typescript/generator/function.rs#L92

Added line #L92 was not covered by tests
\t\t}} catch (error) {{
\t\t\tconsole.error(error);
\t\t\tthrow error;

Check warning on line 95 in crates/dojo/bindgen/src/plugins/typescript/generator/function.rs

View check run for this annotation

Codecov / codecov/patch

crates/dojo/bindgen/src/plugins/typescript/generator/function.rs#L95

Added line #L95 was not covered by tests
\t\t}}
\t}};\n",
token.name.to_case(Case::Camel),
self.format_function_inputs(token),
token.name,
self.format_function_calldata(token)
self.format_function_calldata(token),

Check warning on line 99 in crates/dojo/bindgen/src/plugins/typescript/generator/function.rs

View check run for this annotation

Codecov / codecov/patch

crates/dojo/bindgen/src/plugins/typescript/generator/function.rs#L99

Added line #L99 was not covered by tests
Comment on lines +90 to +99
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Ohayo sensei, fix the missing parenthesis.

There’s a syntax error with the provider.call(...) invocation. Add the closing parenthesis.

- return await provider.call("{namespace}", build_{function_name}_calldata({});
+ return await provider.call("{namespace}", build_{function_name}_calldata({}));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"\tconst {function_name} = async ({}) => {{
\t\ttry {{
\t\t\treturn await provider.call(\"{namespace}\", {{
\t\t\t\tcontractName: \"{contract_name}\",
\t\t\t\tentrypoint: \"{}\",
\t\t\t\tcalldata: [{}],
\t\t\t}});
\t\t\treturn await provider.call(\"{namespace}\", build_{function_name}_calldata({});
\t\t}} catch (error) {{
\t\t\tconsole.error(error);
\t\t\tthrow error;
\t\t}}
\t}};\n",
token.name.to_case(Case::Camel),
self.format_function_inputs(token),
token.name,
self.format_function_calldata(token)
self.format_function_calldata(token),
"\tconst {function_name} = async ({}) => {{
\t\ttry {{
\t\t\treturn await provider.call(\"{namespace}\", build_{function_name}_calldata({}));
\t\t}} catch (error) {{
\t\t\tconsole.error(error);
\t\t\tthrow error;
\t\t}}
\t}};\n",
self.format_function_inputs(token),
self.format_function_calldata(token),

),
}
};
format!("{}\n{}", function_calldata, function_call)
}

fn get_function_input_args(&self, token: &Function) -> Vec<String> {
token.inputs.iter().fold(Vec::new(), |mut acc, input| {
let prefix = match &input.1 {
Token::Composite(t) => {
if !token_is_custom_enum(t)
&& (t.r#type == CompositeType::Enum
|| (t.r#type == CompositeType::Struct
&& !t.type_path.starts_with("core"))

Check warning on line 112 in crates/dojo/bindgen/src/plugins/typescript/generator/function.rs

View check run for this annotation

Codecov / codecov/patch

crates/dojo/bindgen/src/plugins/typescript/generator/function.rs#L112

Added line #L112 was not covered by tests
|| t.r#type == CompositeType::Unknown)
{
"models."
} else {
""

Check warning on line 117 in crates/dojo/bindgen/src/plugins/typescript/generator/function.rs

View check run for this annotation

Codecov / codecov/patch

crates/dojo/bindgen/src/plugins/typescript/generator/function.rs#L117

Added line #L117 was not covered by tests
}
}
_ => "",
};
let mut type_input = JsPrimitiveInputType::from(&input.1).to_string();
if type_input.contains("<") {
type_input = type_input.replace("<", format!("<{}", prefix).as_str());
} else {
type_input = format!("{}{}", prefix, type_input);
}
acc.push(format!("{}: {}", input.0.to_case(Case::Camel), type_input));
acc
})
}

fn format_function_inputs(&self, token: &Function) -> String {
let inputs = match token.state_mutability {
StateMutability::External => vec!["snAccount: Account | AccountInterface".to_owned()],
StateMutability::View => Vec::new(),
};
token
.inputs
.iter()
.fold(inputs, |mut acc, input| {
let prefix = match &input.1 {
Token::Composite(t) => {
if !token_is_custom_enum(t)
&& (t.r#type == CompositeType::Enum
|| (t.r#type == CompositeType::Struct
&& !t.type_path.starts_with("core"))
|| t.r#type == CompositeType::Unknown)
{
"models."
} else {
""
}
}
_ => "",
};
let mut type_input = JsPrimitiveInputType::from(&input.1).to_string();
if type_input.contains("<") {
type_input = type_input.replace("<", format!("<{}", prefix).as_str());
} else {
type_input = format!("{}{}", prefix, type_input);
}
acc.push(format!("{}: {}", input.0.to_case(Case::Camel), type_input));
acc
})
.join(", ")
[inputs, self.get_function_input_args(token)].concat().join(", ")
}

fn format_function_calldata(&self, token: &Function) -> String {
Expand All @@ -143,12 +162,15 @@
token: &Function,
buffer: &mut Buffer,
) {
let return_token = "\treturn {";
let function_name = format!("{contract_name}_{}", token.name.to_case(Case::Camel));
let build_calldata = format!("build{}Calldata", token.name.to_case(Case::Pascal));
let build_calldata_sc =
format!("build_{contract_name}_{}_calldata", token.name.to_case(Case::Camel));
let return_token = "\n\n\treturn {";
if !buffer.has(return_token) {
buffer.push(format!(
"\treturn {{\n\t\t{}: {{\n\t\t\t{}: {}_{},\n\t\t}},\n\t}};\n}}",
contract_name,
token.name.to_case(Case::Camel),
"\n\n\treturn {{\n\t\t{}: {{\n\t\t\t{}: {function_name},\n\t\t\t{build_calldata}: \
{build_calldata_sc},\n\t\t}},\n\t}};\n}}",
contract_name,
token.name.to_case(Case::Camel)
));
Expand All @@ -171,9 +193,8 @@
) {
if let Some(insert_pos) = buffer.get_first_before_pos(",", pos, return_idx) {
let gen = format!(
"\n\t\t\t{}: {}_{},",
token.name.to_case(Case::Camel),
contract_name,
"\n\t\t\t{}: {function_name},\n\t\t\t{build_calldata}: \
{build_calldata_sc},",
token.name.to_case(Case::Camel)
);
// avoid duplicating identifiers. This can occur because some contracts keeps
Expand All @@ -189,11 +210,10 @@
// if buffer has return but not contract_name, we append in this object
buffer.insert_after(
format!(
"\n\t\t{}: {{\n\t\t\t{}: {}_{},\n\t\t}},",
contract_name,
token.name.to_case(Case::Camel),
"\n\t\t{}: {{\n\t\t\t{}: {function_name},\n\t\t\t{build_calldata}: \
{build_calldata_sc},\n\t\t}},",
contract_name,
token.name.to_case(Case::Camel),
token.name.to_case(Case::Camel)
),
return_token,
",",
Expand Down Expand Up @@ -271,20 +291,25 @@
fn test_generate_system_function() {
let generator = TsFunctionGenerator {};
let function = create_change_theme_function();
let expected = "\tconst actions_changeTheme = async (snAccount: Account | \
AccountInterface, value: BigNumberish) => {
let expected = "\tconst build_actions_changeTheme_calldata = (value: BigNumberish) => {
\t\treturn {
\t\t\tcontractName: \"actions\",
\t\t\tentrypoint: \"change_theme\",
\t\t\tcalldata: [value],
\t\t};
\t};

\tconst actions_changeTheme = async (snAccount: Account | AccountInterface, value: BigNumberish) \
=> {
\t\ttry {
\t\t\treturn await provider.execute(
\t\t\t\tsnAccount,
\t\t\t\t{
\t\t\t\t\tcontractName: \"actions\",
\t\t\t\t\tentrypoint: \"change_theme\",
\t\t\t\t\tcalldata: [value],
\t\t\t\t},
\t\t\t\tbuild_actions_changeTheme_calldata(value),
\t\t\t\t\"onchain_dash\",
\t\t\t);
\t\t} catch (error) {
\t\t\tconsole.error(error);
\t\t\tthrow error;
\t\t}
\t};
";
Expand Down Expand Up @@ -367,9 +392,10 @@

generator.setup_function_wrapper_end("actions", &create_change_theme_function(), &mut buff);

let expected = "\treturn {
let expected = "\n\n\treturn {
\t\tactions: {
\t\t\tchangeTheme: actions_changeTheme,
\t\t\tbuildChangeThemeCalldata: build_actions_changeTheme_calldata,
\t\t},
\t};
}";
Expand All @@ -382,24 +408,29 @@
&create_increate_global_counter_function(),
&mut buff,
);
let expected_2 = "\treturn {
let expected_2 = "\n\n\treturn {
\t\tactions: {
\t\t\tchangeTheme: actions_changeTheme,
\t\t\tbuildChangeThemeCalldata: build_actions_changeTheme_calldata,
\t\t\tincreaseGlobalCounter: actions_increaseGlobalCounter,
\t\t\tbuildIncreaseGlobalCounterCalldata: build_actions_increaseGlobalCounter_calldata,
\t\t},
\t};
}";
assert_eq!(1, buff.len());
assert_eq!(expected_2, buff[0]);

generator.setup_function_wrapper_end("dojo_starter", &create_move_function(), &mut buff);
let expected_3 = "\treturn {
let expected_3 = "\n\n\treturn {
\t\tactions: {
\t\t\tchangeTheme: actions_changeTheme,
\t\t\tbuildChangeThemeCalldata: build_actions_changeTheme_calldata,
\t\t\tincreaseGlobalCounter: actions_increaseGlobalCounter,
\t\t\tbuildIncreaseGlobalCounterCalldata: build_actions_increaseGlobalCounter_calldata,
\t\t},
\t\tdojo_starter: {
\t\t\tmove: dojo_starter_move,
\t\t\tbuildMoveCalldata: build_dojo_starter_move_calldata,
\t\t},
\t};
}";
Expand All @@ -414,9 +445,10 @@

generator.setup_function_wrapper_end("actions", &create_change_theme_function(), &mut buff);

let expected = "\treturn {
let expected = "\n\n\treturn {
\t\tactions: {
\t\t\tchangeTheme: actions_changeTheme,
\t\t\tbuildChangeThemeCalldata: build_actions_changeTheme_calldata,
\t\t},
\t};
}";
Expand Down
Loading