git.delta.rocks / unique-network / refs/commits / be088e7492dc

difftreelog

refactor reuse code generation patterns

Yaroslav Bolyukin2022-12-22parent: #81e4f2e.patch.diff
in: master

22 files changed

modifiedcrates/evm-coder/procedural/src/abi_derive/derive_enum.rsdiffbeforeafterboth
--- a/crates/evm-coder/procedural/src/abi_derive/derive_enum.rs
+++ b/crates/evm-coder/procedural/src/abi_derive/derive_enum.rs
@@ -1,20 +1,52 @@
 use quote::quote;
 
+use super::extract_docs;
+
 pub fn impl_solidity_option<'a>(
+	docs: Vec<String>,
 	name: &proc_macro2::Ident,
-	enum_options: impl Iterator<Item = &'a syn::Ident>,
+	enum_options: impl Iterator<Item = &'a syn::Variant> + Clone,
 ) -> proc_macro2::TokenStream {
-	let enum_options = enum_options.map(|opt| {
+	let variant_names = enum_options.clone().map(|opt| {
+		let opt = &opt.ident;
 		let s = name.to_string() + "." + opt.to_string().as_str();
 		let as_string = proc_macro2::Literal::string(s.as_str());
 		quote!(#name::#opt => #as_string,)
 	});
+	let solidity_name = name.to_string();
+
+	let solidity_fields = enum_options.map(|v| {
+		let docs = extract_docs(&v.attrs).expect("TODO: handle bad docs");
+		let name = v.ident.to_string();
+		quote! {
+			SolidityEnumVariant {
+				docs: &[#(#docs),*],
+				name: #name,
+			}
+		}
+	});
+
 	quote!(
 		#[cfg(feature = "stubgen")]
-		impl ::evm_coder::solidity::SolidityEnum for #name {
+		impl ::evm_coder::solidity::SolidityEnumTy for #name {
+			fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector) -> String {
+				use evm_coder::solidity::*;
+				use core::fmt::Write;
+				let interface = SolidityEnum {
+					docs: &[#(#docs),*],
+					name: #solidity_name,
+					fields: &[#(
+						#solidity_fields,
+					)*],
+				};
+				let mut out = String::new();
+				let _ = interface.format(&mut out, tc);
+				tc.collect(out);
+				#solidity_name.to_string()
+			}
 			fn solidity_option(&self) -> &str {
 				match self {
-					#(#enum_options)*
+					#(#variant_names)*
 				}
 			}
 		}
@@ -23,11 +55,12 @@
 
 pub fn impl_enum_from_u8<'a>(
 	name: &proc_macro2::Ident,
-	enum_options: impl Iterator<Item = &'a syn::Ident>,
+	enum_options: impl Iterator<Item = &'a syn::Variant>,
 ) -> proc_macro2::TokenStream {
 	let error_str = format!("Value not convertible into enum \"{name}\"");
 	let error_str = proc_macro2::Literal::string(&error_str);
 	let enum_options = enum_options.enumerate().map(|(i, opt)| {
+		let opt = &opt.ident;
 		let n = proc_macro2::Literal::u8_suffixed(i as u8);
 		quote! {#n => Ok(#name::#opt),}
 	});
@@ -83,21 +116,6 @@
 			}
 		}
 	)
-}
-
-pub fn impl_enum_solidity_type<'a>(name: &syn::Ident) -> proc_macro2::TokenStream {
-	quote! {
-		#[cfg(feature = "stubgen")]
-		impl ::evm_coder::solidity::SolidityType for #name {
-			fn names(tc: &::evm_coder::solidity::TypeCollector) -> Vec<String> {
-				Vec::new()
-			}
-
-			fn len() -> usize {
-				1
-			}
-		}
-	}
 }
 
 pub fn impl_enum_solidity_type_name(name: &syn::Ident) -> proc_macro2::TokenStream {
@@ -108,7 +126,7 @@
 				writer: &mut impl ::core::fmt::Write,
 				tc: &::evm_coder::solidity::TypeCollector,
 			) -> ::core::fmt::Result {
-				write!(writer, "{}", tc.collect_struct::<Self>())
+				write!(writer, "{}", tc.collect_enum::<Self>())
 			}
 
 			fn is_simple() -> bool {
@@ -119,49 +137,7 @@
 				writer: &mut impl ::core::fmt::Write,
 				tc: &::evm_coder::solidity::TypeCollector,
 			) -> ::core::fmt::Result {
-				write!(writer, "{}", <#name as ::evm_coder::solidity::SolidityEnum>::solidity_option(&<#name>::default()))
-			}
-		}
-	)
-}
-
-pub fn impl_enum_solidity_struct_collect<'a>(
-	name: &syn::Ident,
-	enum_options: impl Iterator<Item = &'a syn::Ident>,
-	option_count: usize,
-	enum_options_docs: impl Iterator<Item = syn::Result<Vec<proc_macro2::TokenStream>>>,
-	docs: &[proc_macro2::TokenStream],
-) -> proc_macro2::TokenStream {
-	let string_name = name.to_string();
-	let enum_options = enum_options
-		.zip(enum_options_docs)
-		.enumerate()
-		.map(|(i, (opt, doc))| {
-			let opt = proc_macro2::Literal::string(opt.to_string().as_str());
-			let doc = doc.expect("Doc parsing error");
-			let comma = if i != option_count - 1 { "," } else { "" };
-			quote! {
-				#(#doc)*
-				writeln!(str, "\t{}{}", #opt, #comma).expect("Enum format option");
-			}
-		});
-
-	quote!(
-		#[cfg(feature = "stubgen")]
-		impl ::evm_coder::solidity::StructCollect for #name {
-			fn name() -> String {
-				#string_name.into()
-			}
-
-			fn declaration() -> String {
-				use std::fmt::Write;
-
-				let mut str = String::new();
-				#(#docs)*
-				writeln!(str, "enum {} {{", <Self as ::evm_coder::solidity::StructCollect>::name()).unwrap();
-				#(#enum_options)*
-				writeln!(str, "}}").unwrap();
-				str
+				write!(writer, "{}", <#name as ::evm_coder::solidity::SolidityEnumTy>::solidity_option(&<#name>::default()))
 			}
 		}
 	)
modifiedcrates/evm-coder/procedural/src/abi_derive/derive_struct.rsdiffbeforeafterboth
--- a/crates/evm-coder/procedural/src/abi_derive/derive_struct.rs
+++ b/crates/evm-coder/procedural/src/abi_derive/derive_struct.rs
@@ -1,5 +1,6 @@
 use super::extract_docs;
 use quote::quote;
+use syn::Field;
 
 pub fn tuple_type<'a>(
 	field_types: impl Iterator<Item = &'a syn::Type> + Clone,
@@ -87,10 +88,6 @@
 	&field.ty
 }
 
-pub fn map_field_to_doc(field: &syn::Field) -> syn::Result<Vec<proc_macro2::TokenStream>> {
-	extract_docs(&field.attrs, true)
-}
-
 pub fn impl_can_be_placed_in_vec(ident: &syn::Ident) -> proc_macro2::TokenStream {
 	quote! {
 		impl ::evm_coder::sealed::CanBePlacedInVec for #ident {}
@@ -147,27 +144,44 @@
 
 pub fn impl_struct_solidity_type<'a>(
 	name: &syn::Ident,
-	field_types: impl Iterator<Item = &'a syn::Type> + Clone,
-	params_count: usize,
+	docs: Vec<String>,
+	fields: impl Iterator<Item = &'a Field> + Clone,
 ) -> proc_macro2::TokenStream {
-	let len = proc_macro2::Literal::usize_suffixed(params_count);
+	let solidity_name = name.to_string();
+	let solidity_fields = fields.enumerate().map(|(i, f)| {
+		let name = f
+			.ident
+			.as_ref()
+			.map(|i| i.to_string())
+			.unwrap_or_else(|| format!("field_{i}"));
+		let ty = &f.ty;
+		let docs = extract_docs(&f.attrs).expect("TODO: handle bad docs");
+		quote! {
+			SolidityStructField::<#ty> {
+				docs: &[#(#docs),*],
+				name: #name,
+				ty: ::core::marker::PhantomData,
+			}
+		}
+	});
 	quote! {
 		#[cfg(feature = "stubgen")]
-		impl ::evm_coder::solidity::SolidityType for #name {
-			fn names(tc: &::evm_coder::solidity::TypeCollector) -> Vec<String> {
-				let mut collected =
-					Vec::with_capacity(<Self as ::evm_coder::solidity::SolidityType>::len());
-				#({
-					let mut out = String::new();
-					<#field_types as ::evm_coder::solidity::SolidityTypeName>::solidity_name(&mut out, tc)
-						.expect("no fmt error");
-					collected.push(out);
-				})*
-				collected
-			}
-
-			fn len() -> usize {
-				#len
+		impl ::evm_coder::solidity::SolidityStructTy for #name {
+			/// Generate solidity definitions for methods described in this struct
+			fn generate_solidity_interface(tc: &evm_coder::solidity::TypeCollector) -> String {
+				use evm_coder::solidity::*;
+				use core::fmt::Write;
+				let interface = SolidityStruct {
+					docs: &[#(#docs),*],
+					name: #solidity_name,
+					fields: (#(
+						#solidity_fields,
+					)*),
+				};
+				let mut out = String::new();
+				let _ = interface.format(&mut out, tc);
+				tc.collect(out);
+				#solidity_name.to_string()
 			}
 		}
 	}
@@ -214,47 +228,4 @@
 			}
 		}
 	}
