Unverified Commit c9a97bbe authored by Robin Freyler's avatar Robin Freyler Committed by GitHub
Browse files

Make #[ink(selector = ..)] take a u32 parameter instead of a string (#928)

* make #[ink(selector = ..)] take an integer instead of a string

Also warn about deprecation if a user still uses the old string parameter.

* update tests for new selector int parameter

* update contract examples for new selector int parameter

* remove unused regex dependency from ink_lang_ir

Also remove unnecessary regex dependency from ink_lang_codegen

* update README for new selector int parameter

Also update namespace parameter description.

* update preliminary release notes

* update spellcheck dict
parent 4155ebe2
Pipeline #158157 passed with stages
in 30 minutes and 7 seconds
90 100
ABI ABI
AST AST
...@@ -91,3 +91,4 @@ runtime/S ...@@ -91,3 +91,4 @@ runtime/S
struct/S struct/S
vec/S vec/S
vector/S vector/S
wildcard/S
...@@ -220,8 +220,8 @@ In a module annotated with `#[ink::contract]` these attributes are available: ...@@ -220,8 +220,8 @@ In a module annotated with `#[ink::contract]` these attributes are available:
| `#[ink(message)]` | Applicable to methods. | Flags a method for the ink! storage struct as message making it available to the API for calling the contract. | | `#[ink(message)]` | Applicable to methods. | Flags a method for the ink! storage struct as message making it available to the API for calling the contract. |
| `#[ink(constructor)]` | Applicable to method. | Flags a method for the ink! storage struct as constructor making it available to the API for instantiating the contract. | | `#[ink(constructor)]` | Applicable to method. | Flags a method for the ink! storage struct as constructor making it available to the API for instantiating the contract. |
| `#[ink(payable)]` | Applicable to ink! messages. | Allows receiving value as part of the call of the ink! message. ink! constructors are implicitly payable. | | `#[ink(payable)]` | Applicable to ink! messages. | Allows receiving value as part of the call of the ink! message. ink! constructors are implicitly payable. |
| `#[ink(selector = "..")]` | Applicable to ink! messages and ink! constructors. | Specifies a concrete dispatch selector for the flagged entity. This allows a contract author to precisely control the selectors of their APIs making it possible to rename their API without breakage. | | `#[ink(selector = S:u32)]` | Applicable to ink! messages and ink! constructors. | Specifies a concrete dispatch selector for the flagged entity. This allows a contract author to precisely control the selectors of their APIs making it possible to rename their API without breakage. |
| `#[ink(namespace = "..")]` | Applicable to ink! trait implementation blocks. | Changes the resulting selectors of all the ink! messages and ink! constructors within the trait implementation. Allows to disambiguate between trait implementations with overlapping message or constructor names. Use only with great care and consideration! | | `#[ink(namespace = N:string)]` | Applicable to ink! trait implementation blocks. | Changes the resulting selectors of all the ink! messages and ink! constructors within the trait implementation. Allows to disambiguate between trait implementations with overlapping message or constructor names. Use only with great care and consideration! |
| `#[ink(impl)]` | Applicable to ink! implementation blocks. | Tells the ink! codegen that some implementation block shall be granted access to ink! internals even without it containing any ink! messages or ink! constructors. | | `#[ink(impl)]` | Applicable to ink! implementation blocks. | Tells the ink! codegen that some implementation block shall be granted access to ink! internals even without it containing any ink! messages or ink! constructors. |
See [here](https://paritytech.github.io/ink/ink_lang/attr.contract.html) for a more detailed description of those and also for details on the `#[ink::contract]` macro. See [here](https://paritytech.github.io/ink/ink_lang/attr.contract.html) for a more detailed description of those and also for details on the `#[ink::contract]` macro.
......
# Version 3.0-rc6 (UNRELEASED)
This is the 6th release candidate for ink! 3.0.
## Changed
- Message and constructor selectors no longer take their inputs as string but as `u32` decodable integer. For example:
- It is no longer possible to specify a selector as `#[ink(selector = "0xC0DECAFE")]`.
- The newly allowed formats are `#[ink(selector = 0xC0DECAFE)]` and `#[ink(selector = 42)]`.
- Smart contract authors are required to update their smart contracts for this change.
# Version 3.0-rc5 (2021-09-08) # Version 3.0-rc5 (2021-09-08)
This is the 5th release candidate for ink! 3.0. This is the 5th release candidate for ink! 3.0.
......
...@@ -25,7 +25,6 @@ proc-macro2 = "1.0" ...@@ -25,7 +25,6 @@ proc-macro2 = "1.0"
derive_more = { version = "0.99", default-features = false, features = ["from"] } derive_more = { version = "0.99", default-features = false, features = ["from"] }
itertools = "0.10" itertools = "0.10"
either = { version = "1.5", default-features = false } either = { version = "1.5", default-features = false }
regex = "1.3"
blake2 = "0.9" blake2 = "0.9"
heck = "0.3.1" heck = "0.3.1"
scale = { package = "parity-scale-codec", version = "2.1", default-features = false, features = ["derive", "full"] } scale = { package = "parity-scale-codec", version = "2.1", default-features = false, features = ["derive", "full"] }
......
...@@ -23,7 +23,6 @@ syn = { version = "1.0", features = ["parsing", "full", "visit", "extra-traits"] ...@@ -23,7 +23,6 @@ syn = { version = "1.0", features = ["parsing", "full", "visit", "extra-traits"]
proc-macro2 = "1.0" proc-macro2 = "1.0"
itertools = { version = "0.10", default-features = false } itertools = { version = "0.10", default-features = false }
either = { version = "1.5", default-features = false } either = { version = "1.5", default-features = false }
regex = "1.3"
blake2 = "0.9" blake2 = "0.9"
[features] [features]
......
...@@ -28,7 +28,6 @@ use proc_macro2::{ ...@@ -28,7 +28,6 @@ use proc_macro2::{
Ident, Ident,
Span, Span,
}; };
use regex::Regex;
use std::collections::HashMap; use std::collections::HashMap;
use syn::spanned::Spanned; use syn::spanned::Spanned;
...@@ -98,12 +97,12 @@ impl Attrs for syn::Item { ...@@ -98,12 +97,12 @@ impl Attrs for syn::Item {
/// ///
/// An attribute with a parameterized flag: /// An attribute with a parameterized flag:
/// ```no_compile /// ```no_compile
/// #[ink(selector = "0xDEADBEEF")] /// #[ink(selector = 0xDEADBEEF)]
/// ``` /// ```
/// ///
/// An attribute with multiple flags: /// An attribute with multiple flags:
/// ```no_compile /// ```no_compile
/// #[ink(message, payable, selector = "0xDEADBEEF")] /// #[ink(message, payable, selector = 0xDEADBEEF)]
/// ``` /// ```
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InkAttribute { pub struct InkAttribute {
...@@ -314,7 +313,7 @@ pub enum AttributeArgKind { ...@@ -314,7 +313,7 @@ pub enum AttributeArgKind {
Constructor, Constructor,
/// `#[ink(payable)]` /// `#[ink(payable)]`
Payable, Payable,
/// `#[ink(selector = "0xDEADBEEF")]` /// `#[ink(selector = 0xDEADBEEF)]`
Selector, Selector,
/// `#[ink(extension = N: u32)]` /// `#[ink(extension = N: u32)]`
Extension, Extension,
...@@ -367,7 +366,7 @@ pub enum AttributeArg { ...@@ -367,7 +366,7 @@ pub enum AttributeArg {
/// Applied on ink! constructors or messages in order to specify that they /// Applied on ink! constructors or messages in order to specify that they
/// can receive funds from callers. /// can receive funds from callers.
Payable, Payable,
/// `#[ink(selector = "0xDEADBEEF")]` /// `#[ink(selector = 0xDEADBEEF)]`
/// ///
/// Applied on ink! constructors or messages to manually control their /// Applied on ink! constructors or messages to manually control their
/// selectors. /// selectors.
...@@ -732,19 +731,6 @@ impl InkAttribute { ...@@ -732,19 +731,6 @@ impl InkAttribute {
} }
} }
/// Returns an error to notify about non-hex digits at a position.
fn err_non_hex(meta: &syn::Meta, pos: usize) -> syn::Error {
format_err_spanned!(meta, "encountered non-hex digit at position {}", pos)
}
/// Returns an error to notify about an invalid ink! selector.
fn invalid_selector_err_regex(meta: &syn::Meta) -> syn::Error {
format_err_spanned!(
meta,
"invalid selector - a selector must consist of four bytes in hex (e.g. `selector = \"0xCAFEBABE\"`)"
)
}
impl TryFrom<syn::NestedMeta> for AttributeFrag { impl TryFrom<syn::NestedMeta> for AttributeFrag {
type Error = syn::Error; type Error = syn::Error;
...@@ -754,46 +740,28 @@ impl TryFrom<syn::NestedMeta> for AttributeFrag { ...@@ -754,46 +740,28 @@ impl TryFrom<syn::NestedMeta> for AttributeFrag {
match &meta { match &meta {
syn::Meta::NameValue(name_value) => { syn::Meta::NameValue(name_value) => {
if name_value.path.is_ident("selector") { if name_value.path.is_ident("selector") {
if let syn::Lit::Str(lit_str) = &name_value.lit { if let syn::Lit::Int(lit_int) = &name_value.lit {
let regex = Regex::new(r"0x([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})([\da-fA-F]{2})") let selector_u32 = lit_int.base10_parse::<u32>()
.map_err(|_| { .map_err(|error| {
invalid_selector_err_regex(&meta) format_err_spanned!(
})?; lit_int,
let str = lit_str.value(); "selector value out of range. selector must be a valid `u32` integer: {}",
let cap = error
regex.captures(&str).ok_or_else(|| { )
invalid_selector_err_regex(&meta)
})?; })?;
if !regex.is_match(&str) { let selector = Selector::from_bytes(selector_u32.to_be_bytes());
return Err(invalid_selector_err_regex( return Ok(AttributeFrag {
&meta, ast: meta,
)) arg: AttributeArg::Selector(selector),
})
} }
let len_digits = (str.as_bytes().len() - 2) / 2; if let syn::Lit::Str(_) = &name_value.lit {
if len_digits != 4 {
return Err(format_err!( return Err(format_err!(
name_value, name_value,
"expected 4-digit hexcode for `selector` argument, found {} digits", "#[ink(selector = ..)] attributes with string inputs are deprecated. \
len_digits, use an integer instead, e.g. #[ink(selector = 1)] or #[ink(selector = 0xC0DECAFE)]."
)) ))
} }
let selector_bytes = [
u8::from_str_radix(&cap[1], 16)
.map_err(|_| err_non_hex(&meta, 0))?,
u8::from_str_radix(&cap[2], 16)
.map_err(|_| err_non_hex(&meta, 1))?,
u8::from_str_radix(&cap[3], 16)
.map_err(|_| err_non_hex(&meta, 2))?,
u8::from_str_radix(&cap[4], 16)
.map_err(|_| err_non_hex(&meta, 3))?,
];
return Ok(AttributeFrag {
ast: meta,
arg: AttributeArg::Selector(Selector::from_bytes(
selector_bytes,
)),
})
}
return Err(format_err!(name_value, "expecteded 4-digit hexcode for `selector` argument, e.g. #[ink(selector = 0xC0FEBABE]")) return Err(format_err!(name_value, "expecteded 4-digit hexcode for `selector` argument, e.g. #[ink(selector = 0xC0FEBABE]"))
} }
if name_value.path.is_ident("namespace") { if name_value.path.is_ident("namespace") {
...@@ -1066,7 +1034,7 @@ mod tests { ...@@ -1066,7 +1034,7 @@ mod tests {
fn selector_works() { fn selector_works() {
assert_attribute_try_from( assert_attribute_try_from(
syn::parse_quote! { syn::parse_quote! {
#[ink(selector = "0xDEADBEEF")] #[ink(selector = 0xDEADBEEF)]
}, },
Ok(test::Attribute::Ink(vec![AttributeArg::Selector( Ok(test::Attribute::Ink(vec![AttributeArg::Selector(
Selector::from_bytes([0xDE, 0xAD, 0xBE, 0xEF]), Selector::from_bytes([0xDE, 0xAD, 0xBE, 0xEF]),
...@@ -1075,22 +1043,28 @@ mod tests { ...@@ -1075,22 +1043,28 @@ mod tests {
} }
#[test] #[test]
fn selector_non_hexcode() { fn selector_negative_number() {
assert_attribute_try_from( assert_attribute_try_from(
syn::parse_quote! { syn::parse_quote! {
#[ink(selector = "0xhelloworld")] #[ink(selector = -1)]
}, },
Err("invalid selector - a selector must consist of four bytes in hex (e.g. `selector = \"0xCAFEBABE\"`)"), Err(
"selector value out of range. selector must be a valid `u32` integer: \
invalid digit found in string",
),
); );
} }
#[test] #[test]
fn selector_too_long() { fn selector_out_of_range() {
assert_attribute_try_from( assert_attribute_try_from(
syn::parse_quote! { syn::parse_quote! {
#[ink(selector = "0xDEADBEEFC0FEBABE")] #[ink(selector = 0xFFFF_FFFF_FFFF_FFFF)]
}, },
Err("expected 4-digit hexcode for `selector` argument, found 8 digits"), Err(
"selector value out of range. \
selector must be a valid `u32` integer: number too large to fit in target type"
),
); );
} }
...@@ -1098,7 +1072,7 @@ mod tests { ...@@ -1098,7 +1072,7 @@ mod tests {
fn selector_invalid_type() { fn selector_invalid_type() {
assert_attribute_try_from( assert_attribute_try_from(
syn::parse_quote! { syn::parse_quote! {
#[ink(selector = 42)] #[ink(selector = true)]
}, },
Err("expecteded 4-digit hexcode for `selector` argument, e.g. #[ink(selector = 0xC0FEBABE]"), Err("expecteded 4-digit hexcode for `selector` argument, e.g. #[ink(selector = 0xC0FEBABE]"),
); );
......
...@@ -208,7 +208,7 @@ pub trait Callable { ...@@ -208,7 +208,7 @@ pub trait Callable {
/// ///
/// ```no_compile /// ```no_compile
/// impl MyStorage { /// impl MyStorage {
/// #[ink(message, selector = "0xDEADBEEF")] /// #[ink(message, selector = 0xDEADBEEF)]
/// fn my_message(&self) {} /// fn my_message(&self) {}
/// } /// }
/// ``` /// ```
...@@ -611,7 +611,7 @@ mod tests { ...@@ -611,7 +611,7 @@ mod tests {
impl MyTrait for MyStorage {} impl MyTrait for MyStorage {}
}, },
syn::parse_quote! { syn::parse_quote! {
#[ink(message, selector = "0xDEADBEEF")] #[ink(message, selector = 0xDEADBEEF)]
fn my_message(&self) {} fn my_message(&self) {}
}, },
[0xDE, 0xAD, 0xBE, 0xEF], [0xDE, 0xAD, 0xBE, 0xEF],
......
...@@ -405,7 +405,7 @@ mod tests { ...@@ -405,7 +405,7 @@ mod tests {
true, true,
syn::parse_quote! { syn::parse_quote! {
#[ink(message)] #[ink(message)]
#[ink(selector = "0xDEADBEEF", payable)] #[ink(selector = 0xDEADBEEF, payable)]
pub fn my_message(&self) {} pub fn my_message(&self) {}
}, },
), ),
......
...@@ -192,8 +192,8 @@ impl ItemMod { ...@@ -192,8 +192,8 @@ impl ItemMod {
format_err!( format_err!(
second_span, second_span,
"encountered ink! {}s with overlapping selectors (= {:02X?})\n\ "encountered ink! {}s with overlapping selectors (= {:02X?})\n\
hint: use #[ink(selector = \"0x...\")] on the callable or \ hint: use #[ink(selector = S:u32)] on the callable or \
#[ink(namespace = \"...\")] on the implementation block to \ #[ink(namespace = N:string)] on the implementation block to \
disambiguate overlapping selectors.", disambiguate overlapping selectors.",
kind, kind,
selector.as_bytes(), selector.as_bytes(),
...@@ -713,20 +713,19 @@ mod tests { ...@@ -713,20 +713,19 @@ mod tests {
#[ink(constructor)] #[ink(constructor)]
pub fn my_constructor() -> Self {} pub fn my_constructor() -> Self {}
#[ink(message, selector = "0xDEADBEEF")] #[ink(message, selector = 0xDEADBEEF)]
pub fn my_message_1(&self) {} pub fn my_message_1(&self) {}
} }
impl MyStorage { impl MyStorage {
#[ink(message, selector = "0xDEADBEEF")] #[ink(message, selector = 0xDEADBEEF)]
pub fn my_message_2(&self) {} pub fn my_message_2(&self) {}
} }
} }
}, },
"encountered ink! messages with overlapping selectors (= [DE, AD, BE, EF])\n\ "encountered ink! messages with overlapping selectors (= [DE, AD, BE, EF])\n\
hint: use #[ink(selector = \"0x...\")] on the callable or \ hint: use #[ink(selector = S:u32)] on the callable or #[ink(namespace = N:string)] \
#[ink(namespace = \"...\")] on the implementation block to \ on the implementation block to disambiguate overlapping selectors.",
disambiguate overlapping selectors.",
); );
} }
...@@ -739,7 +738,7 @@ mod tests { ...@@ -739,7 +738,7 @@ mod tests {
pub struct MyStorage {} pub struct MyStorage {}
impl MyStorage { impl MyStorage {
#[ink(constructor, selector = "0xDEADBEEF")] #[ink(constructor, selector = 0xDEADBEEF)]
pub fn my_constructor_1() -> Self {} pub fn my_constructor_1() -> Self {}
#[ink(message)] #[ink(message)]
...@@ -747,15 +746,14 @@ mod tests { ...@@ -747,15 +746,14 @@ mod tests {
} }
impl MyStorage { impl MyStorage {
#[ink(constructor, selector = "0xDEADBEEF")] #[ink(constructor, selector = 0xDEADBEEF)]
pub fn my_constructor_2() -> Self {} pub fn my_constructor_2() -> Self {}
} }
} }
}, },
"encountered ink! constructors with overlapping selectors (= [DE, AD, BE, EF])\n\ "encountered ink! constructors with overlapping selectors (= [DE, AD, BE, EF])\n\
hint: use #[ink(selector = \"0x...\")] on the callable or \ hint: use #[ink(selector = S:u32)] on the callable or #[ink(namespace = N:string)] \
#[ink(namespace = \"...\")] on the implementation block to \ on the implementation block to disambiguate overlapping selectors.",
disambiguate overlapping selectors.",
); );
} }
...@@ -782,9 +780,8 @@ mod tests { ...@@ -782,9 +780,8 @@ mod tests {
} }
}, },
"encountered ink! messages with overlapping selectors (= [04, C4, 94, 46])\n\ "encountered ink! messages with overlapping selectors (= [04, C4, 94, 46])\n\
hint: use #[ink(selector = \"0x...\")] on the callable or \ hint: use #[ink(selector = S:u32)] on the callable or #[ink(namespace = N:string)] \
#[ink(namespace = \"...\")] on the implementation block to \ on the implementation block to disambiguate overlapping selectors.",
disambiguate overlapping selectors.",
); );
} }
...@@ -824,10 +821,10 @@ mod tests { ...@@ -824,10 +821,10 @@ mod tests {
pub struct MyStorage {} pub struct MyStorage {}
impl MyStorage { impl MyStorage {
#[ink(constructor, selector = "0xDEADBEEF")] #[ink(constructor, selector = 0xDEADBEEF)]
pub fn my_constructor() -> Self {} pub fn my_constructor() -> Self {}
#[ink(message, selector = "0xDEADBEEF")] #[ink(message, selector = 0xDEADBEEF)]
pub fn my_message(&self) {} pub fn my_message(&self) {}
} }
} }
......
...@@ -356,20 +356,20 @@ use proc_macro::TokenStream; ...@@ -356,20 +356,20 @@ use proc_macro::TokenStream;
/// # } /// # }
/// impl Flipper { /// impl Flipper {
/// #[ink(constructor)] /// #[ink(constructor)]
/// #[ink(selector = "0xDEADBEEF")] // Works on constructors as well. /// #[ink(selector = 0xDEADBEEF)] // Works on constructors as well.
/// pub fn new(initial_value: bool) -> Self { /// pub fn new(initial_value: bool) -> Self {
/// Flipper { value: false } /// Flipper { value: false }
/// } /// }
/// ///
/// # /// Flips the current value. /// # /// Flips the current value.
/// # #[ink(message)] /// # #[ink(message)]
/// # #[ink(selector = "0xCAFEBABE")] // You can either specify selector out-of-line. /// # #[ink(selector = 0xCAFEBABE)] // You can either specify selector out-of-line.
/// # pub fn flip(&mut self) { /// # pub fn flip(&mut self) {
/// # self.value = !self.value; /// # self.value = !self.value;
/// # } /// # }
/// # /// #
/// /// Returns the current value. /// /// Returns the current value.
/// #[ink(message, selector = "0xFEEDBEEF")] // ... or specify selector inline. /// #[ink(message, selector = 0xFEEDBEEF)] // ... or specify selector inline.
/// pub fn get(&self) -> bool { /// pub fn get(&self) -> bool {
/// self.value /// self.value
/// } /// }
......
...@@ -50,6 +50,7 @@ fn compile_tests() { ...@@ -50,6 +50,7 @@ fn compile_tests() {
t.compile_fail("tests/ui/fail/M-03-message-returns-self.rs"); t.compile_fail("tests/ui/fail/M-03-message-returns-self.rs");
t.compile_fail("tests/ui/fail/M-04-message-returns-non-codec.rs"); t.compile_fail("tests/ui/fail/M-04-message-returns-non-codec.rs");
t.compile_fail("tests/ui/fail/M-05-message-invalid-selector.rs"); t.compile_fail("tests/ui/fail/M-05-message-invalid-selector.rs");
t.compile_fail("tests/ui/fail/M-06-message-invalid-selector-type.rs");
t.compile_fail("tests/ui/fail/M-10-method-unknown-ink-marker.rs"); t.compile_fail("tests/ui/fail/M-10-method-unknown-ink-marker.rs");
t.compile_fail("tests/ui/fail/S-01-missing-storage-struct.rs"); t.compile_fail("tests/ui/fail/S-01-missing-storage-struct.rs");
......
...@@ -11,7 +11,7 @@ mod message_invalid_selector { ...@@ -11,7 +11,7 @@ mod message_invalid_selector {
Self {} Self {}
} }
#[ink(message, selector = "0x00")] #[ink(message, selector = "0xC0DECAFE")]
pub fn invalid_selector(&self) {} pub fn invalid_selector(&self) {}
} }
} }
......
error: invalid selector - a selector must consist of four bytes in hex (e.g. `selector = "0xCAFEBABE"`) error: #[ink(selector = ..)] attributes with string inputs are deprecated. use an integer instead, e.g. #[ink(selector = 1)] or #[ink(selector = 0xC0DECAFE)].
--> $DIR/M-05-message-invalid-selector.rs:14:24 --> $DIR/M-05-message-invalid-selector.rs:14:24
| |
14 | #[ink(message, selector = "0x00")] 14 | #[ink(message, selector = "0xC0DECAFE")]
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^
use ink_lang as ink;
#[ink::contract]
mod message_invalid_selector {
#[ink(storage)]
pub struct MessageInvalidSelector {}
impl MessageInvalidSelector {
#[ink(constructor)]
pub fn constructor() -> Self {
Self {}
}
#[ink(message, selector = true)]
pub fn invalid_selector(&self) {}
}
}
fn main() {}
error: expecteded 4-digit hexcode for `selector` argument, e.g. #[ink(selector = 0xC0FEBABE]
--> $DIR/M-06-message-invalid-selector-type.rs:14:24
|
14 | #[ink(message, selector = true)]
| ^^^^^^^^^^^^^^^
...@@ -69,7 +69,7 @@ pub mod give_me { ...@@ -69,7 +69,7 @@ pub mod give_me {
/// ///
/// The method needs to be annotated with `payable`; only then it is /// The method needs to be annotated with `payable`; only then it is
/// allowed to receive value as part of the call. /// allowed to receive value as part of the call.
#[ink(message, payable, selector = "0xCAFEBABE")] #[ink(message, payable, selector = 0xCAFEBABE)]
pub fn was_it_ten(&self) { pub fn was_it_ten(&self) {
ink_env::debug_println!( ink_env::debug_println!(
"received payment: {}", "received payment: {}",
......
...@@ -562,7 +562,7 @@ mod erc1155 { ...@@ -562,7 +562,7 @@ mod erc1155 {
} }
impl super::Erc1155TokenReceiver for Contract { impl super::Erc1155TokenReceiver for Contract {
#[ink(message, selector = "0xF23A6E61")] #[ink(message, selector = 0xF23A6E61)]
fn on_received( fn on_received(
&mut self, &mut self,