diff --git a/crates/lang/codegen/src/generator/metadata.rs b/crates/lang/codegen/src/generator/metadata.rs index 55a69478a05..622221cc814 100644 --- a/crates/lang/codegen/src/generator/metadata.rs +++ b/crates/lang/codegen/src/generator/metadata.rs @@ -122,6 +122,7 @@ impl Metadata<'_> { .iter() .filter_map(|attr| attr.extract_docs()); let selector_bytes = constructor.composed_selector().hex_lits(); + let is_payable = constructor.is_payable(); let constructor = constructor.callable(); let ident = constructor.ident(); let args = constructor.inputs().map(Self::generate_dispatch_argument); @@ -133,6 +134,7 @@ impl Metadata<'_> { .args([ #( #args ),* ]) + .payable(#is_payable) .docs([ #( #docs ),* ]) diff --git a/crates/metadata/src/lib.rs b/crates/metadata/src/lib.rs index 65432220017..86bc9e285ca 100644 --- a/crates/metadata/src/lib.rs +++ b/crates/metadata/src/lib.rs @@ -71,12 +71,14 @@ pub enum MetadataVersioned { /// Version 1 of the contract metadata. V1(MetadataVersionDeprecated), /// Version 2 of the contract metadata. - V2(InkProject), + V2(MetadataVersionDeprecated), + /// Version 3 of the contract metadata. + V3(InkProject), } impl From for MetadataVersioned { fn from(ink_project: InkProject) -> Self { - MetadataVersioned::V2(ink_project) + MetadataVersioned::V3(ink_project) } } diff --git a/crates/metadata/src/specs.rs b/crates/metadata/src/specs.rs index c56e034694c..437916cd56e 100644 --- a/crates/metadata/src/specs.rs +++ b/crates/metadata/src/specs.rs @@ -227,6 +227,8 @@ pub struct ConstructorSpec { pub label: F::String, /// The selector hash of the message. pub selector: Selector, + /// If the constructor accepts any `value` from the caller. + pub payable: bool, /// The parameters of the deployment handler. pub args: Vec>, /// The deployment handler documentation. @@ -240,6 +242,7 @@ impl IntoPortable for ConstructorSpec { ConstructorSpec { label: self.label.into_portable(registry), selector: self.selector, + payable: self.payable, args: self .args .into_iter() @@ -266,6 +269,11 @@ where &self.selector } + /// Returns if the constructor is payable by the caller. + pub fn payable(&self) -> &bool { + &self.payable + } + /// Returns the parameters of the deployment handler. pub fn args(&self) -> &[MessageParamSpec] { &self.args @@ -285,20 +293,21 @@ where /// compile-time instead of at run-time. This is useful to better /// debug code-gen macros. #[must_use] -pub struct ConstructorSpecBuilder { +pub struct ConstructorSpecBuilder { spec: ConstructorSpec, - marker: PhantomData Selector>, + marker: PhantomData (Selector, IsPayable)>, } impl ConstructorSpec { /// Creates a new constructor spec builder. pub fn from_label( label: &'static str, - ) -> ConstructorSpecBuilder> { + ) -> ConstructorSpecBuilder, Missing> { ConstructorSpecBuilder { spec: Self { label, selector: Selector::default(), + payable: Default::default(), args: Vec::new(), docs: Vec::new(), }, @@ -307,9 +316,12 @@ impl ConstructorSpec { } } -impl ConstructorSpecBuilder> { +impl

ConstructorSpecBuilder, P> { /// Sets the function selector of the message. - pub fn selector(self, selector: [u8; 4]) -> ConstructorSpecBuilder { + pub fn selector( + self, + selector: [u8; 4], + ) -> ConstructorSpecBuilder { ConstructorSpecBuilder { spec: ConstructorSpec { selector: selector.into(), @@ -320,7 +332,23 @@ impl ConstructorSpecBuilder> { } } -impl ConstructorSpecBuilder { +impl ConstructorSpecBuilder> { + /// Sets if the constructor is payable, thus accepting value for the caller. + pub fn payable( + self, + is_payable: bool, + ) -> ConstructorSpecBuilder { + ConstructorSpecBuilder { + spec: ConstructorSpec { + payable: is_payable, + ..self.spec + }, + marker: PhantomData, + } + } +} + +impl ConstructorSpecBuilder { /// Sets the input arguments of the message specification. pub fn args(self, args: A) -> Self where @@ -344,7 +372,7 @@ impl ConstructorSpecBuilder { } } -impl ConstructorSpecBuilder { +impl ConstructorSpecBuilder { /// Finishes construction of the constructor. pub fn done(self) -> ConstructorSpec { self.spec @@ -368,7 +396,7 @@ pub struct MessageSpec { selector: Selector, /// If the message is allowed to mutate the contract state. mutates: bool, - /// If the message is payable by the caller. + /// If the message accepts any `value` from the caller. payable: bool, /// The parameters of the message. args: Vec>, @@ -508,7 +536,7 @@ impl MessageSpecBuilder, P, R> { } impl MessageSpecBuilder, R> { - /// Sets if the message is mutable, thus taking `&mut self` or not thus taking `&self`. + /// Sets if the message is payable, thus accepting value for the caller. pub fn payable( self, is_payable: bool, diff --git a/crates/metadata/src/tests.rs b/crates/metadata/src/tests.rs index d7451680a43..44d5d8492de 100644 --- a/crates/metadata/src/tests.rs +++ b/crates/metadata/src/tests.rs @@ -26,6 +26,7 @@ fn spec_constructor_selector_must_serialize_to_hex() { let label = "foo"; let cs = ConstructorSpec::from_label(label) .selector(123_456_789u32.to_be_bytes()) + .payable(true) .done(); let mut registry = Registry::new(); let portable_spec = cs.into_portable(&mut registry); @@ -40,6 +41,7 @@ fn spec_constructor_selector_must_serialize_to_hex() { json, json!({ "label": "foo", + "payable": true, "selector": "0x075bcd15", "args": [], "docs": [] @@ -55,6 +57,7 @@ fn spec_contract_json() { .constructors(vec![ ConstructorSpec::from_label("new") .selector([94u8, 189u8, 136u8, 214u8]) + .payable(true) .args(vec![MessageParamSpec::new("init_value") .of_type(TypeSpec::with_name_segs::( vec!["i32"].into_iter().map(AsRef::as_ref), @@ -64,6 +67,7 @@ fn spec_contract_json() { .done(), ConstructorSpec::from_label("default") .selector([2u8, 34u8, 255u8, 24u8]) + .payable(Default::default()) .args(Vec::new()) .docs(Vec::new()) .done(), @@ -120,12 +124,14 @@ fn spec_contract_json() { ], "docs": [], "label": "new", + "payable": true, "selector": "0x5ebd88d6" }, { "args": [], "docs": [], "label": "default", + "payable": false, "selector": "0x0222ff18" } ], @@ -177,6 +183,7 @@ fn trim_docs() { let cs = ConstructorSpec::from_label(label) .selector(123_456_789u32.to_be_bytes()) .docs(vec![" foobar "]) + .payable(Default::default()) .done(); let mut registry = Registry::new(); let compact_spec = cs.into_portable(&mut registry); @@ -191,6 +198,7 @@ fn trim_docs() { json, json!({ "label": "foo", + "payable": false, "selector": "0x075bcd15", "args": [], "docs": ["foobar"]