-}
-
-pub fn impl_struct_solidity_struct_collect<'a>(
-	name: &syn::Ident,
-	field_names: impl Iterator<Item = proc_macro2::Ident> + Clone,
-	field_types: impl Iterator<Item = &'a syn::Type> + Clone,
-	field_docs: impl Iterator<Item = syn::Result<Vec<proc_macro2::TokenStream>>> + Clone,
-	docs: &[proc_macro2::TokenStream],
-) -> syn::Result<proc_macro2::TokenStream> {
-	let string_name = name.to_string();
-	let name_type = field_names
-		.into_iter()
-		.zip(field_types)
-		.zip(field_docs)
-		.map(|((name, ty), doc)| {
-			let field_docs = doc.expect("Doc parse error");
-			let name = format!("{}", name);
-			quote!(
-				#(#field_docs)*
-				write!(str, "\t{} ", <#ty as ::evm_coder::solidity::StructCollect>::name()).unwrap();
-				writeln!(str, "{};", #name).unwrap();
-			)
-		});
-
-	Ok(quote! {
-		#[cfg(feature = "stubgen")]
-		impl ::evm_coder::solidity::StructCollect for #name {
-			fn name() -> String {
-				#string_name.into()
-			}
-
-			fn declaration() -> String {
-				use std::fmt::Write;
-
-				let mut str = String::new();
-				#(#docs)*
-				writeln!(str, "struct {} {{", Self::name()).unwrap();
-				#(#name_type)*
-				writeln!(str, "}}").unwrap();
-				str
-			}
-		}
-	})
 }
modifiedcrates/evm-coder/procedural/src/abi_derive/mod.rsdiffbeforeafterboth
--- a/crates/evm-coder/procedural/src/abi_derive/mod.rs
+++ b/crates/evm-coder/procedural/src/abi_derive/mod.rs
@@ -19,20 +19,18 @@
 	ast: &syn::DeriveInput,
 ) -> syn::Result<proc_macro2::TokenStream> {
 	let name = &ast.ident;
-	let docs = extract_docs(&ast.attrs, false)?;
-	let (is_named_fields, field_names, field_types, field_docs, params_count) = match ds.fields {
+	let docs = extract_docs(&ast.attrs)?;
+	let (is_named_fields, field_names, field_types, params_count) = match ds.fields {
 		syn::Fields::Named(ref fields) => Ok((
 			true,
 			fields.named.iter().enumerate().map(map_field_to_name),
 			fields.named.iter().map(map_field_to_type),
-			fields.named.iter().map(map_field_to_doc),
 			fields.named.len(),
 		)),
 		syn::Fields::Unnamed(ref fields) => Ok((
 			false,
 			fields.unnamed.iter().enumerate().map(map_field_to_name),
 			fields.unnamed.iter().map(map_field_to_type),
-			fields.unnamed.iter().map(map_field_to_doc),
 			fields.unnamed.len(),
 		)),
 		syn::Fields::Unit => Err(syn::Error::new(name.span(), "Unit structs not supported")),
@@ -52,11 +50,9 @@
 	let abi_type = impl_struct_abi_type(name, tuple_type.clone());
 	let abi_read = impl_struct_abi_read(name, tuple_type, tuple_names, struct_from_tuple);
 	let abi_write = impl_struct_abi_write(name, is_named_fields, tuple_ref_type, tuple_data);
-	let solidity_type = impl_struct_solidity_type(name, field_types.clone(), params_count);
+	let solidity_type = impl_struct_solidity_type(name, docs, ds.fields.iter());
 	let solidity_type_name =
 		impl_struct_solidity_type_name(name, field_types.clone(), params_count);
-	let solidity_struct_collect =
-		impl_struct_solidity_struct_collect(name, field_names, field_types, field_docs, &docs)?;
 
 	Ok(quote! {
 		#can_be_plcaed_in_vec
@@ -65,7 +61,6 @@
 		#abi_write
 		#solidity_type
 		#solidity_type_name
-		#solidity_struct_collect
 	})
 }
 
@@ -75,26 +70,16 @@
 ) -> syn::Result<proc_macro2::TokenStream> {
 	let name = &ast.ident;
 	check_repr_u8(name, &ast.attrs)?;
-	let docs = extract_docs(&ast.attrs, false)?;
-	let option_count = check_and_count_options(de)?;
-	let enum_options = de.variants.iter().map(|v| &v.ident);
-	let enum_options_docs = de.variants.iter().map(|v| extract_docs(&v.attrs, true));
+	let docs = extract_docs(&ast.attrs)?;
+	let enum_options = de.variants.iter();
 
 	let from = impl_enum_from_u8(name, enum_options.clone());
-	let solidity_option = impl_solidity_option(name, enum_options.clone());
+	let solidity_option = impl_solidity_option(docs, name, enum_options.clone());
 	let can_be_plcaed_in_vec = impl_can_be_placed_in_vec(name);
 	let abi_type = impl_enum_abi_type(name);
 	let abi_read = impl_enum_abi_read(name);
 	let abi_write = impl_enum_abi_write(name);
-	let solidity_type = impl_enum_solidity_type(name);
 	let solidity_type_name = impl_enum_solidity_type_name(name);
-	let solidity_struct_collect = impl_enum_solidity_struct_collect(
-		name,
-		enum_options,
-		option_count,
-		enum_options_docs,
-		&docs,
-	);
 
 	Ok(quote! {
 		#from
@@ -103,16 +88,11 @@
 		#abi_type
 		#abi_read
 		#abi_write
-		#solidity_type
 		#solidity_type_name
-		#solidity_struct_collect
 	})
 }
 
-fn extract_docs(
-	attrs: &[syn::Attribute],
-	is_field_doc: bool,
-) -> syn::Result<Vec<proc_macro2::TokenStream>> {
+fn extract_docs(attrs: &[syn::Attribute]) -> syn::Result<Vec<String>> {
 	attrs
 		.iter()
 		.filter_map(|attr| {
@@ -132,16 +112,6 @@
 				}
 			}
 			None
-		})
-		.enumerate()
-		.map(|(i, doc)| {
-			let doc = doc?;
-			let doc = doc.trim();
-			let dev = if i == 0 { " @dev" } else { "" };
-			let tab = if is_field_doc { "\t" } else { "" };
-			Ok(quote! {
-				writeln!(str, "{}///{} {}", #tab, #dev, #doc).unwrap();
-			})
 		})
 		.collect()
 }
modifiedcrates/evm-coder/src/solidity/impls.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/solidity/impls.rs
+++ b/crates/evm-coder/src/solidity/impls.rs
@@ -1,4 +1,4 @@
-use super::{TypeCollector, SolidityTypeName, SolidityType, StructCollect};
+use super::{TypeCollector, SolidityTypeName, SolidityTupleTy};
 use crate::{sealed, types::*};
 use core::fmt;
 use primitive_types::{U256, H160};
@@ -17,16 +17,6 @@
 					write!(writer, $default)
 				}
             }
-
-			impl StructCollect for $ty {
-				fn name() -> String {
-					$name.to_string()
-				}
-
-				fn declaration() -> String {
-					String::default()
-				}
-			}
         )*
     };
 }
@@ -71,17 +61,7 @@
 		write!(writer, "new ")?;
 		T::solidity_name(writer, tc)?;
 		write!(writer, "[](0)")
