From 85957f48feaff670fdadb97447c7fd4c454b7ddd Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 10 Oct 2024 12:27:57 +0300 Subject: [PATCH 1/3] abi - title --- .../abi-tester/abi_tester_expected_main.abi.json | 1 + .../feature-tests/abi-tester/src/abi_tester.rs | 1 + framework/base/src/abi/endpoint_abi.rs | 6 ++++-- framework/base/src/external_view_contract.rs | 1 + framework/derive/src/generate/abi_gen.rs | 6 ++++++ framework/derive/src/model/method.rs | 1 + .../src/parse/{attributes/mod.rs => attributes.rs} | 2 +- .../derive/src/parse/attributes/attr_names.rs | 1 + framework/derive/src/parse/attributes/doc_attr.rs | 13 +++++++++++++ framework/derive/src/parse/endpoint_parse.rs | 14 +++++++++++++- framework/derive/src/parse/method_parse.rs | 4 +++- .../meta-lib/src/abi_json/endpoint_abi_json.rs | 5 +++++ .../scenario/tests/contract_without_macros.rs | 4 ++++ 13 files changed, 54 insertions(+), 5 deletions(-) rename framework/derive/src/parse/{attributes/mod.rs => attributes.rs} (93%) diff --git a/contracts/feature-tests/abi-tester/abi_tester_expected_main.abi.json b/contracts/feature-tests/abi-tester/abi_tester_expected_main.abi.json index 60edcce7f1..8748ff67aa 100644 --- a/contracts/feature-tests/abi-tester/abi_tester_expected_main.abi.json +++ b/contracts/feature-tests/abi-tester/abi_tester_expected_main.abi.json @@ -110,6 +110,7 @@ }, { "name": "multi_result_3", + "title": "result-3", "mutability": "mutable", "inputs": [], "outputs": [ diff --git a/contracts/feature-tests/abi-tester/src/abi_tester.rs b/contracts/feature-tests/abi-tester/src/abi_tester.rs index f5ce735a8c..9405fa28a0 100644 --- a/contracts/feature-tests/abi-tester/src/abi_tester.rs +++ b/contracts/feature-tests/abi-tester/src/abi_tester.rs @@ -58,6 +58,7 @@ pub trait AbiTester { fn take_managed_type(&self, _arg: AbiManagedType) {} #[endpoint] + #[title("result-3")] #[output_name("multi-result-1")] #[output_name("multi-result-2")] #[output_name("multi-result-3")] diff --git a/framework/base/src/abi/endpoint_abi.rs b/framework/base/src/abi/endpoint_abi.rs index 03e098d0e9..d8a50f18f0 100644 --- a/framework/base/src/abi/endpoint_abi.rs +++ b/framework/base/src/abi/endpoint_abi.rs @@ -1,7 +1,6 @@ use super::*; use alloc::{ - string::{String, ToString}, - vec::Vec, + borrow::ToOwned, string::{String, ToString}, vec::Vec }; #[derive(Clone, Debug)] @@ -42,6 +41,7 @@ pub struct EndpointAbi { pub docs: Vec, pub name: String, pub rust_method_name: String, + pub title: Option, pub only_owner: bool, pub only_admin: bool, pub labels: Vec, @@ -62,6 +62,7 @@ impl EndpointAbi { docs: &[&str], name: &str, rust_method_name: &str, + title: Option<&str>, only_owner: bool, only_admin: bool, mutability: EndpointMutabilityAbi, @@ -80,6 +81,7 @@ impl EndpointAbi { endpoint_type, mutability, payable_in_tokens: payable_in_tokens.iter().map(|s| s.to_string()).collect(), + title: title.map(|title| title.to_owned()), inputs: Vec::new(), outputs: Vec::new(), allow_multiple_var_args, diff --git a/framework/base/src/external_view_contract.rs b/framework/base/src/external_view_contract.rs index 2b01176176..7a1e0722a7 100644 --- a/framework/base/src/external_view_contract.rs +++ b/framework/base/src/external_view_contract.rs @@ -39,6 +39,7 @@ pub fn external_view_contract_constructor_abi() -> EndpointAbi { ], "init", EXTERNAL_VIEW_CONSTRUCTOR_FLAG, + None, false, false, EndpointMutabilityAbi::Mutable, diff --git a/framework/derive/src/generate/abi_gen.rs b/framework/derive/src/generate/abi_gen.rs index 5d5a73934c..db727cf7c4 100644 --- a/framework/derive/src/generate/abi_gen.rs +++ b/framework/derive/src/generate/abi_gen.rs @@ -15,6 +15,11 @@ fn generate_endpoint_snippet( ) -> proc_macro2::TokenStream { let endpoint_docs = &m.docs; let rust_method_name = m.name.to_string(); + let title_tokens = if let Some(title) = &m.title { + quote! { Some(#title) } + } else { + quote! { None } + }; let payable_in_tokens = m.payable_metadata().abi_strings(); let input_snippets: Vec = m @@ -58,6 +63,7 @@ fn generate_endpoint_snippet( &[ #(#endpoint_docs),* ], #endpoint_name, #rust_method_name, + #title_tokens, #only_owner, #only_admin, #mutability_tokens, diff --git a/framework/derive/src/model/method.rs b/framework/derive/src/model/method.rs index 22acf8eb78..8a4e8ec5eb 100644 --- a/framework/derive/src/model/method.rs +++ b/framework/derive/src/model/method.rs @@ -40,6 +40,7 @@ pub struct Method { pub generics: syn::Generics, pub unprocessed_attributes: Vec, pub method_args: Vec, + pub title: Option, pub output_names: Vec, pub label_names: Vec, pub return_type: syn::ReturnType, diff --git a/framework/derive/src/parse/attributes/mod.rs b/framework/derive/src/parse/attributes.rs similarity index 93% rename from framework/derive/src/parse/attributes/mod.rs rename to framework/derive/src/parse/attributes.rs index e58c1a912e..a5f9906db9 100644 --- a/framework/derive/src/parse/attributes/mod.rs +++ b/framework/derive/src/parse/attributes.rs @@ -11,7 +11,7 @@ mod trait_prop_names; mod util; pub use argument_attr::*; -pub use doc_attr::{extract_doc, extract_macro_attributes, OutputNameAttribute}; +pub use doc_attr::{extract_doc, extract_macro_attributes, OutputNameAttribute, TitleAttribute}; pub use endpoint_attr::*; pub use event_attr::*; pub use label_attr::*; diff --git a/framework/derive/src/parse/attributes/attr_names.rs b/framework/derive/src/parse/attributes/attr_names.rs index 29784fc1c3..5a976e185c 100644 --- a/framework/derive/src/parse/attributes/attr_names.rs +++ b/framework/derive/src/parse/attributes/attr_names.rs @@ -2,6 +2,7 @@ pub(super) static ATTR_PAYABLE: &str = "payable"; pub(super) static ATTR_ONLY_OWNER: &str = "only_owner"; pub(super) static ATTR_ONLY_ADMIN: &str = "only_admin"; pub(super) static ATTR_ONLY_USER_ACCOUNT: &str = "only_user_account"; +pub(super) static ATTR_TITLE: &str = "title"; pub(super) static ATTR_OUTPUT_NAME: &str = "output_name"; pub(super) static ATTR_PAYMENT: &str = "payment"; // synonymous with `payment_amount` pub(super) static ATTR_PAYMENT_AMOUNT: &str = "payment_amount"; diff --git a/framework/derive/src/parse/attributes/doc_attr.rs b/framework/derive/src/parse/attributes/doc_attr.rs index 5c5ed4d41b..c9fc871eef 100644 --- a/framework/derive/src/parse/attributes/doc_attr.rs +++ b/framework/derive/src/parse/attributes/doc_attr.rs @@ -81,3 +81,16 @@ impl OutputNameAttribute { }) } } + + +pub struct TitleAttribute { + pub title: String, +} + +impl TitleAttribute { + pub fn parse(attr: &syn::Attribute) -> Option { + is_attr_one_string_arg(attr, ATTR_TITLE).map(|arg_str| TitleAttribute { + title: arg_str, + }) + } +} diff --git a/framework/derive/src/parse/endpoint_parse.rs b/framework/derive/src/parse/endpoint_parse.rs index 5edc30ad08..26fb612ea6 100644 --- a/framework/derive/src/parse/endpoint_parse.rs +++ b/framework/derive/src/parse/endpoint_parse.rs @@ -8,7 +8,7 @@ use super::{ is_allow_multiple_var_args, is_callback_raw, is_init, is_only_admin, is_only_owner, is_only_user_account, is_upgrade, CallbackAttribute, EndpointAttribute, ExternalViewAttribute, LabelAttribute, OutputNameAttribute, PromisesCallbackAttribute, - ViewAttribute, + TitleAttribute, ViewAttribute, }, MethodAttributesPass1, }; @@ -224,6 +224,18 @@ pub fn process_output_names_attribute(attr: &syn::Attribute, method: &mut Method .is_some() } +pub fn process_title_attribute(attr: &syn::Attribute, method: &mut Method) -> bool { + TitleAttribute::parse(attr) + .map(|title_attr| { + assert!( + method.title.is_none(), + "only one title attribute allowed per method" + ); + method.title = Some(title_attr.title); + }) + .is_some() +} + pub fn process_label_names_attribute(attr: &syn::Attribute, method: &mut Method) -> bool { LabelAttribute::parse(attr) .map(|label_attr| { diff --git a/framework/derive/src/parse/method_parse.rs b/framework/derive/src/parse/method_parse.rs index 481638068a..e299912cdd 100644 --- a/framework/derive/src/parse/method_parse.rs +++ b/framework/derive/src/parse/method_parse.rs @@ -13,7 +13,7 @@ use super::{ process_init_attribute, process_label_names_attribute, process_only_admin_attribute, process_only_owner_attribute, process_only_user_account_attribute, process_output_names_attribute, process_payable_attribute, process_promises_callback_attribute, - process_upgrade_attribute, process_view_attribute, + process_title_attribute, process_upgrade_attribute, process_view_attribute, }; pub struct MethodAttributesPass1 { pub method_name: String, @@ -56,6 +56,7 @@ pub fn process_method(m: &syn::TraitItemFn, trait_attributes: &TraitProperties) generics: m.sig.generics.clone(), unprocessed_attributes: Vec::new(), method_args, + title: None, output_names: Vec::new(), label_names: Vec::new(), return_type: m.sig.output.clone(), @@ -131,6 +132,7 @@ fn process_attribute_second_pass( || process_storage_mapper_from_address_attribute(attr, method) || process_storage_is_empty_attribute(attr, method) || process_storage_clear_attribute(attr, method) + || process_title_attribute(attr, method) || process_output_names_attribute(attr, method) || process_label_names_attribute(attr, method) } diff --git a/framework/meta-lib/src/abi_json/endpoint_abi_json.rs b/framework/meta-lib/src/abi_json/endpoint_abi_json.rs index b6bd041713..0537718e4a 100644 --- a/framework/meta-lib/src/abi_json/endpoint_abi_json.rs +++ b/framework/meta-lib/src/abi_json/endpoint_abi_json.rs @@ -93,6 +93,10 @@ pub struct EndpointAbiJson { pub docs: Vec, pub name: String, + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub title: Option, + #[serde(rename = "onlyOwner")] #[serde(default)] #[serde(skip_serializing_if = "Option::is_none")] @@ -128,6 +132,7 @@ impl From<&EndpointAbi> for EndpointAbiJson { EndpointAbiJson { docs: abi.docs.iter().map(|d| d.to_string()).collect(), name: abi.name.to_string(), + title: abi.title.clone(), only_owner: if abi.only_owner { Some(true) } else { None }, only_admin: if abi.only_admin { Some(true) } else { None }, mutability: match abi.mutability { diff --git a/framework/scenario/tests/contract_without_macros.rs b/framework/scenario/tests/contract_without_macros.rs index a08f1a4bbd..7515365023 100644 --- a/framework/scenario/tests/contract_without_macros.rs +++ b/framework/scenario/tests/contract_without_macros.rs @@ -390,6 +390,7 @@ mod sample_adder { &[], "getSum", "sum", + None, false, false, multiversx_sc::abi::EndpointMutabilityAbi::Readonly, @@ -411,6 +412,7 @@ mod sample_adder { &[], "init", "init", + None, false, false, multiversx_sc::abi::EndpointMutabilityAbi::Mutable, @@ -426,6 +428,7 @@ mod sample_adder { &[], "upgrade", "upgrade", + None, false, false, multiversx_sc::abi::EndpointMutabilityAbi::Mutable, @@ -441,6 +444,7 @@ mod sample_adder { &["Add desired amount to the storage variable."], "add", "add", + None, false, false, multiversx_sc::abi::EndpointMutabilityAbi::Mutable, From 06d4bf5fb8901cc7893d44753b6fab539c6fc047 Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 10 Oct 2024 13:26:15 +0300 Subject: [PATCH 2/3] abi - title in a few contracts --- contracts/core/price-aggregator/src/lib.rs | 1 + contracts/core/wegld-swap/src/wegld.rs | 2 ++ .../examples/crowdfunding-esdt/src/crowdfunding_esdt.rs | 5 +++++ 3 files changed, 8 insertions(+) diff --git a/contracts/core/price-aggregator/src/lib.rs b/contracts/core/price-aggregator/src/lib.rs index 1dbed54848..9d9443dcb5 100644 --- a/contracts/core/price-aggregator/src/lib.rs +++ b/contracts/core/price-aggregator/src/lib.rs @@ -358,6 +358,7 @@ pub trait PriceAggregator: } #[view(getOracles)] + #[title("oracles")] fn get_oracles(&self) -> MultiValueEncoded { let mut result = MultiValueEncoded::new(); for key in self.oracle_status().keys() { diff --git a/contracts/core/wegld-swap/src/wegld.rs b/contracts/core/wegld-swap/src/wegld.rs index 4a38cab09e..23a4493494 100644 --- a/contracts/core/wegld-swap/src/wegld.rs +++ b/contracts/core/wegld-swap/src/wegld.rs @@ -55,12 +55,14 @@ pub trait EgldEsdtSwap: multiversx_sc_modules::pause::PauseModule { } #[view(getLockedEgldBalance)] + #[title("lockedEgldBalance")] fn get_locked_egld_balance(&self) -> BigUint { self.blockchain() .get_sc_balance(&EgldOrEsdtTokenIdentifier::egld(), 0) } #[view(getWrappedEgldTokenId)] + #[title("wrappedEgldTokenId")] #[storage_mapper("wrappedEgldTokenId")] fn wrapped_egld_token_id(&self) -> SingleValueMapper; } diff --git a/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt.rs b/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt.rs index 1dea493562..d47e256f08 100644 --- a/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt.rs +++ b/contracts/examples/crowdfunding-esdt/src/crowdfunding_esdt.rs @@ -55,6 +55,7 @@ pub trait Crowdfunding { } #[view(getCurrentFunds)] + #[title("currentFunds")] fn get_current_funds(&self) -> BigUint { let token = self.cf_token_identifier().get(); @@ -106,18 +107,22 @@ pub trait Crowdfunding { // storage #[view(getTarget)] + #[title("target")] #[storage_mapper("target")] fn target(&self) -> SingleValueMapper; #[view(getDeadline)] + #[title("deadline")] #[storage_mapper("deadline")] fn deadline(&self) -> SingleValueMapper; #[view(getDeposit)] + #[title("deposit")] #[storage_mapper("deposit")] fn deposit(&self, donor: &ManagedAddress) -> SingleValueMapper; #[view(getCrowdfundingTokenIdentifier)] + #[title("tokenIdentifier")] #[storage_mapper("tokenIdentifier")] fn cf_token_identifier(&self) -> SingleValueMapper; } From 6b5925f9ae5124dd1ef8475c80f4ecc17610676a Mon Sep 17 00:00:00 2001 From: Andrei Marinica Date: Thu, 10 Oct 2024 13:26:47 +0300 Subject: [PATCH 3/3] cleanup --- framework/base/src/abi/endpoint_abi.rs | 4 +++- framework/derive/src/parse/attributes/doc_attr.rs | 5 +---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/framework/base/src/abi/endpoint_abi.rs b/framework/base/src/abi/endpoint_abi.rs index d8a50f18f0..c1d0567643 100644 --- a/framework/base/src/abi/endpoint_abi.rs +++ b/framework/base/src/abi/endpoint_abi.rs @@ -1,6 +1,8 @@ use super::*; use alloc::{ - borrow::ToOwned, string::{String, ToString}, vec::Vec + borrow::ToOwned, + string::{String, ToString}, + vec::Vec, }; #[derive(Clone, Debug)] diff --git a/framework/derive/src/parse/attributes/doc_attr.rs b/framework/derive/src/parse/attributes/doc_attr.rs index c9fc871eef..e9485d6368 100644 --- a/framework/derive/src/parse/attributes/doc_attr.rs +++ b/framework/derive/src/parse/attributes/doc_attr.rs @@ -82,15 +82,12 @@ impl OutputNameAttribute { } } - pub struct TitleAttribute { pub title: String, } impl TitleAttribute { pub fn parse(attr: &syn::Attribute) -> Option { - is_attr_one_string_arg(attr, ATTR_TITLE).map(|arg_str| TitleAttribute { - title: arg_str, - }) + is_attr_one_string_arg(attr, ATTR_TITLE).map(|arg_str| TitleAttribute { title: arg_str }) } }