-	}
-}
-
-impl<T: StructCollect + sealed::CanBePlacedInVec> StructCollect for Vec<T> {
-	fn name() -> String {
-		<T as StructCollect>::name() + "[]"
 	}
-
-	fn declaration() -> String {
-		unimplemented!("Vectors have not declarations.")
-	}
 }
 
 macro_rules! count {
@@ -91,8 +71,8 @@
 
 macro_rules! impl_tuples {
 	($($ident:ident)+) => {
-		impl<$($ident: SolidityTypeName + 'static),+> SolidityType for ($($ident,)+) {
-			fn names(tc: &TypeCollector) -> Vec<string> {
+		impl<$($ident: SolidityTypeName + 'static),+> SolidityTupleTy for ($($ident,)+) {
+			fn fields(tc: &TypeCollector) -> Vec<string> {
 				let mut collected = Vec::with_capacity(Self::len());
 				$({
 					let mut out = string::new();
modifiedcrates/evm-coder/src/solidity/mod.rsdiffbeforeafterboth
before · crates/evm-coder/src/solidity/mod.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implementation detail of [`crate::solidity_interface`] macro code-generation.18//! You should not rely on any public item from this module, as it is only intended to be used19//! by procedural macro, API and output format may be changed at any time.20//!21//! Purpose of this module is to receive solidity contract definition in module-specified22//! format, and then output string, representing interface of this contract in solidity language2324mod traits;25pub use traits::*;26mod impls;2728#[cfg(not(feature = "std"))]29use alloc::{string::String, vec::Vec, collections::BTreeMap, format};30#[cfg(feature = "std")]31use std::collections::BTreeMap;32use core::{33	fmt::{self, Write},34	marker::PhantomData,35	cell::{Cell, RefCell},36	cmp::Reverse,37};38use impl_trait_for_tuples::impl_for_tuples;39use crate::{types::*, custom_signature::SignatureUnit};4041#[derive(Default)]42pub struct TypeCollector {43	/// Code => id44	/// id ordering is required to perform topo-sort on the resulting data45	structs: RefCell<BTreeMap<string, usize>>,46	anonymous: RefCell<BTreeMap<Vec<string>, usize>>,47	id: Cell<usize>,48}49impl TypeCollector {50	pub fn new() -> Self {51		Self::default()52	}53	pub fn collect(&self, item: string) {54		let id = self.next_id();55		self.structs.borrow_mut().insert(item, id);56	}57	pub fn next_id(&self) -> usize {58		let v = self.id.get();59		self.id.set(v + 1);60		v61	}62	pub fn collect_tuple<T: SolidityType>(&self) -> String {63		let names = T::names(self);64		if let Some(id) = self.anonymous.borrow().get(&names).cloned() {65			return format!("Tuple{}", id);66		}67		let id = self.next_id();68		let mut str = String::new();69		writeln!(str, "/// @dev anonymous struct").unwrap();70		writeln!(str, "struct Tuple{} {{", id).unwrap();71		for (i, name) in names.iter().enumerate() {72			writeln!(str, "\t{} field_{};", name, i).unwrap();73		}74		writeln!(str, "}}").unwrap();75		self.collect(str);76		self.anonymous.borrow_mut().insert(names, id);77		format!("Tuple{}", id)78	}79	pub fn collect_struct<T: StructCollect + SolidityType>(&self) -> String {80		let _names = T::names(self);81		self.collect(<T as StructCollect>::declaration());82		<T as StructCollect>::name()83	}84	pub fn finish(self) -> Vec<string> {85		let mut data = self.structs.into_inner().into_iter().collect::<Vec<_>>();86		data.sort_by_key(|(_, id)| Reverse(*id));87		data.into_iter().map(|(code, _)| code).collect()88	}89}90#[derive(Default)]91pub struct UnnamedArgument<T>(PhantomData<*const T>);9293impl<T: SolidityTypeName> SolidityArguments for UnnamedArgument<T> {94	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {95		if !T::is_void() {96			T::solidity_name(writer, tc)?;97			if !T::is_simple() {98				write!(writer, " memory")?;99			}100			Ok(())101		} else {102			Ok(())103		}104	}105	fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {106		Ok(())107	}108	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {109		T::solidity_default(writer, tc)110	}111	fn len(&self) -> usize {112		if T::is_void() {113			0114		} else {115			1116		}117	}118}119120pub struct NamedArgument<T>(&'static str, PhantomData<*const T>);121122impl<T> NamedArgument<T> {123	pub fn new(name: &'static str) -> Self {124		Self(name, Default::default())125	}126}127128impl<T: SolidityTypeName> SolidityArguments for NamedArgument<T> {129	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {130		if !T::is_void() {131			T::solidity_name(writer, tc)?;132			if !T::is_simple() {133				write!(writer, " memory")?;134			}135			write!(writer, " {}", self.0)136		} else {137			Ok(())138		}139	}140	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {141		writeln!(writer, "\t{prefix}\t{};", self.0)142	}143	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {144		T::solidity_default(writer, tc)145	}146	fn len(&self) -> usize {147		if T::is_void() {148			0149		} else {150			1151		}152	}153}154155pub struct SolidityEventArgument<T>(pub bool, &'static str, PhantomData<*const T>);156157impl<T> SolidityEventArgument<T> {158	pub fn new(indexed: bool, name: &'static str) -> Self {159		Self(indexed, name, Default::default())160	}161}162163impl<T: SolidityTypeName> SolidityArguments for SolidityEventArgument<T> {164	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {165		if !T::is_void() {166			T::solidity_name(writer, tc)?;167			if self.0 {168				write!(writer, " indexed")?;169			}170			write!(writer, " {}", self.1)171		} else {172			Ok(())173		}174	}175	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {176		writeln!(writer, "\t{prefix}\t{};", self.1)177	}178	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {179		T::solidity_default(writer, tc)180	}181	fn len(&self) -> usize {182		if T::is_void() {183			0184		} else {185			1186		}187	}188}189190impl SolidityArguments for () {191	fn solidity_name(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {192		Ok(())193	}194	fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {195		Ok(())196	}197	fn solidity_default(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {198		Ok(())199	}200	fn len(&self) -> usize {201		0202	}203}204205#[impl_for_tuples(1, 12)]206impl SolidityArguments for Tuple {207	for_tuples!( where #( Tuple: SolidityArguments ),* );208209	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {210		let mut first = true;211		for_tuples!( #(212            if !Tuple.is_empty() {213                if !first {214                    write!(writer, ", ")?;215                }216                first = false;217                Tuple.solidity_name(writer, tc)?;218            }219        )* );220		Ok(())221	}222	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {223		for_tuples!( #(224            Tuple.solidity_get(prefix, writer)?;225        )* );226		Ok(())227	}228	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {229		if self.is_empty() {230			Ok(())231		} else if self.len() == 1 {232			for_tuples!( #(233				Tuple.solidity_default(writer, tc)?;234			)* );235			Ok(())236		} else {237			write!(writer, "(")?;238			let mut first = true;239			for_tuples!( #(240				if !Tuple.is_empty() {241					if !first {242						write!(writer, ", ")?;243					}244					first = false;245					Tuple.solidity_default(writer, tc)?;246				}247			)* );248			write!(writer, ")")?;249			Ok(())250		}251	}252	fn len(&self) -> usize {253		for_tuples!( #( Tuple.len() )+* )254	}255}256257pub enum SolidityMutability {258	Pure,259	View,260	Mutable,261}262pub struct SolidityFunction<A, R> {263	pub docs: &'static [&'static str],264	pub selector: u32,265	pub hide: bool,266	pub custom_signature: SignatureUnit,267	pub name: &'static str,268	pub args: A,269	pub result: R,270	pub mutability: SolidityMutability,271	pub is_payable: bool,272}273impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {274	fn solidity_name(275		&self,276		is_impl: bool,277		writer: &mut impl fmt::Write,278		tc: &TypeCollector,279	) -> fmt::Result {280		let hide_comment = self.hide.then_some("// ").unwrap_or("");281		for doc in self.docs {282			writeln!(writer, "\t{hide_comment}///{}", doc)?;283		}284		writeln!(285			writer,286			"\t{hide_comment}/// @dev EVM selector for this function is: 0x{:0>8x},",287			self.selector288		)?;289		writeln!(290			writer,291			"\t{hide_comment}///  or in textual repr: {}",292			self.custom_signature.as_str().expect("bad utf-8")293		)?;294		write!(writer, "\t{hide_comment}function {}(", self.name)?;295		self.args.solidity_name(writer, tc)?;296		write!(writer, ")")?;297		if is_impl {298			write!(writer, " public")?;299		} else {300			write!(writer, " external")?;301		}302		match &self.mutability {303			SolidityMutability::Pure => write!(writer, " pure")?,304			SolidityMutability::View => write!(writer, " view")?,305			SolidityMutability::Mutable => {}306		}307		if self.is_payable {308			write!(writer, " payable")?;309		}310		if !self.result.is_empty() {311			write!(writer, " returns (")?;312			self.result.solidity_name(writer, tc)?;313			write!(writer, ")")?;314		}315		if is_impl {316			writeln!(writer, " {{")?;317			writeln!(writer, "\t{hide_comment}\trequire(false, stub_error);")?;318			self.args.solidity_get(hide_comment, writer)?;319			match &self.mutability {320				SolidityMutability::Pure => {}321				SolidityMutability::View => writeln!(writer, "\t{hide_comment}\tdummy;")?,322				SolidityMutability::Mutable => writeln!(writer, "\t{hide_comment}\tdummy = 0;")?,323			}324			if !self.result.is_empty() {325				write!(writer, "\t{hide_comment}\treturn ")?;326				self.result.solidity_default(writer, tc)?;327				writeln!(writer, ";")?;328			}329			writeln!(writer, "\t{hide_comment}}}")?;330		} else {331			writeln!(writer, ";")?;332		}333		if self.hide {334			writeln!(writer, "// FORMATTING: FORCE NEWLINE")?;335		}336		Ok(())337	}338}339340#[impl_for_tuples(0, 48)]341impl SolidityFunctions for Tuple {342	for_tuples!( where #( Tuple: SolidityFunctions ),* );343344	fn solidity_name(345		&self,346		is_impl: bool,347		writer: &mut impl fmt::Write,348		tc: &TypeCollector,349	) -> fmt::Result {350		let mut first = false;351		for_tuples!( #(352            Tuple.solidity_name(is_impl, writer, tc)?;353        )* );354		Ok(())355	}356}357358pub struct SolidityInterface<F: SolidityFunctions> {359	pub docs: &'static [&'static str],360	pub selector: bytes4,361	pub name: &'static str,362	pub is: &'static [&'static str],363	pub functions: F,364}365366impl<F: SolidityFunctions> SolidityInterface<F> {367	pub fn format(368		&self,369		is_impl: bool,370		out: &mut impl fmt::Write,371		tc: &TypeCollector,372	) -> fmt::Result {373		const ZERO_BYTES: [u8; 4] = [0; 4];374		for doc in self.docs {375			writeln!(out, "///{}", doc)?;376		}377		if self.selector != ZERO_BYTES {378			writeln!(379				out,380				"/// @dev the ERC-165 identifier for this interface is 0x{:0>8x}",381				u32::from_be_bytes(self.selector)382			)?;383		}384		if is_impl {385			write!(out, "contract ")?;386		} else {387			write!(out, "interface ")?;388		}389		write!(out, "{}", self.name)?;390		if !self.is.is_empty() {391			write!(out, " is")?;392			for (i, n) in self.is.iter().enumerate() {393				if i != 0 {394					write!(out, ",")?;395				}396				write!(out, " {}", n)?;397			}398		}399		writeln!(out, " {{")?;400		self.functions.solidity_name(is_impl, out, tc)?;401		writeln!(out, "}}")?;402		Ok(())403	}404}405406pub struct SolidityEvent<A> {407	pub name: &'static str,408	pub args: A,409}410411impl<A: SolidityArguments> SolidityFunctions for SolidityEvent<A> {412	fn solidity_name(413		&self,414		_is_impl: bool,415		writer: &mut impl fmt::Write,416		tc: &TypeCollector,417	) -> fmt::Result {418		write!(writer, "\tevent {}(", self.name)?;419		self.args.solidity_name(writer, tc)?;420		writeln!(writer, ");")421	}422}
after · crates/evm-coder/src/solidity/mod.rs
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617//! Implementation detail of [`crate::solidity_interface`] macro code-generation.18//! You should not rely on any public item from this module, as it is only intended to be used19//! by procedural macro, API and output format may be changed at any time.20//!21//! Purpose of this module is to receive solidity contract definition in module-specified22//! format, and then output string, representing interface of this contract in solidity language2324mod traits;25pub use traits::*;26mod impls;2728#[cfg(not(feature = "std"))]29use alloc::{string::String, vec::Vec, collections::BTreeMap, format};30#[cfg(feature = "std")]31use std::collections::BTreeMap;32use core::{33	fmt::{self, Write},34	marker::PhantomData,35	cell::{Cell, RefCell},36	cmp::Reverse,37};38use impl_trait_for_tuples::impl_for_tuples;39use crate::{types::*, custom_signature::SignatureUnit};4041#[derive(Default)]42pub struct TypeCollector {43	/// Code => id44	/// id ordering is required to perform topo-sort on the resulting data45	structs: RefCell<BTreeMap<string, usize>>,46	anonymous: RefCell<BTreeMap<Vec<string>, usize>>,47	// generic: RefCell<BTreeMap<string, usize>>,48	id: Cell<usize>,49}50impl TypeCollector {51	pub fn new() -> Self {52		Self::default()53	}54	pub fn collect(&self, item: string) {55		let id = self.next_id();56		self.structs.borrow_mut().insert(item, id);57	}58	pub fn next_id(&self) -> usize {59		let v = self.id.get();60		self.id.set(v + 1);61		v62	}63	/// Collect typle, deduplicating it by type, and returning generated name64	pub fn collect_tuple<T: SolidityTupleTy>(&self) -> String {65		let names = T::fields(self);66		if let Some(id) = self.anonymous.borrow().get(&names).cloned() {67			return format!("Tuple{}", id);68		}69		let id = self.next_id();70		let mut str = String::new();71		writeln!(str, "/// @dev anonymous struct").unwrap();72		writeln!(str, "struct Tuple{} {{", id).unwrap();73		for (i, name) in names.iter().enumerate() {74			writeln!(str, "\t{} field_{};", name, i).unwrap();75		}76		writeln!(str, "}}").unwrap();77		self.collect(str);78		self.anonymous.borrow_mut().insert(names, id);79		format!("Tuple{}", id)80	}81	pub fn collect_struct<T: SolidityStructTy>(&self) -> String {82		T::generate_solidity_interface(self)83	}84	pub fn collect_enum<T: SolidityEnumTy>(&self) -> String {85		T::generate_solidity_interface(self)86	}87	pub fn finish(self) -> Vec<string> {88		let mut data = self.structs.into_inner().into_iter().collect::<Vec<_>>();89		data.sort_by_key(|(_, id)| Reverse(*id));90		data.into_iter().map(|(code, _)| code).collect()91	}92}93#[derive(Default)]94pub struct UnnamedArgument<T>(PhantomData<*const T>);9596impl<T: SolidityTypeName> SolidityArguments for UnnamedArgument<T> {97	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {98		if !T::is_void() {99			T::solidity_name(writer, tc)?;100			if !T::is_simple() {101				write!(writer, " memory")?;102			}103			Ok(())104		} else {105			Ok(())106		}107	}108	fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {109		Ok(())110	}111	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {112		T::solidity_default(writer, tc)113	}114	fn len(&self) -> usize {115		if T::is_void() {116			0117		} else {118			1119		}120	}121}122123pub struct NamedArgument<T>(&'static str, PhantomData<*const T>);124125impl<T> NamedArgument<T> {126	pub fn new(name: &'static str) -> Self {127		Self(name, Default::default())128	}129}130131impl<T: SolidityTypeName> SolidityArguments for NamedArgument<T> {132	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {133		if !T::is_void() {134			T::solidity_name(writer, tc)?;135			if !T::is_simple() {136				write!(writer, " memory")?;137			}138			write!(writer, " {}", self.0)139		} else {140			Ok(())141		}142	}143	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {144		writeln!(writer, "\t{prefix}\t{};", self.0)145	}146	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {147		T::solidity_default(writer, tc)148	}149	fn len(&self) -> usize {150		if T::is_void() {151			0152		} else {153			1154		}155	}156}157158pub struct SolidityEventArgument<T>(pub bool, &'static str, PhantomData<*const T>);159160impl<T> SolidityEventArgument<T> {161	pub fn new(indexed: bool, name: &'static str) -> Self {162		Self(indexed, name, Default::default())163	}164}165166impl<T: SolidityTypeName> SolidityArguments for SolidityEventArgument<T> {167	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {168		if !T::is_void() {169			T::solidity_name(writer, tc)?;170			if self.0 {171				write!(writer, " indexed")?;172			}173			write!(writer, " {}", self.1)174		} else {175			Ok(())176		}177	}178	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {179		writeln!(writer, "\t{prefix}\t{};", self.1)180	}181	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {182		T::solidity_default(writer, tc)183	}184	fn len(&self) -> usize {185		if T::is_void() {186			0187		} else {188			1189		}190	}191}192193impl SolidityArguments for () {194	fn solidity_name(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {195		Ok(())196	}197	fn solidity_get(&self, _prefix: &str, _writer: &mut impl fmt::Write) -> fmt::Result {198		Ok(())199	}200	fn solidity_default(&self, _writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {201		Ok(())202	}203	fn len(&self) -> usize {204		0205	}206}207208#[impl_for_tuples(1, 12)]209impl SolidityArguments for Tuple {210	for_tuples!( where #( Tuple: SolidityArguments ),* );211212	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {213		let mut first = true;214		for_tuples!( #(215            if !Tuple.is_empty() {216                if !first {217                    write!(writer, ", ")?;218                }219                first = false;220                Tuple.solidity_name(writer, tc)?;221            }222        )* );223		Ok(())224	}225	fn solidity_get(&self, prefix: &str, writer: &mut impl fmt::Write) -> fmt::Result {226		for_tuples!( #(227            Tuple.solidity_get(prefix, writer)?;228        )* );229		Ok(())230	}231	fn solidity_default(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {232		if self.is_empty() {233			Ok(())234		} else if self.len() == 1 {235			for_tuples!( #(236				Tuple.solidity_default(writer, tc)?;237			)* );238			Ok(())239		} else {240			write!(writer, "(")?;241			let mut first = true;242			for_tuples!( #(243				if !Tuple.is_empty() {244					if !first {245						write!(writer, ", ")?;246					}247					first = false;248					Tuple.solidity_default(writer, tc)?;249				}250			)* );251			write!(writer, ")")?;252			Ok(())253		}254	}255	fn len(&self) -> usize {256		for_tuples!( #( Tuple.len() )+* )257	}258}259260pub enum SolidityMutability {261	Pure,262	View,263	Mutable,264}265pub struct SolidityFunction<A, R> {266	pub docs: &'static [&'static str],267	pub selector: u32,268	pub hide: bool,269	pub custom_signature: SignatureUnit,270	pub name: &'static str,271	pub args: A,272	pub result: R,273	pub mutability: SolidityMutability,274	pub is_payable: bool,275}276impl<A: SolidityArguments, R: SolidityArguments> SolidityFunctions for SolidityFunction<A, R> {277	fn solidity_name(278		&self,279		is_impl: bool,280		writer: &mut impl fmt::Write,281		tc: &TypeCollector,282	) -> fmt::Result {283		let hide_comment = self.hide.then_some("// ").unwrap_or("");284		for doc in self.docs {285			writeln!(writer, "\t{hide_comment}///{}", doc)?;286		}287		writeln!(288			writer,289			"\t{hide_comment}/// @dev EVM selector for this function is: 0x{:0>8x},",290			self.selector291		)?;292		writeln!(293			writer,294			"\t{hide_comment}///  or in textual repr: {}",295			self.custom_signature.as_str().expect("bad utf-8")296		)?;297		write!(writer, "\t{hide_comment}function {}(", self.name)?;298		self.args.solidity_name(writer, tc)?;299		write!(writer, ")")?;300		if is_impl {301			write!(writer, " public")?;302		} else {303			write!(writer, " external")?;304		}305		match &self.mutability {306			SolidityMutability::Pure => write!(writer, " pure")?,307			SolidityMutability::View => write!(writer, " view")?,308			SolidityMutability::Mutable => {}309		}310		if self.is_payable {311			write!(writer, " payable")?;312		}313		if !self.result.is_empty() {314			write!(writer, " returns (")?;315			self.result.solidity_name(writer, tc)?;316			write!(writer, ")")?;317		}318		if is_impl {319			writeln!(writer, " {{")?;320			writeln!(writer, "\t{hide_comment}\trequire(false, stub_error);")?;321			self.args.solidity_get(hide_comment, writer)?;322			match &self.mutability {323				SolidityMutability::Pure => {}324				SolidityMutability::View => writeln!(writer, "\t{hide_comment}\tdummy;")?,325				SolidityMutability::Mutable => writeln!(writer, "\t{hide_comment}\tdummy = 0;")?,326			}327			if !self.result.is_empty() {328				write!(writer, "\t{hide_comment}\treturn ")?;329				self.result.solidity_default(writer, tc)?;330				writeln!(writer, ";")?;331			}332			writeln!(writer, "\t{hide_comment}}}")?;333		} else {334			writeln!(writer, ";")?;335		}336		if self.hide {337			writeln!(writer, "// FORMATTING: FORCE NEWLINE")?;338		}339		Ok(())340	}341}342343#[impl_for_tuples(0, 48)]344impl SolidityFunctions for Tuple {345	for_tuples!( where #( Tuple: SolidityFunctions ),* );346347	fn solidity_name(348		&self,349		is_impl: bool,350		writer: &mut impl fmt::Write,351		tc: &TypeCollector,352	) -> fmt::Result {353		let mut first = false;354		for_tuples!( #(355            Tuple.solidity_name(is_impl, writer, tc)?;356        )* );357		Ok(())358	}359}360361pub struct SolidityInterface<F: SolidityFunctions> {362	pub docs: &'static [&'static str],363	pub selector: bytes4,364	pub name: &'static str,365	pub is: &'static [&'static str],366	pub functions: F,367}368369impl<F: SolidityFunctions> SolidityInterface<F> {370	pub fn format(371		&self,372		is_impl: bool,373		out: &mut impl fmt::Write,374		tc: &TypeCollector,375	) -> fmt::Result {376		const ZERO_BYTES: [u8; 4] = [0; 4];377		for doc in self.docs {378			writeln!(out, "///{}", doc)?;379		}380		if self.selector != ZERO_BYTES {381			writeln!(382				out,383				"/// @dev the ERC-165 identifier for this interface is 0x{:0>8x}",384				u32::from_be_bytes(self.selector)385			)?;386		}387		if is_impl {388			write!(out, "contract ")?;389		} else {390			write!(out, "interface ")?;391		}392		write!(out, "{}", self.name)?;393		if !self.is.is_empty() {394			write!(out, " is")?;395			for (i, n) in self.is.iter().enumerate() {396				if i != 0 {397					write!(out, ",")?;398				}399				write!(out, " {}", n)?;400			}401		}402		writeln!(out, " {{")?;403		self.functions.solidity_name(is_impl, out, tc)?;404		writeln!(out, "}}")?;405		Ok(())406	}407}408409pub struct SolidityEvent<A> {410	pub name: &'static str,411	pub args: A,412}413414impl<A: SolidityArguments> SolidityFunctions for SolidityEvent<A> {415	fn solidity_name(416		&self,417		_is_impl: bool,418		writer: &mut impl fmt::Write,419		tc: &TypeCollector,420	) -> fmt::Result {421		write!(writer, "\tevent {}(", self.name)?;422		self.args.solidity_name(writer, tc)?;423		writeln!(writer, ");")424	}425}426427#[impl_for_tuples(0, 48)]428impl SolidityItems for Tuple {429	for_tuples!( where #( Tuple: SolidityItems ),* );430431	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {432		for_tuples!( #(433            Tuple.solidity_name(writer, tc)?;434        )* );435		Ok(())436	}437}438439pub struct SolidityStructField<T> {440	pub docs: &'static [&'static str],441	pub name: &'static str,442	pub ty: PhantomData<*const T>,443}444445impl<T> SolidityItems for SolidityStructField<T>446where447	T: SolidityTypeName,448{449	fn solidity_name(&self, out: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {450		for doc in self.docs {451			writeln!(out, "///{}", doc)?;452		}453		write!(out, "\t")?;454		T::solidity_name(out, tc)?;455		writeln!(out, " {};", self.name)?;456		Ok(())457	}458}459pub struct SolidityStruct<F> {460	pub docs: &'static [&'static str],461	// pub generics:462	pub name: &'static str,463	pub fields: F,464}465impl<F> SolidityStruct<F>466where467	F: SolidityItems,468{469	pub fn format(&self, out: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {470		for doc in self.docs {471			writeln!(out, "///{}", doc)?;472		}473		writeln!(out, "struct {} {{", self.name)?;474		self.fields.solidity_name(out, tc)?;475		writeln!(out, "}}")?;476		Ok(())477	}478}479480pub struct SolidityEnumVariant {481	pub docs: &'static [&'static str],482	pub name: &'static str,483}484impl SolidityItems for SolidityEnumVariant {485	fn solidity_name(&self, out: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {486		for doc in self.docs {487			writeln!(out, "///{}", doc)?;488		}489		write!(out, "\t{}", self.name)?;490		Ok(())491	}492}493pub struct SolidityEnum {494	pub docs: &'static [&'static str],495	pub name: &'static str,496	pub fields: &'static [SolidityEnumVariant],497}498impl SolidityEnum {499	pub fn format(&self, out: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result {500		for doc in self.docs {501			writeln!(out, "///{}", doc)?;502		}503		write!(out, "enum {} {{", self.name)?;504		for (i, field) in self.fields.iter().enumerate() {505			if i != 0 {506				write!(out, ",")?;507			}508			writeln!(out)?;509			field.solidity_name(out, tc)?;510		}511		writeln!(out)?;512		writeln!(out, "}}")?;513		Ok(())514	}515}
modifiedcrates/evm-coder/src/solidity/traits.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/solidity/traits.rs
+++ b/crates/evm-coder/src/solidity/traits.rs
@@ -1,17 +1,6 @@
 use super::TypeCollector;
 use core::fmt;
 
-pub trait StructCollect: 'static {
-	/// Structure name.
-	fn name() -> String;
-	/// Structure declaration.
-	fn declaration() -> String;
-}
-
-pub trait SolidityEnum: 'static {
-	fn solidity_option(&self) -> &str;
-}
-
 pub trait SolidityTypeName: 'static {
 	fn solidity_name(writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
 	/// "simple" types are stored inline, no `memory` modifier should be used in solidity
@@ -23,10 +12,17 @@
 	}
 }
 
-pub trait SolidityType {
-	fn names(tc: &TypeCollector) -> Vec<String>;
+pub trait SolidityTupleTy: 'static {
+	fn fields(tc: &TypeCollector) -> Vec<String>;
 	fn len() -> usize;
 }
+pub trait SolidityStructTy: 'static {
+	fn generate_solidity_interface(tc: &TypeCollector) -> String;
+}
+pub trait SolidityEnumTy: 'static {
+	fn generate_solidity_interface(tc: &TypeCollector) -> String;
+	fn solidity_option(&self) -> &str;
+}
 
 pub trait SolidityArguments {
 	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
@@ -46,3 +42,9 @@
 		tc: &TypeCollector,
 	) -> fmt::Result;
 }
+
+pub trait SolidityItems {
+	fn solidity_name(&self, writer: &mut impl fmt::Write, tc: &TypeCollector) -> fmt::Result;
+	// For PhantomData fields
+	// fn is_void()
+}
modifiedcrates/evm-coder/tests/abi_derive_generation.rsdiffbeforeafterboth
--- a/crates/evm-coder/tests/abi_derive_generation.rs
+++ b/crates/evm-coder/tests/abi_derive_generation.rs
@@ -74,41 +74,6 @@
 	}
 
 	#[test]
-	#[cfg(feature = "stubgen")]
-	fn struct_collect_type_struct3_derived_mixed_param() {
-		assert_eq!(
-			<TypeStruct3DerivedMixedParam as ::evm_coder::solidity::StructCollect>::name(),
-			"TypeStruct3DerivedMixedParam"
-		);
-		similar_asserts::assert_eq!(
-			<TypeStruct3DerivedMixedParam as ::evm_coder::solidity::StructCollect>::declaration(),
-			r#"/// @dev Some docs
-/// At multi
-/// line
-struct TypeStruct3DerivedMixedParam {
-	/// @dev Docs for A
-	/// multi
-	/// line
-	TypeStruct1SimpleParam _a;
-	/// @dev Docs for B
-	TypeStruct2DynamicParam _b;
-	/// @dev Docs for C
-	TypeStruct2MixedParam _c;
-}
-"#
-		);
-	}
-
-	#[test]
-	#[cfg(feature = "stubgen")]
-	fn struct_collect_vec() {
-		assert_eq!(
-			<Vec<u8> as ::evm_coder::solidity::StructCollect>::name(),
-			"uint8[]"
-		);
-	}
-
-	#[test]
 	fn impl_abi_type_signature() {
 		assert_eq!(
 			<TypeStruct1SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
@@ -303,31 +268,6 @@
 	);
 
 	#[test]
-	#[cfg(feature = "stubgen")]
-	fn struct_collect_tuple_struct3_derived_mixed_param() {
-		assert_eq!(
-			<TupleStruct3DerivedMixedParam as ::evm_coder::solidity::StructCollect>::name(),
-			"TupleStruct3DerivedMixedParam"
-		);
-		similar_asserts::assert_eq!(
-			<TupleStruct3DerivedMixedParam as ::evm_coder::solidity::StructCollect>::declaration(),
-			r#"/// @dev Some docs
-/// At multi
-/// line
-struct TupleStruct3DerivedMixedParam {
-	/// @dev Docs for A
-	/// multi
-	/// line
-	TupleStruct1SimpleParam field0;
-	TupleStruct2DynamicParam field1;
-	/// @dev Docs for C
-	TupleStruct2MixedParam field2;
-}
-"#
-		);
-	}
-
-	#[test]
 	fn impl_abi_type_signature_same_for_structs() {
 		assert_eq!(
 			<TypeStruct1SimpleParam as evm_coder::abi::AbiType>::SIGNATURE
@@ -821,30 +761,5 @@
 				<Color as evm_coder::abi::AbiRead>::abi_read(&mut decoder).unwrap();
 			assert_eq!(restored_enum_data, Color::Green);
 		}
-	}
-
-	#[test]
-	#[cfg(feature = "stubgen")]
-	fn struct_collect_enum() {
-		assert_eq!(
-			<Color as ::evm_coder::solidity::StructCollect>::name(),
-			"Color"
-		);
-		similar_asserts::assert_eq!(
-			<Color as ::evm_coder::solidity::StructCollect>::declaration(),
-			r#"/// @dev Some docs
-/// At multi
-/// line
-enum Color {
-	/// @dev Docs for Red
-	/// multi
-	/// line
-	Red,
-	Green,
-	/// @dev Docs for Blue
-	Blue
-}
-"#
-		);
 	}
 }
modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/evm-contract-helpers/src/stubs/ContractHelpers.soldiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
+++ b/pallets/evm-contract-helpers/src/stubs/ContractHelpers.sol
@@ -265,13 +265,13 @@
 	}
 }
 
-/// @dev Cross account struct
+/// Cross account struct
 struct CrossAddress {
 	address eth;
 	uint256 sub;
 }
 
-/// @dev Ethereum representation of Optional value with CrossAddress.
+/// Ethereum representation of Optional value with CrossAddress.
 struct OptionCrossAddress {
 	bool status;
 	CrossAddress value;
modifiedpallets/fungible/src/stubs/UniqueFungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/fungible/src/stubs/UniqueFungible.soldiffbeforeafterboth
--- a/pallets/fungible/src/stubs/UniqueFungible.sol
+++ b/pallets/fungible/src/stubs/UniqueFungible.sol
@@ -437,67 +437,67 @@
 	}
 }
 
-/// @dev Cross account struct
+/// Cross account struct
 struct CrossAddress {
 	address eth;
 	uint256 sub;
 }
 
-/// @dev Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
 struct CollectionNestingPermission {
 	CollectionPermissionField field;
 	bool value;
 }
 
-/// @dev Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
 enum CollectionPermissionField {
-	/// @dev Owner of token can nest tokens under it.
+	/// Owner of token can nest tokens under it.
 	TokenOwner,
-	/// @dev Admin of token collection can nest tokens under token.
+	/// Admin of token collection can nest tokens under token.
 	CollectionAdmin
 }
 
-/// @dev Nested collections.
+/// Nested collections.
 struct CollectionNesting {
 	bool token_owner;
 	uint256[] ids;
 }
 
-/// @dev [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
 struct CollectionLimit {
 	CollectionLimitField field;
 	OptionUint value;
 }
 
-/// @dev Ethereum representation of Optional value with uint256.
+/// Ethereum representation of Optional value with uint256.
 struct OptionUint {
 	bool status;
 	uint256 value;
 }
 
-/// @dev [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
 enum CollectionLimitField {
-	/// @dev How many tokens can a user have on one account.
+	/// How many tokens can a user have on one account.
 	AccountTokenOwnership,
-	/// @dev How many bytes of data are available for sponsorship.
+	/// How many bytes of data are available for sponsorship.
 	SponsoredDataSize,
-	/// @dev In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
 	SponsoredDataRateLimit,
-	/// @dev How many tokens can be mined into this collection.
+	/// How many tokens can be mined into this collection.
 	TokenLimit,
-	/// @dev Timeouts for transfer sponsoring.
+	/// Timeouts for transfer sponsoring.
 	SponsorTransferTimeout,
-	/// @dev Timeout for sponsoring an approval in passed blocks.
+	/// Timeout for sponsoring an approval in passed blocks.
 	SponsorApproveTimeout,
-	/// @dev Whether the collection owner of the collection can send tokens (which belong to other users).
+	/// Whether the collection owner of the collection can send tokens (which belong to other users).
 	OwnerCanTransfer,
-	/// @dev Can the collection owner burn other people's tokens.
+	/// Can the collection owner burn other people's tokens.
 	OwnerCanDestroy,
-	/// @dev Is it possible to send tokens from this collection between users.
+	/// Is it possible to send tokens from this collection between users.
 	TransferEnabled
 }
 
-/// @dev Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
 struct Property {
 	string key;
 	bytes value;
modifiedpallets/nonfungible/src/stubs/UniqueNFT.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/nonfungible/src/stubs/UniqueNFT.soldiffbeforeafterboth
--- a/pallets/nonfungible/src/stubs/UniqueNFT.sol
+++ b/pallets/nonfungible/src/stubs/UniqueNFT.sol
@@ -127,35 +127,35 @@
 	}
 }
 
-/// @dev Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
 struct Property {
 	string key;
 	bytes value;
 }
 
-/// @dev Ethereum representation of Token Property Permissions.
+/// Ethereum representation of Token Property Permissions.
 struct TokenPropertyPermission {
-	/// @dev Token property key.
+	/// Token property key.
 	string key;
-	/// @dev Token property permissions.
+	/// Token property permissions.
 	PropertyPermission[] permissions;
 }
 
-/// @dev Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
 struct PropertyPermission {
-	/// @dev TokenPermission field.
+	/// TokenPermission field.
 	TokenPermissionField code;
-	/// @dev TokenPermission value.
+	/// TokenPermission value.
 	bool value;
 }
 
-/// @dev Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
 enum TokenPermissionField {
-	/// @dev Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
+	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
 	Mutable,
-	/// @dev Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
+	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
 	TokenOwner,
-	/// @dev Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
+	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
 	CollectionAdmin
 }
 
@@ -579,63 +579,63 @@
 	}
 }
 
-/// @dev Cross account struct
+/// Cross account struct
 struct CrossAddress {
 	address eth;
 	uint256 sub;
 }
 
-/// @dev Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
 struct CollectionNestingPermission {
 	CollectionPermissionField field;
 	bool value;
 }
 
-/// @dev Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
 enum CollectionPermissionField {
-	/// @dev Owner of token can nest tokens under it.
+	/// Owner of token can nest tokens under it.
 	TokenOwner,
-	/// @dev Admin of token collection can nest tokens under token.
+	/// Admin of token collection can nest tokens under token.
 	CollectionAdmin
 }
 
-/// @dev Nested collections.
+/// Nested collections.
 struct CollectionNesting {
 	bool token_owner;
 	uint256[] ids;
 }
 
-/// @dev [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
 struct CollectionLimit {
 	CollectionLimitField field;
 	OptionUint value;
 }
 
-/// @dev Ethereum representation of Optional value with uint256.
+/// Ethereum representation of Optional value with uint256.
 struct OptionUint {
 	bool status;
 	uint256 value;
 }
 
-/// @dev [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
 enum CollectionLimitField {
-	/// @dev How many tokens can a user have on one account.
+	/// How many tokens can a user have on one account.
 	AccountTokenOwnership,
-	/// @dev How many bytes of data are available for sponsorship.
+	/// How many bytes of data are available for sponsorship.
 	SponsoredDataSize,
-	/// @dev In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
 	SponsoredDataRateLimit,
-	/// @dev How many tokens can be mined into this collection.
+	/// How many tokens can be mined into this collection.
 	TokenLimit,
-	/// @dev Timeouts for transfer sponsoring.
+	/// Timeouts for transfer sponsoring.
 	SponsorTransferTimeout,
-	/// @dev Timeout for sponsoring an approval in passed blocks.
+	/// Timeout for sponsoring an approval in passed blocks.
 	SponsorApproveTimeout,
-	/// @dev Whether the collection owner of the collection can send tokens (which belong to other users).
+	/// Whether the collection owner of the collection can send tokens (which belong to other users).
 	OwnerCanTransfer,
-	/// @dev Can the collection owner burn other people's tokens.
+	/// Can the collection owner burn other people's tokens.
 	OwnerCanDestroy,
-	/// @dev Is it possible to send tokens from this collection between users.
+	/// Is it possible to send tokens from this collection between users.
 	TransferEnabled
 }
 
modifiedpallets/refungible/src/stubs/UniqueRefungible.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungible.soldiffbeforeafterboth
--- a/pallets/refungible/src/stubs/UniqueRefungible.sol
+++ b/pallets/refungible/src/stubs/UniqueRefungible.sol
@@ -127,35 +127,35 @@
 	}
 }
 
-/// @dev Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
 struct Property {
 	string key;
 	bytes value;
 }
 
-/// @dev Ethereum representation of Token Property Permissions.
+/// Ethereum representation of Token Property Permissions.
 struct TokenPropertyPermission {
-	/// @dev Token property key.
+	/// Token property key.
 	string key;
-	/// @dev Token property permissions.
+	/// Token property permissions.
 	PropertyPermission[] permissions;
 }
 
-/// @dev Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
 struct PropertyPermission {
-	/// @dev TokenPermission field.
+	/// TokenPermission field.
 	TokenPermissionField code;
-	/// @dev TokenPermission value.
+	/// TokenPermission value.
 	bool value;
 }
 
-/// @dev Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
 enum TokenPermissionField {
-	/// @dev Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
+	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
 	Mutable,
-	/// @dev Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
+	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
 	TokenOwner,
-	/// @dev Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
+	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
 	CollectionAdmin
 }
 
@@ -579,63 +579,63 @@
 	}
 }
 
-/// @dev Cross account struct
+/// Cross account struct
 struct CrossAddress {
 	address eth;
 	uint256 sub;
 }
 
-/// @dev Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
 struct CollectionNestingPermission {
 	CollectionPermissionField field;
 	bool value;
 }
 
-/// @dev Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
 enum CollectionPermissionField {
-	/// @dev Owner of token can nest tokens under it.
+	/// Owner of token can nest tokens under it.
 	TokenOwner,
-	/// @dev Admin of token collection can nest tokens under token.
+	/// Admin of token collection can nest tokens under token.
 	CollectionAdmin
 }
 
-/// @dev Nested collections.
+/// Nested collections.
 struct CollectionNesting {
 	bool token_owner;
 	uint256[] ids;
 }
 
-/// @dev [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
 struct CollectionLimit {
 	CollectionLimitField field;
 	OptionUint value;
 }
 
-/// @dev Ethereum representation of Optional value with uint256.
+/// Ethereum representation of Optional value with uint256.
 struct OptionUint {
 	bool status;
 	uint256 value;
 }
 
-/// @dev [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
 enum CollectionLimitField {
-	/// @dev How many tokens can a user have on one account.
+	/// How many tokens can a user have on one account.
 	AccountTokenOwnership,
-	/// @dev How many bytes of data are available for sponsorship.
+	/// How many bytes of data are available for sponsorship.
 	SponsoredDataSize,
-	/// @dev In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
 	SponsoredDataRateLimit,
-	/// @dev How many tokens can be mined into this collection.
+	/// How many tokens can be mined into this collection.
 	TokenLimit,
-	/// @dev Timeouts for transfer sponsoring.
+	/// Timeouts for transfer sponsoring.
 	SponsorTransferTimeout,
-	/// @dev Timeout for sponsoring an approval in passed blocks.
+	/// Timeout for sponsoring an approval in passed blocks.
 	SponsorApproveTimeout,
-	/// @dev Whether the collection owner of the collection can send tokens (which belong to other users).
+	/// Whether the collection owner of the collection can send tokens (which belong to other users).
 	OwnerCanTransfer,
-	/// @dev Can the collection owner burn other people's tokens.
+	/// Can the collection owner burn other people's tokens.
 	OwnerCanDestroy,
-	/// @dev Is it possible to send tokens from this collection between users.
+	/// Is it possible to send tokens from this collection between users.
 	TransferEnabled
 }
 
modifiedpallets/refungible/src/stubs/UniqueRefungibleToken.rawdiffbeforeafterboth

binary blob — no preview

modifiedpallets/refungible/src/stubs/UniqueRefungibleToken.soldiffbeforeafterboth
--- a/pallets/refungible/src/stubs/UniqueRefungibleToken.sol
+++ b/pallets/refungible/src/stubs/UniqueRefungibleToken.sol
@@ -128,7 +128,7 @@
 	}
 }
 
-/// @dev Cross account struct
+/// Cross account struct
 struct CrossAddress {
 	address eth;
 	uint256 sub;
modifiedtests/src/eth/api/ContractHelpers.soldiffbeforeafterboth
--- a/tests/src/eth/api/ContractHelpers.sol
+++ b/tests/src/eth/api/ContractHelpers.sol
@@ -171,13 +171,13 @@
 	function toggleAllowlist(address contractAddress, bool enabled) external;
 }
 
-/// @dev Ethereum representation of Optional value with CrossAddress.
+/// Ethereum representation of Optional value with CrossAddress.
 struct OptionCrossAddress {
 	bool status;
 	CrossAddress value;
 }
 
-/// @dev Cross account struct
+/// Cross account struct
 struct CrossAddress {
 	address eth;
 	uint256 sub;
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -279,67 +279,67 @@
 	function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
 }
 
-/// @dev Cross account struct
+/// Cross account struct
 struct CrossAddress {
 	address eth;
 	uint256 sub;
 }
 
-/// @dev Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
 struct CollectionNestingPermission {
 	CollectionPermissionField field;
 	bool value;
 }
 
-/// @dev Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
 enum CollectionPermissionField {
-	/// @dev Owner of token can nest tokens under it.
+	/// Owner of token can nest tokens under it.
 	TokenOwner,
-	/// @dev Admin of token collection can nest tokens under token.
+	/// Admin of token collection can nest tokens under token.
 	CollectionAdmin
 }
 
-/// @dev Nested collections.
+/// Nested collections.
 struct CollectionNesting {
 	bool token_owner;
 	uint256[] ids;
 }
 
-/// @dev [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
 struct CollectionLimit {
 	CollectionLimitField field;
 	OptionUint value;
 }
 
-/// @dev Ethereum representation of Optional value with uint256.
+/// Ethereum representation of Optional value with uint256.
 struct OptionUint {
 	bool status;
 	uint256 value;
 }
 
-/// @dev [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
 enum CollectionLimitField {
-	/// @dev How many tokens can a user have on one account.
+	/// How many tokens can a user have on one account.
 	AccountTokenOwnership,
-	/// @dev How many bytes of data are available for sponsorship.
+	/// How many bytes of data are available for sponsorship.
 	SponsoredDataSize,
-	/// @dev In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
 	SponsoredDataRateLimit,
-	/// @dev How many tokens can be mined into this collection.
+	/// How many tokens can be mined into this collection.
 	TokenLimit,
-	/// @dev Timeouts for transfer sponsoring.
+	/// Timeouts for transfer sponsoring.
 	SponsorTransferTimeout,
-	/// @dev Timeout for sponsoring an approval in passed blocks.
+	/// Timeout for sponsoring an approval in passed blocks.
 	SponsorApproveTimeout,
-	/// @dev Whether the collection owner of the collection can send tokens (which belong to other users).
+	/// Whether the collection owner of the collection can send tokens (which belong to other users).
 	OwnerCanTransfer,
-	/// @dev Can the collection owner burn other people's tokens.
+	/// Can the collection owner burn other people's tokens.
 	OwnerCanDestroy,
-	/// @dev Is it possible to send tokens from this collection between users.
+	/// Is it possible to send tokens from this collection between users.
 	TransferEnabled
 }
 
-/// @dev Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
 struct Property {
 	string key;
 	bytes value;
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -80,35 +80,35 @@
 	function property(uint256 tokenId, string memory key) external view returns (bytes memory);
 }
 
-/// @dev Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
 struct Property {
 	string key;
 	bytes value;
 }
 
-/// @dev Ethereum representation of Token Property Permissions.
+/// Ethereum representation of Token Property Permissions.
 struct TokenPropertyPermission {
-	/// @dev Token property key.
+	/// Token property key.
 	string key;
-	/// @dev Token property permissions.
+	/// Token property permissions.
 	PropertyPermission[] permissions;
 }
 
-/// @dev Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
 struct PropertyPermission {
-	/// @dev TokenPermission field.
+	/// TokenPermission field.
 	TokenPermissionField code;
-	/// @dev TokenPermission value.
+	/// TokenPermission value.
 	bool value;
 }
 
-/// @dev Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
 enum TokenPermissionField {
-	/// @dev Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
+	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
 	Mutable,
-	/// @dev Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
+	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
 	TokenOwner,
-	/// @dev Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
+	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
 	CollectionAdmin
 }
 
@@ -379,63 +379,63 @@
 	function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
 }
 
-/// @dev Cross account struct
+/// Cross account struct
 struct CrossAddress {
 	address eth;
 	uint256 sub;
 }
 
-/// @dev Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
 struct CollectionNestingPermission {
 	CollectionPermissionField field;
 	bool value;
 }
 
-/// @dev Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
 enum CollectionPermissionField {
-	/// @dev Owner of token can nest tokens under it.
+	/// Owner of token can nest tokens under it.
 	TokenOwner,
-	/// @dev Admin of token collection can nest tokens under token.
+	/// Admin of token collection can nest tokens under token.
 	CollectionAdmin
 }
 
-/// @dev Nested collections.
+/// Nested collections.
 struct CollectionNesting {
 	bool token_owner;
 	uint256[] ids;
 }
 
-/// @dev [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
 struct CollectionLimit {
 	CollectionLimitField field;
 	OptionUint value;
 }
 
-/// @dev Ethereum representation of Optional value with uint256.
+/// Ethereum representation of Optional value with uint256.
 struct OptionUint {
 	bool status;
 	uint256 value;
 }
 
-/// @dev [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
 enum CollectionLimitField {
-	/// @dev How many tokens can a user have on one account.
+	/// How many tokens can a user have on one account.
 	AccountTokenOwnership,
-	/// @dev How many bytes of data are available for sponsorship.
+	/// How many bytes of data are available for sponsorship.
 	SponsoredDataSize,
-	/// @dev In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
 	SponsoredDataRateLimit,
-	/// @dev How many tokens can be mined into this collection.
+	/// How many tokens can be mined into this collection.
 	TokenLimit,
-	/// @dev Timeouts for transfer sponsoring.
+	/// Timeouts for transfer sponsoring.
 	SponsorTransferTimeout,
-	/// @dev Timeout for sponsoring an approval in passed blocks.
+	/// Timeout for sponsoring an approval in passed blocks.
 	SponsorApproveTimeout,
-	/// @dev Whether the collection owner of the collection can send tokens (which belong to other users).
+	/// Whether the collection owner of the collection can send tokens (which belong to other users).
 	OwnerCanTransfer,
-	/// @dev Can the collection owner burn other people's tokens.
+	/// Can the collection owner burn other people's tokens.
 	OwnerCanDestroy,
-	/// @dev Is it possible to send tokens from this collection between users.
+	/// Is it possible to send tokens from this collection between users.
 	TransferEnabled
 }
 
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungible.sol
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -80,35 +80,35 @@
 	function property(uint256 tokenId, string memory key) external view returns (bytes memory);
 }
 
-/// @dev Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
+/// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
 struct Property {
 	string key;
 	bytes value;
 }
 
-/// @dev Ethereum representation of Token Property Permissions.
+/// Ethereum representation of Token Property Permissions.
 struct TokenPropertyPermission {
-	/// @dev Token property key.
+	/// Token property key.
 	string key;
-	/// @dev Token property permissions.
+	/// Token property permissions.
 	PropertyPermission[] permissions;
 }
 
-/// @dev Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) as an key and value.
 struct PropertyPermission {
-	/// @dev TokenPermission field.
+	/// TokenPermission field.
 	TokenPermissionField code;
-	/// @dev TokenPermission value.
+	/// TokenPermission value.
 	bool value;
 }
 
-/// @dev Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
+/// Ethereum representation of TokenPermissions (see [`up_data_structs::PropertyPermission`]) fields as an enumeration.
 enum TokenPermissionField {
-	/// @dev Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
+	/// Permission to change the property and property permission. See [`up_data_structs::PropertyPermission::mutable`]
 	Mutable,
-	/// @dev Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
+	/// Change permission for the collection administrator. See [`up_data_structs::PropertyPermission::token_owner`]
 	TokenOwner,
-	/// @dev Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
+	/// Permission to change the property for the owner of the token. See [`up_data_structs::PropertyPermission::collection_admin`]
 	CollectionAdmin
 }
 
@@ -379,63 +379,63 @@
 	function changeCollectionOwnerCross(CrossAddress memory newOwner) external;
 }
 
-/// @dev Cross account struct
+/// Cross account struct
 struct CrossAddress {
 	address eth;
 	uint256 sub;
 }
 
-/// @dev Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
 struct CollectionNestingPermission {
 	CollectionPermissionField field;
 	bool value;
 }
 
-/// @dev Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
+/// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) fields as an enumeration.
 enum CollectionPermissionField {
-	/// @dev Owner of token can nest tokens under it.
+	/// Owner of token can nest tokens under it.
 	TokenOwner,
-	/// @dev Admin of token collection can nest tokens under token.
+	/// Admin of token collection can nest tokens under token.
 	CollectionAdmin
 }
 
-/// @dev Nested collections.
+/// Nested collections.
 struct CollectionNesting {
 	bool token_owner;
 	uint256[] ids;
 }
 
-/// @dev [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) field representation for EVM.
 struct CollectionLimit {
 	CollectionLimitField field;
 	OptionUint value;
 }
 
-/// @dev Ethereum representation of Optional value with uint256.
+/// Ethereum representation of Optional value with uint256.
 struct OptionUint {
 	bool status;
 	uint256 value;
 }
 
-/// @dev [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
+/// [`CollectionLimits`](up_data_structs::CollectionLimits) fields representation for EVM.
 enum CollectionLimitField {
-	/// @dev How many tokens can a user have on one account.
+	/// How many tokens can a user have on one account.
 	AccountTokenOwnership,
-	/// @dev How many bytes of data are available for sponsorship.
+	/// How many bytes of data are available for sponsorship.
 	SponsoredDataSize,
-	/// @dev In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
+	/// In any case, chain default: [`SponsoringRateLimit::SponsoringDisabled`]
 	SponsoredDataRateLimit,
-	/// @dev How many tokens can be mined into this collection.
+	/// How many tokens can be mined into this collection.
 	TokenLimit,
-	/// @dev Timeouts for transfer sponsoring.
+	/// Timeouts for transfer sponsoring.
 	SponsorTransferTimeout,
-	/// @dev Timeout for sponsoring an approval in passed blocks.
+	/// Timeout for sponsoring an approval in passed blocks.
 	SponsorApproveTimeout,
-	/// @dev Whether the collection owner of the collection can send tokens (which belong to other users).
+	/// Whether the collection owner of the collection can send tokens (which belong to other users).
 	OwnerCanTransfer,
-	/// @dev Can the collection owner burn other people's tokens.
+	/// Can the collection owner burn other people's tokens.
 	OwnerCanDestroy,
-	/// @dev Is it possible to send tokens from this collection between users.
+	/// Is it possible to send tokens from this collection between users.
 	TransferEnabled
 }
 
modifiedtests/src/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungibleToken.sol
+++ b/tests/src/eth/api/UniqueRefungibleToken.sol
@@ -79,7 +79,7 @@
 	) external returns (bool);
 }
 
-/// @dev Cross account struct
+/// Cross account struct
 struct CrossAddress {
 	address eth;
 	uint256 sub;