git.delta.rocks / unique-network / refs/commits / 7a935af0dcb6

difftreelog

Merge branch 'develop' into tests/generalization

Max Andreev2023-01-18parents: #9df5af1 #d996a74.patch.diff
in: master

57 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2330,7 +2330,6 @@
  "hex",
  "hex-literal",
  "impl-trait-for-tuples",
- "pallet-evm",
  "primitive-types 0.12.1",
  "sha3-const",
  "similar-asserts",
modifiedcrates/evm-coder/Cargo.tomldiffbeforeafterboth
--- a/crates/evm-coder/Cargo.toml
+++ b/crates/evm-coder/Cargo.toml
@@ -19,8 +19,6 @@
 # We have tuple-heavy code in solidity.rs
 impl-trait-for-tuples = "0.2.2"
 
-pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }
-
 [dev-dependencies]
 # We want to assert some large binary blobs equality in tests
 hex = "0.4.3"
modifiedcrates/evm-coder/procedural/src/solidity_interface.rsdiffbeforeafterboth
--- a/crates/evm-coder/procedural/src/solidity_interface.rs
+++ b/crates/evm-coder/procedural/src/solidity_interface.rs
@@ -347,14 +347,14 @@
 
 	fn is_value(&self) -> bool {
 		if let Ok(ident) = self.plain() {
-			return ident == "value";
+			return ident == "Value";
 		}
 		false
 	}
 
 	fn is_caller(&self) -> bool {
 		if let Ok(ident) = self.plain() {
-			return ident == "caller";
+			return ident == "Caller";
 		}
 		false
 	}
@@ -610,7 +610,7 @@
 		let custom_signature = self.expand_custom_signature();
 		quote! {
 			const #screaming_name_signature: ::evm_coder::custom_signature::SignatureUnit = #custom_signature;
-			const #screaming_name: ::evm_coder::types::bytes4 = {
+			const #screaming_name: ::evm_coder::types::Bytes4 = {
 				let mut sum = ::evm_coder::sha3_const::Keccak256::new();
 				let mut pos = 0;
 				while pos < Self::#screaming_name_signature.len {
@@ -974,7 +974,7 @@
 					#consts
 				)*
 				/// Return this call ERC165 selector
-				pub const fn interface_id() -> ::evm_coder::types::bytes4 {
+				pub const fn interface_id() -> ::evm_coder::types::Bytes4 {
 					let mut interface_id = 0;
 					#(#interface_id)*
 					#(#inline_interface_id)*
@@ -999,7 +999,7 @@
 						)*),
 					};
 
-					let mut out = ::evm_coder::types::string::new();
+					let mut out = ::evm_coder::types::String::new();
 					if #solidity_name.starts_with("Inline") {
 						out.push_str("/// @dev inlined interface\n");
 					}
@@ -1019,7 +1019,7 @@
 				}
 			}
 			impl #gen_ref ::evm_coder::Call for #call_name #gen_ref {
-				fn parse(method_id: ::evm_coder::types::bytes4, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {
+				fn parse(method_id: ::evm_coder::types::Bytes4, reader: &mut ::evm_coder::abi::AbiReader) -> ::evm_coder::execution::Result<Option<Self>> {
 					use ::evm_coder::abi::AbiRead;
 					match method_id {
 						::evm_coder::ERC165Call::INTERFACE_ID => return Ok(
@@ -1041,7 +1041,7 @@
 			#gen_where
 			{
 				/// Is this contract implements specified ERC165 selector
-				pub fn supports_interface(this: &#name, interface_id: ::evm_coder::types::bytes4) -> bool {
+				pub fn supports_interface(this: &#name, interface_id: ::evm_coder::types::Bytes4) -> bool {
 					interface_id != u32::to_be_bytes(0xffffff) && (
 						interface_id == ::evm_coder::ERC165Call::INTERFACE_ID ||
 						interface_id == Self::interface_id()
modifiedcrates/evm-coder/procedural/src/to_log.rsdiffbeforeafterboth
--- a/crates/evm-coder/procedural/src/to_log.rs
+++ b/crates/evm-coder/procedural/src/to_log.rs
@@ -137,7 +137,7 @@
 			Self::#name {#(
 				#fields,
 			)*} => {
-				topics.push(topic::from(Self::#name_screaming));
+				topics.push(::evm_coder::types::Topic::from(Self::#name_screaming));
 				#(
 					topics.push(#indexed.to_topic());
 				)*
@@ -222,7 +222,7 @@
 							#solidity_functions,
 						)*),
 					};
-					let mut out = string::new();
+					let mut out = ::evm_coder::types::String::new();
 					out.push_str("/// @dev inlined interface\n");
 					let _ = interface.format(is_impl, &mut out, tc);
 					tc.collect(out);
@@ -231,7 +231,7 @@
 
 			#[automatically_derived]
 			impl ::evm_coder::events::ToLog for #name {
-				fn to_log(&self, contract: address) -> ::ethereum::Log {
+				fn to_log(&self, contract: Address) -> ::ethereum::Log {
 					use ::evm_coder::events::ToTopic;
 					use ::evm_coder::abi::AbiWrite;
 					let mut writer = ::evm_coder::abi::AbiWriter::new();
modifiedcrates/evm-coder/src/abi/impls.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/abi/impls.rs
+++ b/crates/evm-coder/src/abi/impls.rs
@@ -63,27 +63,27 @@
 impl_abi!(u128, uint128, false);
 impl_abi!(U256, uint256, false);
 impl_abi!(H160, address, false);
-impl_abi!(string, string, true);
+impl_abi!(String, string, true);
 
 impl_abi_writeable!(&str, string);
 
-impl_abi_type!(bytes, bytes, true);
+impl_abi_type!(Bytes, bytes, true);
 
-impl AbiRead for bytes {
-	fn abi_read(reader: &mut AbiReader) -> Result<bytes> {
-		Ok(bytes(reader.bytes()?))
+impl AbiRead for Bytes {
+	fn abi_read(reader: &mut AbiReader) -> Result<Bytes> {
+		Ok(Bytes(reader.bytes()?))
 	}
 }
 
-impl AbiWrite for bytes {
+impl AbiWrite for Bytes {
 	fn abi_write(&self, writer: &mut AbiWriter) {
 		writer.bytes(self.0.as_slice())
 	}
 }
 
-impl_abi_type!(bytes4, bytes4, false);
-impl AbiRead for bytes4 {
-	fn abi_read(reader: &mut AbiReader) -> Result<bytes4> {
+impl_abi_type!(Bytes4, bytes4, false);
+impl AbiRead for Bytes4 {
+	fn abi_read(reader: &mut AbiReader) -> Result<Bytes4> {
 		reader.bytes4()
 	}
 }
modifiedcrates/evm-coder/src/abi/mod.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/abi/mod.rs
+++ b/crates/evm-coder/src/abi/mod.rs
@@ -54,7 +54,7 @@
 		}
 	}
 	/// Start reading RLP buffer, parsing first 4 bytes as selector
-	pub fn new_call(buf: &'i [u8]) -> Result<(bytes4, Self)> {
+	pub fn new_call(buf: &'i [u8]) -> Result<(Bytes4, Self)> {
 		if buf.len() < 4 {
 			return Err(Error::Error(ExitError::OutOfOffset));
 		}
@@ -148,8 +148,8 @@
 	}
 
 	/// Read [`string`] at current position, then advance
-	pub fn string(&mut self) -> Result<string> {
-		string::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))
+	pub fn string(&mut self) -> Result<String> {
+		String::from_utf8(self.bytes()?).map_err(|_| Error::Error(ExitError::InvalidRange))
 	}
 
 	/// Read [`u8`] at current position, then advance
modifiedcrates/evm-coder/src/abi/test.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/abi/test.rs
+++ b/crates/evm-coder/src/abi/test.rs
@@ -39,22 +39,22 @@
 
 #[test]
 fn encode_decode_uint8() {
-	test_impl_uint!(uint8);
+	test_impl_uint!(u8);
 }
 
 #[test]
 fn encode_decode_uint32() {
-	test_impl_uint!(uint32);
+	test_impl_uint!(u32);
 }
 
 #[test]
 fn encode_decode_uint128() {
-	test_impl_uint!(uint128);
+	test_impl_uint!(u128);
 }
 
 #[test]
 fn encode_decode_uint256() {
-	test_impl::<uint256>(
+	test_impl::<U256>(
 		0xdeadbeef,
 		U256([255, 0, 0, 0]),
 		&hex!(
@@ -101,7 +101,7 @@
 
 #[test]
 fn encode_decode_vec_tuple_address_uint256() {
-	test_impl::<Vec<(address, uint256)>>(
+	test_impl::<Vec<(Address, U256)>>(
         0x1ACF2D55,
         vec![
             (
@@ -138,7 +138,7 @@
 
 #[test]
 fn encode_decode_vec_tuple_uint256_string() {
-	test_impl::<Vec<(uint256, string)>>(
+	test_impl::<Vec<(U256, String)>>(
         0xdeadbeef,
         vec![
             (1.into(), "Test URI 0".to_string()),
@@ -261,7 +261,7 @@
 	let (call, mut decoder) = AbiReader::new_call(encoded_data).unwrap();
 	assert_eq!(call, u32::to_be_bytes(decoded_data.0));
 	let address = decoder.address().unwrap();
-	let data = <Vec<(uint256, string)>>::abi_read(&mut decoder).unwrap();
+	let data = <Vec<(U256, String)>>::abi_read(&mut decoder).unwrap();
 	assert_eq!(data, decoded_data.1);
 
 	let mut writer = AbiWriter::new_call(decoded_data.0);
@@ -273,12 +273,12 @@
 
 #[test]
 fn encode_decode_vec_tuple_string_bytes() {
-	test_impl::<Vec<(string, bytes)>>(
+	test_impl::<Vec<(String, Bytes)>>(
 		0xdeadbeef,
 		vec![
 			(
 				"Test URI 0".to_string(),
-				bytes(vec![
+				Bytes(vec![
 					0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
 					0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
 					0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
@@ -287,14 +287,14 @@
 			),
 			(
 				"Test URI 1".to_string(),
-				bytes(vec![
+				Bytes(vec![
 					0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
 					0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
 					0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
 					0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
 				]),
 			),
-			("Test URI 2".to_string(), bytes(vec![0x33, 0x33])),
+			("Test URI 2".to_string(), Bytes(vec![0x33, 0x33])),
 		],
 		&hex!(
 			"
@@ -337,10 +337,10 @@
 // #[ignore = "reason"]
 fn encode_decode_tuple0_tuple1_uint8_tuple1_string_bytes_tuple1_uint8_bytes() {
 	let int = 0xff;
-	let by = bytes(vec![0x11, 0x22, 0x33]);
+	let by = Bytes(vec![0x11, 0x22, 0x33]);
 	let string = "some string".to_string();
 
-	test_impl::<((u8,), (String, bytes), (u8, bytes))>(
+	test_impl::<((u8,), (String, Bytes), (u8, Bytes))>(
 		0xdeadbeef,
 		((int,), (string.clone(), by.clone()), (int, by)),
 		&hex!(
@@ -485,9 +485,9 @@
 
 #[test]
 fn encode_decode_tuple0_tuple1_string_bytes() {
-	test_impl::<((String, bytes),)>(
+	test_impl::<((String, Bytes),)>(
 		0xdeadbeef,
-		(("some string".to_string(), bytes(vec![1, 2, 3])),),
+		(("some string".to_string(), Bytes(vec![1, 2, 3])),),
 		&hex!(
 			"
                 deadbeef
modifiedcrates/evm-coder/src/events.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/events.rs
+++ b/crates/evm-coder/src/events.rs
@@ -15,7 +15,7 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 use ethereum::Log;
-use primitive_types::{H160, H256};
+use primitive_types::{H160, H256, U256};
 
 use crate::types::*;
 
@@ -45,7 +45,7 @@
 	}
 }
 
-impl ToTopic for uint256 {
+impl ToTopic for U256 {
 	fn to_topic(&self) -> H256 {
 		let mut out = [0u8; 32];
 		self.to_big_endian(&mut out);
@@ -53,7 +53,7 @@
 	}
 }
 
-impl ToTopic for address {
+impl ToTopic for Address {
 	fn to_topic(&self) -> H256 {
 		let mut out = [0u8; 32];
 		out[12..32].copy_from_slice(&self.0);
@@ -61,7 +61,7 @@
 	}
 }
 
-impl ToTopic for uint32 {
+impl ToTopic for u32 {
 	fn to_topic(&self) -> H256 {
 		let mut out = [0u8; 32];
 		out[28..32].copy_from_slice(&self.to_be_bytes());
modifiedcrates/evm-coder/src/lib.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/lib.rs
+++ b/crates/evm-coder/src/lib.rs
@@ -131,33 +131,23 @@
 	use alloc::{vec::Vec};
 	use primitive_types::{U256, H160, H256};
 
-	pub type address = H160;
-	pub type uint8 = u8;
-	pub type uint16 = u16;
-	pub type uint32 = u32;
-	pub type uint64 = u64;
-	pub type uint128 = u128;
-	pub type uint256 = U256;
-	pub type bytes4 = [u8; 4];
-	pub type topic = H256;
+	pub type Address = H160;
+	pub type Bytes4 = [u8; 4];
+	pub type Topic = H256;
 
 	#[cfg(not(feature = "std"))]
-	pub type string = ::alloc::string::String;
+	pub type String = ::alloc::string::String;
 	#[cfg(feature = "std")]
-	pub type string = ::std::string::String;
+	pub type String = ::std::string::String;
 
 	#[derive(Default, Debug, PartialEq, Eq, Clone)]
-	pub struct bytes(pub Vec<u8>);
-
-	/// Solidity doesn't have `void` type, however we have special implementation
-	/// for empty tuple return type
-	pub type void = ();
+	pub struct Bytes(pub Vec<u8>);
 
 	//#region Special types
 	/// Makes function payable
-	pub type value = U256;
+	pub type Value = U256;
 	/// Makes function caller-sensitive
-	pub type caller = address;
+	pub type Caller = Address;
 	//#endregion
 
 	/// Ethereum typed call message, similar to solidity
@@ -172,20 +162,20 @@
 		pub value: U256,
 	}
 
-	impl From<Vec<u8>> for bytes {
+	impl From<Vec<u8>> for Bytes {
 		fn from(src: Vec<u8>) -> Self {
 			Self(src)
 		}
 	}
 
 	#[allow(clippy::from_over_into)]
-	impl Into<Vec<u8>> for bytes {
+	impl Into<Vec<u8>> for Bytes {
 		fn into(self) -> Vec<u8> {
 			self.0
 		}
 	}
 
-	impl bytes {
+	impl Bytes {
 		#[must_use]
 		pub fn len(&self) -> usize {
 			self.0.len()
@@ -201,7 +191,7 @@
 /// Parseable EVM call, this trait should be implemented with [`solidity_interface`] macro
 pub trait Call: Sized {
 	/// Parse call buffer into typed call enum
-	fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;
+	fn parse(selector: types::Bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>>;
 }
 
 /// Intended to be used as `#[weight]` output type
@@ -237,22 +227,22 @@
 	/// implements specified interface
 	SupportsInterface {
 		/// Requested interface
-		interface_id: types::bytes4,
+		interface_id: types::Bytes4,
 	},
 }
 
 impl ERC165Call {
 	/// ERC165 selector is provided by standard
-	pub const INTERFACE_ID: types::bytes4 = u32::to_be_bytes(0x01ffc9a7);
+	pub const INTERFACE_ID: types::Bytes4 = u32::to_be_bytes(0x01ffc9a7);
 }
 
 impl Call for ERC165Call {
-	fn parse(selector: types::bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>> {
+	fn parse(selector: types::Bytes4, input: &mut AbiReader) -> execution::Result<Option<Self>> {
 		if selector != Self::INTERFACE_ID {
 			return Ok(None);
 		}
 		Ok(Some(Self::SupportsInterface {
-			interface_id: types::bytes4::abi_read(input)?,
+			interface_id: types::Bytes4::abi_read(input)?,
 		}))
 	}
 }
modifiedcrates/evm-coder/src/solidity/impls.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/solidity/impls.rs
+++ b/crates/evm-coder/src/solidity/impls.rs
@@ -27,14 +27,14 @@
 	u64 => "uint64" true = "0",
 	u128 => "uint128" true = "0",
 	U256 => "uint256" true = "0",
-	bytes4 => "bytes4" true = "bytes4(0)",
+	Bytes4 => "bytes4" true = "bytes4(0)",
 	H160 => "address" true = "0x0000000000000000000000000000000000000000",
-	string => "string" false = "\"\"",
-	bytes => "bytes" false = "hex\"\"",
+	String => "string" false = "\"\"",
+	Bytes => "bytes" false = "hex\"\"",
 	bool => "bool" true = "false",
 }
 
-impl SolidityTypeName for void {
+impl SolidityTypeName for () {
 	fn solidity_name(_writer: &mut impl fmt::Write, _tc: &TypeCollector) -> fmt::Result {
 		Ok(())
 	}
@@ -72,10 +72,10 @@
 macro_rules! impl_tuples {
 	($($ident:ident)+) => {
 		impl<$($ident: SolidityTypeName + 'static),+> SolidityTupleTy for ($($ident,)+) {
-			fn fields(tc: &TypeCollector) -> Vec<string> {
+			fn fields(tc: &TypeCollector) -> Vec<String> {
 				let mut collected = Vec::with_capacity(Self::len());
 				$({
-					let mut out = string::new();
+					let mut out = String::new();
 					$ident::solidity_name(&mut out, tc).expect("no fmt error");
 					collected.push(out);
 				})*;
modifiedcrates/evm-coder/src/solidity/mod.rsdiffbeforeafterboth
--- a/crates/evm-coder/src/solidity/mod.rs
+++ b/crates/evm-coder/src/solidity/mod.rs
@@ -26,7 +26,7 @@
 mod impls;
 
 #[cfg(not(feature = "std"))]
-use alloc::{string::String, vec::Vec, collections::BTreeMap, format};
+use alloc::{vec::Vec, collections::BTreeMap, format};
 #[cfg(feature = "std")]
 use std::collections::BTreeMap;
 use core::{
@@ -42,16 +42,16 @@
 pub struct TypeCollector {
 	/// Code => id
 	/// id ordering is required to perform topo-sort on the resulting data
-	structs: RefCell<BTreeMap<string, usize>>,
-	anonymous: RefCell<BTreeMap<Vec<string>, usize>>,
-	// generic: RefCell<BTreeMap<string, usize>>,
+	structs: RefCell<BTreeMap<String, usize>>,
+	anonymous: RefCell<BTreeMap<Vec<String>, usize>>,
+	// generic: RefCell<BTreeMap<String, usize>>,
 	id: Cell<usize>,
 }
 impl TypeCollector {
 	pub fn new() -> Self {
 		Self::default()
 	}
-	pub fn collect(&self, item: string) {
+	pub fn collect(&self, item: String) {
 		let id = self.next_id();
 		self.structs.borrow_mut().insert(item, id);
 	}
@@ -84,7 +84,7 @@
 	pub fn collect_enum<T: SolidityEnumTy>(&self) -> String {
 		T::generate_solidity_interface(self)
 	}
-	pub fn finish(self) -> Vec<string> {
+	pub fn finish(self) -> Vec<String> {
 		let mut data = self.structs.into_inner().into_iter().collect::<Vec<_>>();
 		data.sort_by_key(|(_, id)| Reverse(*id));
 		data.into_iter().map(|(code, _)| code).collect()
@@ -360,7 +360,7 @@
 
 pub struct SolidityInterface<F: SolidityFunctions> {
 	pub docs: &'static [&'static str],
-	pub selector: bytes4,
+	pub selector: Bytes4,
 	pub name: &'static str,
 	pub is: &'static [&'static str],
 	pub functions: F,
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
@@ -1,6 +1,6 @@
 mod test_struct {
 	use evm_coder_procedural::AbiCoder;
-	use evm_coder::types::bytes;
+	use evm_coder::types::Bytes;
 
 	#[test]
 	fn empty_struct() {
@@ -27,13 +27,13 @@
 	#[derive(AbiCoder, PartialEq, Debug)]
 	struct TypeStruct2DynamicParam {
 		_a: String,
-		_b: bytes,
+		_b: Bytes,
 	}
 
 	#[derive(AbiCoder, PartialEq, Debug)]
 	struct TypeStruct2MixedParam {
 		_a: u8,
-		_b: bytes,
+		_b: Bytes,
 	}
 
 	#[derive(AbiCoder, PartialEq, Debug)]
@@ -236,10 +236,10 @@
 	struct TupleStruct2SimpleParam(u8, u32);
 
 	#[derive(AbiCoder, PartialEq, Debug)]
-	struct TupleStruct2DynamicParam(String, bytes);
+	struct TupleStruct2DynamicParam(String, Bytes);
 
 	#[derive(AbiCoder, PartialEq, Debug)]
-	struct TupleStruct2MixedParam(u8, bytes);
+	struct TupleStruct2MixedParam(u8, Bytes);
 
 	#[derive(AbiCoder, PartialEq, Debug)]
 	struct TupleStruct1DerivedSimpleParam(TupleStruct1SimpleParam);
@@ -562,8 +562,8 @@
 	#[test]
 	fn codec_struct_2_dynamic() {
 		let _a: String = "some string".into();
-		let _b: bytes = bytes(vec![0x11, 0x22, 0x33]);
-		test_impl::<(String, bytes), TupleStruct2DynamicParam, TypeStruct2DynamicParam>(
+		let _b: Bytes = Bytes(vec![0x11, 0x22, 0x33]);
+		test_impl::<(String, Bytes), TupleStruct2DynamicParam, TypeStruct2DynamicParam>(
 			(_a.clone(), _b.clone()),
 			TupleStruct2DynamicParam(_a.clone(), _b.clone()),
 			TypeStruct2DynamicParam { _a, _b },
@@ -573,8 +573,8 @@
 	#[test]
 	fn codec_struct_2_mixed() {
 		let _a: u8 = 0xff;
-		let _b: bytes = bytes(vec![0x11, 0x22, 0x33]);
-		test_impl::<(u8, bytes), TupleStruct2MixedParam, TypeStruct2MixedParam>(
+		let _b: Bytes = Bytes(vec![0x11, 0x22, 0x33]);
+		test_impl::<(u8, Bytes), TupleStruct2MixedParam, TypeStruct2MixedParam>(
 			(_a.clone(), _b.clone()),
 			TupleStruct2MixedParam(_a.clone(), _b.clone()),
 			TypeStruct2MixedParam { _a, _b },
@@ -605,9 +605,9 @@
 	#[test]
 	fn codec_struct_2_derived_dynamic() {
 		let _a = "some string".to_string();
-		let _b = bytes(vec![0x11, 0x22, 0x33]);
+		let _b = Bytes(vec![0x11, 0x22, 0x33]);
 		test_impl::<
-			((String,), (String, bytes)),
+			((String,), (String, Bytes)),
 			TupleStruct2DerivedDynamicParam,
 			TypeStruct2DerivedDynamicParam,
 		>(
@@ -626,10 +626,10 @@
 	#[test]
 	fn codec_struct_3_derived_mixed() {
 		let int = 0xff;
-		let by = bytes(vec![0x11, 0x22, 0x33]);
+		let by = Bytes(vec![0x11, 0x22, 0x33]);
 		let string = "some string".to_string();
 		test_impl::<
-			((u8,), (String, bytes), (u8, bytes)),
+			((u8,), (String, Bytes), (u8, Bytes)),
 			TupleStruct3DerivedMixedParam,
 			TypeStruct3DerivedMixedParam,
 		>(
modifiedcrates/evm-coder/tests/conditional_is.rsdiffbeforeafterboth
--- a/crates/evm-coder/tests/conditional_is.rs
+++ b/crates/evm-coder/tests/conditional_is.rs
@@ -4,14 +4,14 @@
 
 #[solidity_interface(name = A)]
 impl Contract {
-	fn method_a() -> Result<void> {
+	fn method_a() -> Result<()> {
 		Ok(())
 	}
 }
 
 #[solidity_interface(name = B)]
 impl Contract {
-	fn method_b() -> Result<void> {
+	fn method_b() -> Result<()> {
 		Ok(())
 	}
 }
modifiedcrates/evm-coder/tests/generics.rsdiffbeforeafterboth
--- a/crates/evm-coder/tests/generics.rs
+++ b/crates/evm-coder/tests/generics.rs
@@ -16,19 +16,20 @@
 
 use std::marker::PhantomData;
 use evm_coder::{execution::Result, generate_stubgen, solidity_interface, types::*};
+use primitive_types::U256;
 
 pub struct Generic<T>(PhantomData<T>);
 
 #[solidity_interface(name = GenericIs)]
 impl<T> Generic<T> {
-	fn test_1(&self) -> Result<uint256> {
+	fn test_1(&self) -> Result<U256> {
 		unreachable!()
 	}
 }
 
 #[solidity_interface(name = Generic, is(GenericIs))]
 impl<T: Into<u32>> Generic<T> {
-	fn test_2(&self) -> Result<uint256> {
+	fn test_2(&self) -> Result<U256> {
 		unreachable!()
 	}
 }
@@ -40,7 +41,7 @@
 where
 	T: core::fmt::Debug,
 {
-	fn test_3(&self) -> Result<uint256> {
+	fn test_3(&self) -> Result<U256> {
 		unreachable!()
 	}
 }
modifiedcrates/evm-coder/tests/log.rsdiffbeforeafterboth
--- a/crates/evm-coder/tests/log.rs
+++ b/crates/evm-coder/tests/log.rs
@@ -17,19 +17,20 @@
 #![allow(dead_code)]
 
 use evm_coder::{ToLog, types::*};
+use primitive_types::U256;
 
 #[derive(ToLog)]
 enum ERC721Log {
 	Transfer {
 		#[indexed]
-		from: address,
+		from: Address,
 		#[indexed]
-		to: address,
-		value: uint256,
+		to: Address,
+		value: U256,
 	},
 	Eee {
 		#[indexed]
-		aaa: address,
-		bbb: uint256,
+		aaa: Address,
+		bbb: U256,
 	},
 }
modifiedcrates/evm-coder/tests/random.rsdiffbeforeafterboth
--- a/crates/evm-coder/tests/random.rs
+++ b/crates/evm-coder/tests/random.rs
@@ -19,19 +19,20 @@
 use evm_coder::{
 	abi::AbiType, ToLog, execution::Result, solidity_interface, types::*, solidity, weight,
 };
+use primitive_types::U256;
 
 pub struct Impls;
 
 #[solidity_interface(name = OurInterface)]
 impl Impls {
-	fn fn_a(&self, _input: uint256) -> Result<bool> {
+	fn fn_a(&self, _input: U256) -> Result<bool> {
 		unreachable!()
 	}
 }
 
 #[solidity_interface(name = OurInterface1)]
 impl Impls {
-	fn fn_b(&self, _input: uint128) -> Result<uint32> {
+	fn fn_b(&self, _input: u128) -> Result<u32> {
 		unreachable!()
 	}
 }
@@ -39,12 +40,12 @@
 #[derive(ToLog)]
 enum OurEvents {
 	Event1 {
-		field1: uint32,
+		field1: u32,
 	},
 	Event2 {
-		field1: uint32,
+		field1: u32,
 		#[indexed]
-		field2: uint32,
+		field2: u32,
 	},
 }
 
@@ -56,27 +57,27 @@
 )]
 impl Impls {
 	#[solidity(rename_selector = "fnK")]
-	fn fn_c(&self, _input: uint32) -> Result<uint8> {
+	fn fn_c(&self, _input: u32) -> Result<u8> {
 		unreachable!()
 	}
-	fn fn_d(&self, _value: uint32) -> Result<uint32> {
+	fn fn_d(&self, _value: u32) -> Result<u32> {
 		unreachable!()
 	}
 
-	fn caller_sensitive(&self, _caller: caller) -> Result<uint8> {
+	fn caller_sensitive(&self, _caller: Caller) -> Result<u8> {
 		unreachable!()
 	}
-	fn payable(&mut self, _value: value) -> Result<uint8> {
+	fn payable(&mut self, _value: Value) -> Result<u8> {
 		unreachable!()
 	}
 
 	#[weight(*_weight)]
-	fn with_weight(&self, _weight: uint64) -> Result<void> {
+	fn with_weight(&self, _weight: u64) -> Result<()> {
 		unreachable!()
 	}
 
 	/// Doccoment example
-	fn with_doc(&self) -> Result<void> {
+	fn with_doc(&self) -> Result<()> {
 		unreachable!()
 	}
 }
modifiedcrates/evm-coder/tests/solidity_generation.rsdiffbeforeafterboth
--- a/crates/evm-coder/tests/solidity_generation.rs
+++ b/crates/evm-coder/tests/solidity_generation.rs
@@ -15,34 +15,35 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 use evm_coder::{abi::AbiType, execution::Result, generate_stubgen, solidity_interface, types::*};
+use primitive_types::U256;
 
 pub struct ERC20;
 
 #[solidity_interface(name = ERC20)]
 impl ERC20 {
-	fn decimals(&self) -> Result<uint8> {
+	fn decimals(&self) -> Result<u8> {
 		unreachable!()
 	}
 	/// Get balance of specified owner
-	fn balance_of(&self, _owner: address) -> Result<uint256> {
+	fn balance_of(&self, _owner: Address) -> Result<U256> {
 		unreachable!()
 	}
-	fn transfer(&mut self, _caller: caller, _to: address, _value: uint256) -> Result<bool> {
+	fn transfer(&mut self, _caller: Caller, _to: Address, _value: U256) -> Result<bool> {
 		unreachable!()
 	}
 	fn transfer_from(
 		&mut self,
-		_caller: caller,
-		_from: address,
-		_to: address,
-		_value: uint256,
+		_caller: Caller,
+		_from: Address,
+		_to: Address,
+		_value: U256,
 	) -> Result<bool> {
 		unreachable!()
 	}
-	fn approve(&mut self, _caller: caller, _spender: address, _value: uint256) -> Result<bool> {
+	fn approve(&mut self, _caller: Caller, _spender: Address, _value: U256) -> Result<bool> {
 		unreachable!()
 	}
-	fn allowance(&self, _owner: address, _spender: address) -> Result<uint256> {
+	fn allowance(&self, _owner: Address, _spender: Address) -> Result<U256> {
 		unreachable!()
 	}
 }
modifiedpallets/common/src/erc.rsdiffbeforeafterboth
--- a/pallets/common/src/erc.rs
+++ b/pallets/common/src/erc.rs
@@ -26,6 +26,7 @@
 };
 use pallet_evm_coder_substrate::dispatch_to_evm;
 use sp_std::{vec, vec::Vec};
+use sp_core::U256;
 use up_data_structs::{
 	AccessMode, CollectionMode, CollectionPermissions, OwnerRestrictedSet, Property,
 	SponsoringRateLimit, SponsorshipState,
@@ -42,32 +43,32 @@
 	CollectionCreated {
 		/// Collection owner.
 		#[indexed]
-		owner: address,
+		owner: Address,
 
 		/// Collection ID.
 		#[indexed]
-		collection_id: address,
+		collection_id: Address,
 	},
 	/// The collection has been destroyed.
 	CollectionDestroyed {
 		/// Collection ID.
 		#[indexed]
-		collection_id: address,
+		collection_id: Address,
 	},
 	/// The collection has been changed.
 	CollectionChanged {
 		/// Collection ID.
 		#[indexed]
-		collection_id: address,
+		collection_id: Address,
 	},
 
 	/// The token has been changed.
 	TokenChanged {
 		/// Collection ID.
 		#[indexed]
-		collection_id: address,
+		collection_id: Address,
 		/// Token ID.
-		token_id: uint256,
+		token_id: U256,
 	},
 }
 
@@ -93,12 +94,7 @@
 	/// @param value Propery value.
 	#[solidity(hide)]
 	#[weight(<SelfWeightOf<T>>::set_collection_properties(1))]
-	fn set_collection_property(
-		&mut self,
-		caller: caller,
-		key: string,
-		value: bytes,
-	) -> Result<void> {
+	fn set_collection_property(&mut self, caller: Caller, key: String, value: Bytes) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let key = <Vec<u8>>::from(key)
 			.try_into()
@@ -115,9 +111,9 @@
 	#[weight(<SelfWeightOf<T>>::set_collection_properties(properties.len() as u32))]
 	fn set_collection_properties(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		properties: Vec<eth::Property>,
-	) -> Result<void> {
+	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 
 		let properties = properties
@@ -134,7 +130,7 @@
 	/// @param key Property key.
 	#[solidity(hide)]
 	#[weight(<SelfWeightOf<T>>::delete_collection_properties(1))]
-	fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {
+	fn delete_collection_property(&mut self, caller: Caller, key: String) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let key = <Vec<u8>>::from(key)
 			.try_into()
@@ -147,7 +143,7 @@
 	///
 	/// @param keys Properties keys.
 	#[weight(<SelfWeightOf<T>>::delete_collection_properties(keys.len() as u32))]
-	fn delete_collection_properties(&mut self, caller: caller, keys: Vec<string>) -> Result<()> {
+	fn delete_collection_properties(&mut self, caller: Caller, keys: Vec<String>) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let keys = keys
 			.into_iter()
@@ -168,7 +164,7 @@
 	///
 	/// @param key Property key.
 	/// @return bytes The property corresponding to the key.
-	fn collection_property(&self, key: string) -> Result<bytes> {
+	fn collection_property(&self, key: String) -> Result<Bytes> {
 		let key = <Vec<u8>>::from(key)
 			.try_into()
 			.map_err(|_| "key too large")?;
@@ -176,14 +172,14 @@
 		let props = CollectionProperties::<T>::get(self.id);
 		let prop = props.get(&key).ok_or("key not found")?;
 
-		Ok(bytes(prop.to_vec()))
+		Ok(Bytes(prop.to_vec()))
 	}
 
 	/// Get collection properties.
 	///
 	/// @param keys Properties keys. Empty keys for all propertyes.
 	/// @return Vector of properties key/value pairs.
-	fn collection_properties(&self, keys: Vec<string>) -> Result<Vec<eth::Property>> {
+	fn collection_properties(&self, keys: Vec<String>) -> Result<Vec<eth::Property>> {
 		let keys = keys
 			.into_iter()
 			.map(|key| {
@@ -212,7 +208,7 @@
 	///
 	/// @param sponsor Address of the sponsor from whose account funds will be debited for operations with the contract.
 	#[solidity(hide)]
-	fn set_collection_sponsor(&mut self, caller: caller, sponsor: address) -> Result<void> {
+	fn set_collection_sponsor(&mut self, caller: Caller, sponsor: Address) -> Result<()> {
 		self.consume_store_reads_and_writes(1, 1)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -229,9 +225,9 @@
 	/// @param sponsor Cross account address of the sponsor from whose account funds will be debited for operations with the contract.
 	fn set_collection_sponsor_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		sponsor: eth::CrossAddress,
-	) -> Result<void> {
+	) -> Result<()> {
 		self.consume_store_reads_and_writes(1, 1)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -252,7 +248,7 @@
 	/// Collection sponsorship confirmation.
 	///
 	/// @dev After setting the sponsor for the collection, it must be confirmed with this function.
-	fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {
+	fn confirm_collection_sponsorship(&mut self, caller: Caller) -> Result<()> {
 		self.consume_store_writes(1)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -261,7 +257,7 @@
 	}
 
 	/// Remove collection sponsor.
-	fn remove_collection_sponsor(&mut self, caller: caller) -> Result<void> {
+	fn remove_collection_sponsor(&mut self, caller: Caller) -> Result<()> {
 		self.consume_store_reads_and_writes(1, 1)?;
 		let caller = T::CrossAccountId::from_eth(caller);
 		self.remove_sponsor(&caller).map_err(dispatch_to_evm::<T>)
@@ -343,11 +339,7 @@
 	/// @dev Throws error if limit not found.
 	/// @param limit Some limit.
 	#[solidity(rename_selector = "setCollectionLimit")]
-	fn set_collection_limit(
-		&mut self,
-		caller: caller,
-		limit: eth::CollectionLimit,
-	) -> Result<void> {
+	fn set_collection_limit(&mut self, caller: Caller, limit: eth::CollectionLimit) -> Result<()> {
 		self.consume_store_reads_and_writes(1, 1)?;
 
 		if !limit.has_value() {
@@ -359,7 +351,7 @@
 	}
 
 	/// Get contract address.
-	fn contract_address(&self) -> Result<address> {
+	fn contract_address(&self) -> Result<Address> {
 		Ok(crate::eth::collection_id_to_address(self.id))
 	}
 
@@ -367,9 +359,9 @@
 	/// @param newAdmin Cross account administrator address.
 	fn add_collection_admin_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		new_admin: eth::CrossAddress,
-	) -> Result<void> {
+	) -> Result<()> {
 		self.consume_store_reads_and_writes(2, 2)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -382,9 +374,9 @@
 	/// @param admin Cross account administrator address.
 	fn remove_collection_admin_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		admin: eth::CrossAddress,
-	) -> Result<void> {
+	) -> Result<()> {
 		self.consume_store_reads_and_writes(2, 2)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -396,7 +388,7 @@
 	/// Add collection admin.
 	/// @param newAdmin Address of the added administrator.
 	#[solidity(hide)]
-	fn add_collection_admin(&mut self, caller: caller, new_admin: address) -> Result<void> {
+	fn add_collection_admin(&mut self, caller: Caller, new_admin: Address) -> Result<()> {
 		self.consume_store_reads_and_writes(2, 2)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -409,7 +401,7 @@
 	///
 	/// @param admin Address of the removed administrator.
 	#[solidity(hide)]
-	fn remove_collection_admin(&mut self, caller: caller, admin: address) -> Result<void> {
+	fn remove_collection_admin(&mut self, caller: Caller, admin: Address) -> Result<()> {
 		self.consume_store_reads_and_writes(2, 2)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -422,7 +414,7 @@
 	///
 	/// @param enable If "true" degenerates to nesting: 'Owner' else to nesting: 'Disabled'
 	#[solidity(rename_selector = "setCollectionNesting")]
-	fn set_nesting_bool(&mut self, caller: caller, enable: bool) -> Result<void> {
+	fn set_nesting_bool(&mut self, caller: Caller, enable: bool) -> Result<()> {
 		self.consume_store_reads_and_writes(1, 1)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -443,10 +435,10 @@
 	#[solidity(rename_selector = "setCollectionNesting")]
 	fn set_nesting(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		enable: bool,
-		collections: Vec<address>,
-	) -> Result<void> {
+		collections: Vec<Address>,
+	) -> Result<()> {
 		self.consume_store_reads_and_writes(1, 1)?;
 
 		if collections.is_empty() {
@@ -511,18 +503,12 @@
 	}
 	/// Set the collection access method.
 	/// @param mode Access mode
-	/// 	0 for Normal
-	/// 	1 for AllowList
-	fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result<void> {
+	fn set_collection_access(&mut self, caller: Caller, mode: eth::AccessMode) -> Result<()> {
 		self.consume_store_reads_and_writes(1, 1)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
 		let permissions = CollectionPermissions {
-			access: Some(match mode {
-				0 => AccessMode::Normal,
-				1 => AccessMode::AllowList,
-				_ => return Err("not supported access mode".into()),
-			}),
+			access: Some(mode.into()),
 			..Default::default()
 		};
 		<Pallet<T>>::update_permissions(&caller, self, permissions).map_err(dispatch_to_evm::<T>)
@@ -540,7 +526,7 @@
 	///
 	/// @param user Address of a trusted user.
 	#[solidity(hide)]
-	fn add_to_collection_allow_list(&mut self, caller: caller, user: address) -> Result<void> {
+	fn add_to_collection_allow_list(&mut self, caller: Caller, user: Address) -> Result<()> {
 		self.consume_store_writes(1)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -554,9 +540,9 @@
 	/// @param user User cross account address.
 	fn add_to_collection_allow_list_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		user: eth::CrossAddress,
-	) -> Result<void> {
+	) -> Result<()> {
 		self.consume_store_writes(1)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -569,7 +555,7 @@
 	///
 	/// @param user Address of a removed user.
 	#[solidity(hide)]
-	fn remove_from_collection_allow_list(&mut self, caller: caller, user: address) -> Result<void> {
+	fn remove_from_collection_allow_list(&mut self, caller: Caller, user: Address) -> Result<()> {
 		self.consume_store_writes(1)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -583,9 +569,9 @@
 	/// @param user User cross account address.
 	fn remove_from_collection_allow_list_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		user: eth::CrossAddress,
-	) -> Result<void> {
+	) -> Result<()> {
 		self.consume_store_writes(1)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -597,7 +583,7 @@
 	/// Switch permission for minting.
 	///
 	/// @param mode Enable if "true".
-	fn set_collection_mint_mode(&mut self, caller: caller, mode: bool) -> Result<void> {
+	fn set_collection_mint_mode(&mut self, caller: Caller, mode: bool) -> Result<()> {
 		self.consume_store_reads_and_writes(1, 1)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -613,7 +599,7 @@
 	/// @param user account to verify
 	/// @return "true" if account is the owner or admin
 	#[solidity(hide, rename_selector = "isOwnerOrAdmin")]
-	fn is_owner_or_admin_eth(&self, user: address) -> Result<bool> {
+	fn is_owner_or_admin_eth(&self, user: Address) -> Result<bool> {
 		let user = T::CrossAccountId::from_eth(user);
 		Ok(self.is_owner_or_admin(&user))
 	}
@@ -630,7 +616,7 @@
 	/// Returns collection type
 	///
 	/// @return `Fungible` or `NFT` or `ReFungible`
-	fn unique_collection_type(&self) -> Result<string> {
+	fn unique_collection_type(&self) -> Result<String> {
 		let mode = match self.collection.mode {
 			CollectionMode::Fungible(_) => "Fungible",
 			CollectionMode::NFT => "NFT",
@@ -654,7 +640,7 @@
 	/// @dev Owner can be changed only by current owner
 	/// @param newOwner new owner account
 	#[solidity(hide, rename_selector = "changeCollectionOwner")]
-	fn set_owner(&mut self, caller: caller, new_owner: address) -> Result<void> {
+	fn set_owner(&mut self, caller: Caller, new_owner: Address) -> Result<()> {
 		self.consume_store_writes(1)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -680,9 +666,9 @@
 	/// @param newOwner new owner cross account
 	fn change_collection_owner_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		new_owner: eth::CrossAddress,
-	) -> Result<void> {
+	) -> Result<()> {
 		self.consume_store_writes(1)?;
 
 		let caller = T::CrossAccountId::from_eth(caller);
modifiedpallets/common/src/eth.rsdiffbeforeafterboth
--- a/pallets/common/src/eth.rs
+++ b/pallets/common/src/eth.rs
@@ -18,12 +18,9 @@
 
 use alloc::format;
 use sp_std::{vec, vec::Vec};
-use evm_coder::{
-	AbiCoder,
-	types::{uint256, address},
-};
+use evm_coder::{AbiCoder, types::Address};
 pub use pallet_evm::{Config, account::CrossAccountId};
-use sp_core::H160;
+use sp_core::{H160, U256};
 use up_data_structs::CollectionId;
 
 // 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 1
@@ -33,7 +30,7 @@
 ];
 
 /// Maps the ethereum address of the collection in substrate.
-pub fn map_eth_to_id(eth: &H160) -> Option<CollectionId> {
+pub fn map_eth_to_id(eth: &Address) -> Option<CollectionId> {
 	if eth[0..16] != ETH_COLLECTION_PREFIX {
 		return None;
 	}
@@ -43,7 +40,7 @@
 }
 
 /// Maps the substrate collection id in ethereum.
-pub fn collection_id_to_address(id: CollectionId) -> H160 {
+pub fn collection_id_to_address(id: CollectionId) -> Address {
 	let mut out = [0; 20];
 	out[0..16].copy_from_slice(&ETH_COLLECTION_PREFIX);
 	out[16..20].copy_from_slice(&u32::to_be_bytes(id.0));
@@ -51,12 +48,12 @@
 }
 
 /// Check if the ethereum address is a collection.
-pub fn is_collection(address: &H160) -> bool {
+pub fn is_collection(address: &Address) -> bool {
 	address[0..16] == ETH_COLLECTION_PREFIX
 }
 
-/// Convert `uint256` to `CrossAccountId`.
-pub fn convert_uint256_to_cross_account<T: Config>(from: uint256) -> T::CrossAccountId
+/// Convert `U256` to `CrossAccountId`.
+pub fn convert_uint256_to_cross_account<T: Config>(from: U256) -> T::CrossAccountId
 where
 	T::AccountId: From<[u8; 32]>,
 {
@@ -69,8 +66,8 @@
 /// Cross account struct
 #[derive(Debug, Default, AbiCoder)]
 pub struct CrossAddress {
-	pub(crate) eth: address,
-	pub(crate) sub: uint256,
+	pub(crate) eth: Address,
+	pub(crate) sub: U256,
 }
 
 impl CrossAddress {
@@ -97,7 +94,7 @@
 	{
 		Self {
 			eth: Default::default(),
-			sub: uint256::from_big_endian(account_id.as_ref()),
+			sub: U256::from_big_endian(account_id.as_ref()),
 		}
 	}
 	/// Converts [`CrossAddress`] to `CrossAccountId`.
@@ -121,17 +118,17 @@
 /// Ethereum representation of collection [`PropertyKey`](up_data_structs::PropertyKey) and [`PropertyValue`](up_data_structs::PropertyValue).
 #[derive(Debug, Default, AbiCoder)]
 pub struct Property {
-	key: evm_coder::types::string,
-	value: evm_coder::types::bytes,
+	key: evm_coder::types::String,
+	value: evm_coder::types::Bytes,
 }
 
 impl TryFrom<up_data_structs::Property> for Property {
 	type Error = evm_coder::execution::Error;
 
 	fn try_from(from: up_data_structs::Property) -> Result<Self, Self::Error> {
-		let key = evm_coder::types::string::from_utf8(from.key.into())
+		let key = evm_coder::types::String::from_utf8(from.key.into())
 			.map_err(|e| Self::Error::Revert(format!("utf8 conversion error: {}", e)))?;
-		let value = evm_coder::types::bytes(from.value.to_vec());
+		let value = evm_coder::types::Bytes(from.value.to_vec());
 		Ok(Property { key, value })
 	}
 }
@@ -187,7 +184,7 @@
 #[derive(Debug, Default, AbiCoder)]
 pub struct CollectionLimit {
 	field: CollectionLimitField,
-	value: Option<uint256>,
+	value: Option<U256>,
 }
 
 impl CollectionLimit {
@@ -345,7 +342,7 @@
 #[derive(Debug, Default, AbiCoder)]
 pub struct TokenPropertyPermission {
 	/// Token property key.
-	key: evm_coder::types::string,
+	key: evm_coder::types::String,
 	/// Token property permissions.
 	permissions: Vec<PropertyPermission>,
 }
@@ -363,7 +360,7 @@
 		),
 	) -> Self {
 		let (key, permission) = value;
-		let key = evm_coder::types::string::from_utf8(key.into_inner())
+		let key = evm_coder::types::String::from_utf8(key.into_inner())
 			.expect("Stored key must be valid");
 		let permissions = PropertyPermission::into_vec(permission);
 		Self { key, permissions }
@@ -393,12 +390,12 @@
 #[derive(Debug, Default, AbiCoder)]
 pub struct CollectionNesting {
 	token_owner: bool,
-	ids: Vec<uint256>,
+	ids: Vec<U256>,
 }
 
 impl CollectionNesting {
 	/// Create [`CollectionNesting`].
-	pub fn new(token_owner: bool, ids: Vec<uint256>) -> Self {
+	pub fn new(token_owner: bool, ids: Vec<U256>) -> Self {
 		Self { token_owner, ids }
 	}
 }
@@ -416,3 +413,32 @@
 		Self { field, value }
 	}
 }
+
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+#[derive(AbiCoder, Copy, Clone, Default, Debug)]
+#[repr(u8)]
+pub enum AccessMode {
+	/// Access grant for owner and admins. Used as default.
+	#[default]
+	Normal,
+	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+	AllowList,
+}
+
+impl From<up_data_structs::AccessMode> for AccessMode {
+	fn from(value: up_data_structs::AccessMode) -> Self {
+		match value {
+			up_data_structs::AccessMode::Normal => AccessMode::Normal,
+			up_data_structs::AccessMode::AllowList => AccessMode::AllowList,
+		}
+	}
+}
+
+impl Into<up_data_structs::AccessMode> for AccessMode {
+	fn into(self) -> up_data_structs::AccessMode {
+		match self {
+			AccessMode::Normal => up_data_structs::AccessMode::Normal,
+			AccessMode::AllowList => up_data_structs::AccessMode::AllowList,
+		}
+	}
+}
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
before · pallets/common/src/lib.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//! # Common pallet18//!19//! The Common pallet provides functionality for handling collections.20//!21//! ## Overview22//!23//! The Common pallet provides an interface for common collection operations for different collection types24//! (see [CommonCollectionOperations]), as well as a generic dispatcher for these, see [dispatch] module.25//! It also provides this functionality to EVM, see [erc] and [eth] modules.26//!27//! The Common pallet provides functions for:28//!29//! - Setting and approving collection sponsor.30//! - Get\set\delete allow list.31//! - Get\set\delete collection properties.32//! - Get\set\delete collection property permissions.33//! - Get\set\delete token property permissions.34//! - Get\set\delete collection administrators.35//! - Checking access permissions.36//!37//! ### Terminology38//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will39//! be possible to mint tokens.40//!41//! **Allow list** - List of users who have the right to minting tokens.42//!43//! **Collection properties** - Collection properties are simply key-value stores where various44//! metadata can be placed.45//!46//! **Permissions on token properties** - For each property in the token can be set permission47//! to change, see [`PropertyPermission`].48//!49//! **Collection administrator** - For a collection, you can set administrators who have the right50//! to most actions on the collection.5152#![warn(missing_docs)]53#![cfg_attr(not(feature = "std"), no_std)]54extern crate alloc;5556use core::ops::{Deref, DerefMut};57use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};58use sp_std::vec::Vec;59use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};60use evm_coder::ToLog;61use frame_support::{62	dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},63	ensure,64	traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},65	dispatch::Pays,66	transactional,67};68use pallet_evm::GasWeightMapping;69use up_data_structs::{70	COLLECTION_NUMBER_LIMIT,71	Collection,72	RpcCollection,73	CollectionFlags,74	RpcCollectionFlags,75	CollectionId,76	CreateItemData,77	MAX_TOKEN_PREFIX_LENGTH,78	COLLECTION_ADMINS_LIMIT,79	TokenId,80	TokenChild,81	CollectionStats,82	MAX_TOKEN_OWNERSHIP,83	CollectionMode,84	NFT_SPONSOR_TRANSFER_TIMEOUT,85	FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,86	REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,87	MAX_SPONSOR_TIMEOUT,88	CUSTOM_DATA_LIMIT,89	CollectionLimits,90	CreateCollectionData,91	SponsorshipState,92	CreateItemExData,93	SponsoringRateLimit,94	budget::Budget,95	PhantomType,96	Property,97	Properties,98	PropertiesPermissionMap,99	PropertyKey,100	PropertyValue,101	PropertyPermission,102	PropertiesError,103	PropertyKeyPermission,104	TokenData,105	TrySetProperty,106	PropertyScope,107	// RMRK108	RmrkCollectionInfo,109	RmrkInstanceInfo,110	RmrkResourceInfo,111	RmrkPropertyInfo,112	RmrkBaseInfo,113	RmrkPartType,114	RmrkBoundedTheme,115	RmrkNftChild,116	CollectionPermissions,117};118use up_pov_estimate_rpc::PovInfo;119120pub use pallet::*;121use sp_core::H160;122use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};123#[cfg(feature = "runtime-benchmarks")]124pub mod benchmarking;125pub mod dispatch;126pub mod erc;127pub mod eth;128pub mod weights;129130/// Weight info.131pub type SelfWeightOf<T> = <T as Config>::WeightInfo;132133/// Collection handle contains information about collection data and id.134/// Also provides functionality to count consumed gas.135///136/// CollectionHandle is used as a generic wrapper for collections of all types.137/// It allows to perform common operations and queries on any collection type,138/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].139#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]140pub struct CollectionHandle<T: Config> {141	/// Collection id142	pub id: CollectionId,143	collection: Collection<T::AccountId>,144	/// Substrate recorder for counting consumed gas145	pub recorder: SubstrateRecorder<T>,146}147148impl<T: Config> WithRecorder<T> for CollectionHandle<T> {149	fn recorder(&self) -> &SubstrateRecorder<T> {150		&self.recorder151	}152	fn into_recorder(self) -> SubstrateRecorder<T> {153		self.recorder154	}155}156157impl<T: Config> CollectionHandle<T> {158	/// Same as [CollectionHandle::new] but with an explicit gas limit.159	pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {160		<CollectionById<T>>::get(id).map(|collection| Self {161			id,162			collection,163			recorder: SubstrateRecorder::new(gas_limit),164		})165	}166167	/// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].168	pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {169		<CollectionById<T>>::get(id).map(|collection| Self {170			id,171			collection,172			recorder,173		})174	}175176	/// Retrives collection data from storage and creates collection handle with default parameters.177	/// If collection not found return `None`178	pub fn new(id: CollectionId) -> Option<Self> {179		Self::new_with_gas_limit(id, u64::MAX)180	}181182	/// Same as [`CollectionHandle::new`] but if collection not found [CollectionNotFound](Error::CollectionNotFound) returned.183	pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {184		Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)185	}186187	/// Consume gas for reading.188	pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {189		self.recorder190			.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(191				<T as frame_system::Config>::DbWeight::get()192					.read193					.saturating_mul(reads),194			)))195	}196197	/// Consume gas for writing.198	pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {199		self.recorder200			.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(201				<T as frame_system::Config>::DbWeight::get()202					.write203					.saturating_mul(writes),204			)))205	}206207	/// Consume gas for reading and writing.208	pub fn consume_store_reads_and_writes(209		&self,210		reads: u64,211		writes: u64,212	) -> evm_coder::execution::Result<()> {213		let weight = <T as frame_system::Config>::DbWeight::get();214		let reads = weight.read.saturating_mul(reads);215		let writes = weight.read.saturating_mul(writes);216		self.recorder217			.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(218				reads.saturating_add(writes),219			)))220	}221222	/// Save collection to storage.223	pub fn save(&self) -> DispatchResult {224		<CollectionById<T>>::insert(self.id, &self.collection);225		Ok(())226	}227228	/// Set collection sponsor.229	///230	/// Unique collections allows sponsoring for certain actions.231	/// This method allows you to set the sponsor of the collection.232	/// In order for sponsorship to become active, it must be confirmed through [`Self::confirm_sponsorship`].233	pub fn set_sponsor(234		&mut self,235		sender: &T::CrossAccountId,236		sponsor: T::AccountId,237	) -> DispatchResult {238		self.check_is_internal()?;239		self.check_is_owner_or_admin(sender)?;240241		self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor.clone());242243		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(self.id, sponsor));244		<PalletEvm<T>>::deposit_log(245			erc::CollectionHelpersEvents::CollectionChanged {246				collection_id: eth::collection_id_to_address(self.id),247			}248			.to_log(T::ContractAddress::get()),249		);250251		self.save()252	}253254	/// Force set `sponsor`.255	///256	/// Differs from [`set_sponsor`][`Self::set_sponsor`] in that confirmation257	/// from the `sponsor` is not required.258	///259	/// # Arguments260	///261	/// * `sender`: Caller's account.262	/// * `sponsor`: ID of the account of the sponsor-to-be.263	pub fn force_set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {264		self.check_is_internal()?;265266		self.collection.sponsorship = SponsorshipState::Confirmed(sponsor.clone());267268		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(self.id, sponsor.clone()));269		<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(self.id, sponsor));270		<PalletEvm<T>>::deposit_log(271			erc::CollectionHelpersEvents::CollectionChanged {272				collection_id: eth::collection_id_to_address(self.id),273			}274			.to_log(T::ContractAddress::get()),275		);276277		self.save()278	}279280	/// Confirm sponsorship281	///282	/// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.283	/// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [`Self::set_sponsor`].284	pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> DispatchResult {285		self.check_is_internal()?;286		ensure!(287			self.collection.sponsorship.pending_sponsor() == Some(sender),288			Error::<T>::ConfirmSponsorshipFail289		);290291		self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());292293		<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(self.id, sender.clone()));294		<PalletEvm<T>>::deposit_log(295			erc::CollectionHelpersEvents::CollectionChanged {296				collection_id: eth::collection_id_to_address(self.id),297			}298			.to_log(T::ContractAddress::get()),299		);300301		self.save()302	}303304	/// Remove collection sponsor.305	pub fn remove_sponsor(&mut self, sender: &T::CrossAccountId) -> DispatchResult {306		self.check_is_internal()?;307		self.check_is_owner_or_admin(sender)?;308309		self.collection.sponsorship = SponsorshipState::Disabled;310311		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(self.id));312		<PalletEvm<T>>::deposit_log(313			erc::CollectionHelpersEvents::CollectionChanged {314				collection_id: eth::collection_id_to_address(self.id),315			}316			.to_log(T::ContractAddress::get()),317		);318		self.save()319	}320321	/// Force remove `sponsor`.322	///323	/// Differs from `remove_sponsor` in that324	/// it doesn't require consent from the `owner` of the collection.325	pub fn force_remove_sponsor(&mut self) -> DispatchResult {326		self.check_is_internal()?;327328		self.collection.sponsorship = SponsorshipState::Disabled;329330		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(self.id));331		<PalletEvm<T>>::deposit_log(332			erc::CollectionHelpersEvents::CollectionChanged {333				collection_id: eth::collection_id_to_address(self.id),334			}335			.to_log(T::ContractAddress::get()),336		);337		self.save()338	}339340	/// Checks that the collection was created with, and must be operated upon through **Unique API**.341	/// Now check only the `external` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.342	pub fn check_is_internal(&self) -> DispatchResult {343		if self.flags.external {344			return Err(<Error<T>>::CollectionIsExternal)?;345		}346347		Ok(())348	}349350	/// Checks that the collection was created with, and must be operated upon through an **assimilated API**.351	/// Now check only the `external` flag and if it's **false**, then return [`Error::CollectionIsInternal`] error.352	pub fn check_is_external(&self) -> DispatchResult {353		if !self.flags.external {354			return Err(<Error<T>>::CollectionIsInternal)?;355		}356357		Ok(())358	}359}360361impl<T: Config> Deref for CollectionHandle<T> {362	type Target = Collection<T::AccountId>;363364	fn deref(&self) -> &Self::Target {365		&self.collection366	}367}368369impl<T: Config> DerefMut for CollectionHandle<T> {370	fn deref_mut(&mut self) -> &mut Self::Target {371		&mut self.collection372	}373}374375impl<T: Config> CollectionHandle<T> {376	/// Checks if the `user` is the owner of the collection.377	pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {378		ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);379		Ok(())380	}381382	/// Returns **true** if the `user` is the owner or administrator of the collection.383	pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {384		*user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))385	}386387	/// Checks if the `user` is the owner or administrator of the collection.388	pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {389		ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);390		Ok(())391	}392393	/// Returns **true** if394	/// * the `user`is a collection owner or admin395	/// * the collection limits allow the owner/admins to transfer/burn any collection token396	pub fn ignores_token_restrictions(&self, user: &T::CrossAccountId) -> bool {397		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)398	}399400	/// Return **true** if `user` does not have enough token parts, and he can ignore such restrictions.401	pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {402		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)403	}404405	/// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.406	pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {407		ensure!(408			<Allowlist<T>>::get((self.id, user)),409			<Error<T>>::AddressNotInAllowlist410		);411		Ok(())412	}413414	/// Changes collection owner to another account415	/// #### Store read/writes416	/// 1 writes417	pub fn change_owner(418		&mut self,419		caller: T::CrossAccountId,420		new_owner: T::CrossAccountId,421	) -> DispatchResult {422		self.check_is_internal()?;423		self.check_is_owner(&caller)?;424		self.collection.owner = new_owner.as_sub().clone();425426		<Pallet<T>>::deposit_event(Event::<T>::CollectionOwnerChanged(427			self.id,428			new_owner.as_sub().clone(),429		));430		<PalletEvm<T>>::deposit_log(431			erc::CollectionHelpersEvents::CollectionChanged {432				collection_id: eth::collection_id_to_address(self.id),433			}434			.to_log(T::ContractAddress::get()),435		);436437		self.save()438	}439}440441#[frame_support::pallet]442pub mod pallet {443	use super::*;444	use dispatch::CollectionDispatch;445	use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};446	use frame_system::pallet_prelude::*;447	use frame_support::traits::Currency;448	use up_data_structs::{TokenId, mapping::TokenAddressMapping};449	use scale_info::TypeInfo;450	use weights::WeightInfo;451452	#[pallet::config]453	pub trait Config:454		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::Config + TypeInfo455	{456		/// Weight information for functions of this pallet.457		type WeightInfo: WeightInfo;458459		/// Events compatible with [`frame_system::Config::Event`].460		type RuntimeEvent: IsType<<Self as frame_system::Config>::RuntimeEvent> + From<Event<Self>>;461462		/// Handler of accounts and payment.463		type Currency: Currency<Self::AccountId>;464465		/// Set price to create a collection.466		#[pallet::constant]467		type CollectionCreationPrice: Get<468			<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,469		>;470471		/// Dispatcher of operations on collections.472		type CollectionDispatch: CollectionDispatch<Self>;473474		/// Account which holds the chain's treasury.475		type TreasuryAccountId: Get<Self::AccountId>;476477		/// Address under which the CollectionHelper contract would be available.478		#[pallet::constant]479		type ContractAddress: Get<H160>;480481		/// Mapper for token addresses to Ethereum addresses.482		type EvmTokenAddressMapping: TokenAddressMapping<H160>;483484		/// Mapper for token addresses to [`CrossAccountId`].485		type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;486	}487488	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);489490	#[pallet::pallet]491	#[pallet::storage_version(STORAGE_VERSION)]492	#[pallet::generate_store(pub(super) trait Store)]493	pub struct Pallet<T>(_);494495	#[pallet::extra_constants]496	impl<T: Config> Pallet<T> {497		/// Maximum admins per collection.498		pub fn collection_admins_limit() -> u32 {499			COLLECTION_ADMINS_LIMIT500		}501	}502503	#[pallet::event]504	#[pallet::generate_deposit(pub fn deposit_event)]505	pub enum Event<T: Config> {506		/// New collection was created507		CollectionCreated(508			/// Globally unique identifier of newly created collection.509			CollectionId,510			/// [`CollectionMode`] converted into _u8_.511			u8,512			/// Collection owner.513			T::AccountId,514		),515516		/// New collection was destroyed517		CollectionDestroyed(518			/// Globally unique identifier of collection.519			CollectionId,520		),521522		/// New item was created.523		ItemCreated(524			/// Id of the collection where item was created.525			CollectionId,526			/// Id of an item. Unique within the collection.527			TokenId,528			/// Owner of newly created item529			T::CrossAccountId,530			/// Always 1 for NFT531			u128,532		),533534		/// Collection item was burned.535		ItemDestroyed(536			/// Id of the collection where item was destroyed.537			CollectionId,538			/// Identifier of burned NFT.539			TokenId,540			/// Which user has destroyed its tokens.541			T::CrossAccountId,542			/// Amount of token pieces destroed. Always 1 for NFT.543			u128,544		),545546		/// Item was transferred547		Transfer(548			/// Id of collection to which item is belong.549			CollectionId,550			/// Id of an item.551			TokenId,552			/// Original owner of item.553			T::CrossAccountId,554			/// New owner of item.555			T::CrossAccountId,556			/// Amount of token pieces transfered. Always 1 for NFT.557			u128,558		),559560		/// Amount pieces of token owned by `sender` was approved for `spender`.561		Approved(562			/// Id of collection to which item is belong.563			CollectionId,564			/// Id of an item.565			TokenId,566			/// Original owner of item.567			T::CrossAccountId,568			/// Id for which the approval was granted.569			T::CrossAccountId,570			/// Amount of token pieces transfered. Always 1 for NFT.571			u128,572		),573574		/// A `sender` approves operations on all owned tokens for `spender`.575		ApprovedForAll(576			/// Id of collection to which item is belong.577			CollectionId,578			/// Owner of a wallet.579			T::CrossAccountId,580			/// Id for which operator status was granted or rewoked.581			T::CrossAccountId,582			/// Is operator status granted or revoked?583			bool,584		),585586		/// The colletion property has been added or edited.587		CollectionPropertySet(588			/// Id of collection to which property has been set.589			CollectionId,590			/// The property that was set.591			PropertyKey,592		),593594		/// The property has been deleted.595		CollectionPropertyDeleted(596			/// Id of collection to which property has been deleted.597			CollectionId,598			/// The property that was deleted.599			PropertyKey,600		),601602		/// The token property has been added or edited.603		TokenPropertySet(604			/// Identifier of the collection whose token has the property set.605			CollectionId,606			/// The token for which the property was set.607			TokenId,608			/// The property that was set.609			PropertyKey,610		),611612		/// The token property has been deleted.613		TokenPropertyDeleted(614			/// Identifier of the collection whose token has the property deleted.615			CollectionId,616			/// The token for which the property was deleted.617			TokenId,618			/// The property that was deleted.619			PropertyKey,620		),621622		/// The token property permission of a collection has been set.623		PropertyPermissionSet(624			/// ID of collection to which property permission has been set.625			CollectionId,626			/// The property permission that was set.627			PropertyKey,628		),629630		/// Address was added to the allow list.631		AllowListAddressAdded(632			/// ID of the affected collection.633			CollectionId,634			/// Address of the added account.635			T::CrossAccountId,636		),637638		/// Address was removed from the allow list.639		AllowListAddressRemoved(640			/// ID of the affected collection.641			CollectionId,642			/// Address of the removed account.643			T::CrossAccountId,644		),645646		/// Collection admin was added.647		CollectionAdminAdded(648			/// ID of the affected collection.649			CollectionId,650			/// Admin address.651			T::CrossAccountId,652		),653654		/// Collection admin was removed.655		CollectionAdminRemoved(656			/// ID of the affected collection.657			CollectionId,658			/// Removed admin address.659			T::CrossAccountId,660		),661662		/// Collection limits were set.663		CollectionLimitSet(664			/// ID of the affected collection.665			CollectionId,666		),667668		/// Collection owned was changed.669		CollectionOwnerChanged(670			/// ID of the affected collection.671			CollectionId,672			/// New owner address.673			T::AccountId,674		),675676		/// Collection permissions were set.677		CollectionPermissionSet(678			/// ID of the affected collection.679			CollectionId,680		),681682		/// Collection sponsor was set.683		CollectionSponsorSet(684			/// ID of the affected collection.685			CollectionId,686			/// New sponsor address.687			T::AccountId,688		),689690		/// New sponsor was confirm.691		SponsorshipConfirmed(692			/// ID of the affected collection.693			CollectionId,694			/// New sponsor address.695			T::AccountId,696		),697698		/// Collection sponsor was removed.699		CollectionSponsorRemoved(700			/// ID of the affected collection.701			CollectionId,702		),703	}704705	#[pallet::error]706	pub enum Error<T> {707		/// This collection does not exist.708		CollectionNotFound,709		/// Sender parameter and item owner must be equal.710		MustBeTokenOwner,711		/// No permission to perform action712		NoPermission,713		/// Destroying only empty collections is allowed714		CantDestroyNotEmptyCollection,715		/// Collection is not in mint mode.716		PublicMintingNotAllowed,717		/// Address is not in allow list.718		AddressNotInAllowlist,719720		/// Collection name can not be longer than 63 char.721		CollectionNameLimitExceeded,722		/// Collection description can not be longer than 255 char.723		CollectionDescriptionLimitExceeded,724		/// Token prefix can not be longer than 15 char.725		CollectionTokenPrefixLimitExceeded,726		/// Total collections bound exceeded.727		TotalCollectionsLimitExceeded,728		/// Exceeded max admin count729		CollectionAdminCountExceeded,730		/// Collection limit bounds per collection exceeded731		CollectionLimitBoundsExceeded,732		/// Tried to enable permissions which are only permitted to be disabled733		OwnerPermissionsCantBeReverted,734		/// Collection settings not allowing items transferring735		TransferNotAllowed,736		/// Account token limit exceeded per collection737		AccountTokenLimitExceeded,738		/// Collection token limit exceeded739		CollectionTokenLimitExceeded,740		/// Metadata flag frozen741		MetadataFlagFrozen,742743		/// Item does not exist744		TokenNotFound,745		/// Item is balance not enough746		TokenValueTooLow,747		/// Requested value is more than the approved748		ApprovedValueTooLow,749		/// Tried to approve more than owned750		CantApproveMoreThanOwned,751		/// Only spending from eth mirror could be approved752		AddressIsNotEthMirror,753754		/// Can't transfer tokens to ethereum zero address755		AddressIsZero,756757		/// The operation is not supported758		UnsupportedOperation,759760		/// Insufficient funds to perform an action761		NotSufficientFounds,762763		/// User does not satisfy the nesting rule764		UserIsNotAllowedToNest,765		/// Only tokens from specific collections may nest tokens under this one766		SourceCollectionIsNotAllowedToNest,767768		/// Tried to store more data than allowed in collection field769		CollectionFieldSizeExceeded,770771		/// Tried to store more property data than allowed772		NoSpaceForProperty,773774		/// Tried to store more property keys than allowed775		PropertyLimitReached,776777		/// Property key is too long778		PropertyKeyIsTooLong,779780		/// Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed781		InvalidCharacterInPropertyKey,782783		/// Empty property keys are forbidden784		EmptyPropertyKey,785786		/// Tried to access an external collection with an internal API787		CollectionIsExternal,788789		/// Tried to access an internal collection with an external API790		CollectionIsInternal,791792		/// This address is not set as sponsor, use setCollectionSponsor first.793		ConfirmSponsorshipFail,794795		/// The user is not an administrator.796		UserIsNotCollectionAdmin,797	}798799	/// Storage of the count of created collections. Essentially contains the last collection ID.800	#[pallet::storage]801	pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;802803	/// Storage of the count of deleted collections.804	#[pallet::storage]805	pub type DestroyedCollectionCount<T> =806		StorageValue<Value = CollectionId, QueryKind = ValueQuery>;807808	/// Storage of collection info.809	#[pallet::storage]810	pub type CollectionById<T> = StorageMap<811		Hasher = Blake2_128Concat,812		Key = CollectionId,813		Value = Collection<<T as frame_system::Config>::AccountId>,814		QueryKind = OptionQuery,815	>;816817	/// Storage of collection properties.818	#[pallet::storage]819	#[pallet::getter(fn collection_properties)]820	pub type CollectionProperties<T> = StorageMap<821		Hasher = Blake2_128Concat,822		Key = CollectionId,823		Value = Properties,824		QueryKind = ValueQuery,825		OnEmpty = up_data_structs::CollectionProperties,826	>;827828	/// Storage of token property permissions of a collection.829	#[pallet::storage]830	#[pallet::getter(fn property_permissions)]831	pub type CollectionPropertyPermissions<T> = StorageMap<832		Hasher = Blake2_128Concat,833		Key = CollectionId,834		Value = PropertiesPermissionMap,835		QueryKind = ValueQuery,836	>;837838	/// Storage of the amount of collection admins.839	#[pallet::storage]840	pub type AdminAmount<T> = StorageMap<841		Hasher = Blake2_128Concat,842		Key = CollectionId,843		Value = u32,844		QueryKind = ValueQuery,845	>;846847	/// List of collection admins.848	#[pallet::storage]849	pub type IsAdmin<T: Config> = StorageNMap<850		Key = (851			Key<Blake2_128Concat, CollectionId>,852			Key<Blake2_128Concat, T::CrossAccountId>,853		),854		Value = bool,855		QueryKind = ValueQuery,856	>;857858	/// Allowlisted collection users.859	#[pallet::storage]860	pub type Allowlist<T: Config> = StorageNMap<861		Key = (862			Key<Blake2_128Concat, CollectionId>,863			Key<Blake2_128Concat, T::CrossAccountId>,864		),865		Value = bool,866		QueryKind = ValueQuery,867	>;868869	/// Not used by code, exists only to provide some types to metadata.870	#[pallet::storage]871	pub type DummyStorageValue<T: Config> = StorageValue<872		Value = (873			CollectionStats,874			CollectionId,875			TokenId,876			TokenChild,877			PhantomType<(878				TokenData<T::CrossAccountId>,879				RpcCollection<T::AccountId>,880				// RMRK881				RmrkCollectionInfo<T::AccountId>,882				RmrkInstanceInfo<T::AccountId>,883				RmrkResourceInfo,884				RmrkPropertyInfo,885				RmrkBaseInfo<T::AccountId>,886				RmrkPartType,887				RmrkBoundedTheme,888				RmrkNftChild,889				// PoV Estimate Info890				PovInfo,891			)>,892		),893		QueryKind = OptionQuery,894	>;895896	#[pallet::hooks]897	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {898		fn on_runtime_upgrade() -> Weight {899			StorageVersion::new(1).put::<Pallet<T>>();900901			Weight::zero()902		}903	}904}905906impl<T: Config> Pallet<T> {907	/// Enshure that receiver address is correct.908	///909	/// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.910	pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {911		ensure!(912			&T::CrossAccountId::from_eth(H160([0; 20])) != receiver,913			<Error<T>>::AddressIsZero914		);915		Ok(())916	}917918	/// Get a vector of collection admins.919	pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {920		<IsAdmin<T>>::iter_prefix((collection,))921			.map(|(a, _)| a)922			.collect()923	}924925	/// Get a vector of users allowed to mint tokens.926	pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {927		<Allowlist<T>>::iter_prefix((collection,))928			.map(|(a, _)| a)929			.collect()930	}931932	/// Is `user` allowed to mint token in `collection`.933	pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {934		<Allowlist<T>>::get((collection, user))935	}936937	/// Get statistics of collections.938	pub fn collection_stats() -> CollectionStats {939		let created = <CreatedCollectionCount<T>>::get();940		let destroyed = <DestroyedCollectionCount<T>>::get();941		CollectionStats {942			created: created.0,943			destroyed: destroyed.0,944			alive: created.0 - destroyed.0,945		}946	}947948	/// Get the effective limits for the collection.949	pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {950		let collection = <CollectionById<T>>::get(collection)?;951		let limits = collection.limits;952		let effective_limits = CollectionLimits {953			account_token_ownership_limit: Some(limits.account_token_ownership_limit()),954			sponsored_data_size: Some(limits.sponsored_data_size()),955			sponsored_data_rate_limit: Some(956				limits957					.sponsored_data_rate_limit958					.unwrap_or(SponsoringRateLimit::SponsoringDisabled),959			),960			token_limit: Some(limits.token_limit()),961			sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(962				match collection.mode {963					CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,964					CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,965					CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,966				},967			)),968			sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),969			owner_can_transfer: Some(limits.owner_can_transfer()),970			owner_can_destroy: Some(limits.owner_can_destroy()),971			transfers_enabled: Some(limits.transfers_enabled()),972		};973974		Some(effective_limits)975	}976977	/// Returns information about the `collection` adapted for rpc.978	pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {979		let Collection {980			name,981			description,982			owner,983			mode,984			token_prefix,985			sponsorship,986			limits,987			permissions,988			flags,989		} = <CollectionById<T>>::get(collection)?;990991		let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)992			.into_iter()993			.map(|(key, permission)| PropertyKeyPermission { key, permission })994			.collect();995996		let properties = <CollectionProperties<T>>::get(collection)997			.into_iter()998			.map(|(key, value)| Property { key, value })999			.collect();10001001		let permissions = CollectionPermissions {1002			access: Some(permissions.access()),1003			mint_mode: Some(permissions.mint_mode()),1004			nesting: Some(permissions.nesting().clone()),1005		};10061007		Some(RpcCollection {1008			name: name.into_inner(),1009			description: description.into_inner(),1010			owner,1011			mode,1012			token_prefix: token_prefix.into_inner(),1013			sponsorship,1014			limits,1015			permissions,1016			token_property_permissions,1017			properties,1018			read_only: flags.external,10191020			flags: RpcCollectionFlags {1021				foreign: flags.foreign,1022				erc721metadata: flags.erc721metadata,1023			},1024		})1025	}1026}10271028macro_rules! limit_default {1029	($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1030		$(1031			if let Some($new) = $new.$field {1032				let $old = $old.$field($($arg)?);1033				let _ = $new;1034				let _ = $old;1035				$check1036			} else {1037				$new.$field = $old.$field1038			}1039		)*1040	}};1041}1042macro_rules! limit_default_clone {1043	($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1044		$(1045			if let Some($new) = $new.$field.clone() {1046				let $old = $old.$field($($arg)?);1047				let _ = $new;1048				let _ = $old;1049				$check1050			} else {1051				$new.$field = $old.$field.clone()1052			}1053		)*1054	}};1055}10561057impl<T: Config> Pallet<T> {1058	/// Create new collection.1059	///1060	/// * `owner` - The owner of the collection.1061	/// * `data` - Description of the created collection.1062	/// * `flags` - Extra flags to store.1063	pub fn init_collection(1064		owner: T::CrossAccountId,1065		payer: T::CrossAccountId,1066		data: CreateCollectionData<T::AccountId>,1067		flags: CollectionFlags,1068	) -> Result<CollectionId, DispatchError> {1069		{1070			ensure!(1071				data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,1072				Error::<T>::CollectionTokenPrefixLimitExceeded1073			);1074		}10751076		let created_count = <CreatedCollectionCount<T>>::get()1077			.01078			.checked_add(1)1079			.ok_or(ArithmeticError::Overflow)?;1080		let destroyed_count = <DestroyedCollectionCount<T>>::get().0;1081		let id = CollectionId(created_count);10821083		// bound Total number of collections1084		ensure!(1085			created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,1086			<Error<T>>::TotalCollectionsLimitExceeded1087		);10881089		// =========10901091		let collection = Collection {1092			owner: owner.as_sub().clone(),1093			name: data.name,1094			mode: data.mode.clone(),1095			description: data.description,1096			token_prefix: data.token_prefix,1097			sponsorship: data1098				.pending_sponsor1099				.map(SponsorshipState::Unconfirmed)1100				.unwrap_or_default(),1101			limits: data1102				.limits1103				.map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))1104				.unwrap_or_else(|| Ok(CollectionLimits::default()))?,1105			permissions: data1106				.permissions1107				.map(|permissions| {1108					Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)1109				})1110				.unwrap_or_else(|| Ok(CollectionPermissions::default()))?,1111			flags,1112		};11131114		let mut collection_properties = up_data_structs::CollectionProperties::get();1115		collection_properties1116			.try_set_from_iter(data.properties.into_iter())1117			.map_err(<Error<T>>::from)?;11181119		CollectionProperties::<T>::insert(id, collection_properties);11201121		let mut token_props_permissions = PropertiesPermissionMap::new();1122		token_props_permissions1123			.try_set_from_iter(data.token_property_permissions.into_iter())1124			.map_err(<Error<T>>::from)?;11251126		CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);11271128		// Take a (non-refundable) deposit of collection creation1129		{1130			let mut imbalance =1131				<<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();1132			imbalance.subsume(1133				<<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(1134					&T::TreasuryAccountId::get(),1135					T::CollectionCreationPrice::get(),1136				),1137			);1138			<T as Config>::Currency::settle(1139				payer.as_sub(),1140				imbalance,1141				WithdrawReasons::TRANSFER,1142				ExistenceRequirement::KeepAlive,1143			)1144			.map_err(|_| Error::<T>::NotSufficientFounds)?;1145		}11461147		<CreatedCollectionCount<T>>::put(created_count);1148		<Pallet<T>>::deposit_event(Event::CollectionCreated(1149			id,1150			data.mode.id(),1151			owner.as_sub().clone(),1152		));1153		<PalletEvm<T>>::deposit_log(1154			erc::CollectionHelpersEvents::CollectionCreated {1155				owner: *owner.as_eth(),1156				collection_id: eth::collection_id_to_address(id),1157			}1158			.to_log(T::ContractAddress::get()),1159		);1160		<CollectionById<T>>::insert(id, collection);1161		Ok(id)1162	}11631164	/// Destroy collection.1165	///1166	/// * `collection` - Collection handler.1167	/// * `sender` - The owner or administrator of the collection.1168	pub fn destroy_collection(1169		collection: CollectionHandle<T>,1170		sender: &T::CrossAccountId,1171	) -> DispatchResult {1172		ensure!(1173			collection.limits.owner_can_destroy(),1174			<Error<T>>::NoPermission,1175		);1176		collection.check_is_owner(sender)?;11771178		let destroyed_collections = <DestroyedCollectionCount<T>>::get()1179			.01180			.checked_add(1)1181			.ok_or(ArithmeticError::Overflow)?;11821183		// =========11841185		<DestroyedCollectionCount<T>>::put(destroyed_collections);1186		<CollectionById<T>>::remove(collection.id);1187		<AdminAmount<T>>::remove(collection.id);1188		let _ = <IsAdmin<T>>::clear_prefix((collection.id,), u32::MAX, None);1189		let _ = <Allowlist<T>>::clear_prefix((collection.id,), u32::MAX, None);1190		<CollectionProperties<T>>::remove(collection.id);11911192		<Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));11931194		<PalletEvm<T>>::deposit_log(1195			erc::CollectionHelpersEvents::CollectionDestroyed {1196				collection_id: eth::collection_id_to_address(collection.id),1197			}1198			.to_log(T::ContractAddress::get()),1199		);1200		Ok(())1201	}12021203	/// This function sets or removes a collection properties according to1204	/// `properties_updates` contents:1205	/// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`1206	/// * removes a property under the <key> if the value is `None` `(<key>, None)`.1207	///1208	/// This function fires an event for each property change.1209	/// In case of an error, all the changes (including the events) will be reverted1210	/// since the function is transactional.1211	#[transactional]1212	fn modify_collection_properties(1213		collection: &CollectionHandle<T>,1214		sender: &T::CrossAccountId,1215		properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,1216	) -> DispatchResult {1217		collection.check_is_owner_or_admin(sender)?;12181219		let mut stored_properties = <CollectionProperties<T>>::get(collection.id);12201221		for (key, value) in properties_updates {1222			match value {1223				Some(value) => {1224					stored_properties1225						.try_set(key.clone(), value)1226						.map_err(<Error<T>>::from)?;12271228					Self::deposit_event(Event::CollectionPropertySet(collection.id, key));1229					<PalletEvm<T>>::deposit_log(1230						erc::CollectionHelpersEvents::CollectionChanged {1231							collection_id: eth::collection_id_to_address(collection.id),1232						}1233						.to_log(T::ContractAddress::get()),1234					);1235				}1236				None => {1237					stored_properties.remove(&key).map_err(<Error<T>>::from)?;12381239					Self::deposit_event(Event::CollectionPropertyDeleted(collection.id, key));1240					<PalletEvm<T>>::deposit_log(1241						erc::CollectionHelpersEvents::CollectionChanged {1242							collection_id: eth::collection_id_to_address(collection.id),1243						}1244						.to_log(T::ContractAddress::get()),1245					);1246				}1247			}1248		}12491250		<CollectionProperties<T>>::set(collection.id, stored_properties);12511252		Ok(())1253	}12541255	/// Set collection property.1256	///1257	/// * `collection` - Collection handler.1258	/// * `sender` - The owner or administrator of the collection.1259	/// * `property` - The property to set.1260	pub fn set_collection_property(1261		collection: &CollectionHandle<T>,1262		sender: &T::CrossAccountId,1263		property: Property,1264	) -> DispatchResult {1265		Self::set_collection_properties(collection, sender, [property].into_iter())1266	}12671268	/// Set a scoped collection property, where the scope is a special prefix1269	/// prohibiting a user access to change the property directly.1270	///1271	/// * `collection_id` - ID of the collection for which the property is being set.1272	/// * `scope` - Property scope.1273	/// * `property` - The property to set.1274	pub fn set_scoped_collection_property(1275		collection_id: CollectionId,1276		scope: PropertyScope,1277		property: Property,1278	) -> DispatchResult {1279		CollectionProperties::<T>::try_mutate(collection_id, |properties| {1280			properties.try_scoped_set(scope, property.key, property.value)1281		})1282		.map_err(<Error<T>>::from)?;12831284		Ok(())1285	}12861287	/// Set scoped collection properties, where the scope is a special prefix1288	/// prohibiting a user access to change the properties directly.1289	///1290	/// * `collection_id` - ID of the collection for which the properties is being set.1291	/// * `scope` - Property scope.1292	/// * `properties` - The properties to set.1293	pub fn set_scoped_collection_properties(1294		collection_id: CollectionId,1295		scope: PropertyScope,1296		properties: impl Iterator<Item = Property>,1297	) -> DispatchResult {1298		CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {1299			stored_properties.try_scoped_set_from_iter(scope, properties)1300		})1301		.map_err(<Error<T>>::from)?;13021303		Ok(())1304	}13051306	/// Set collection properties.1307	///1308	/// * `collection` - Collection handler.1309	/// * `sender` - The owner or administrator of the collection.1310	/// * `properties` - The properties to set.1311	pub fn set_collection_properties(1312		collection: &CollectionHandle<T>,1313		sender: &T::CrossAccountId,1314		properties: impl Iterator<Item = Property>,1315	) -> DispatchResult {1316		Self::modify_collection_properties(1317			collection,1318			sender,1319			properties.map(|property| (property.key, Some(property.value))),1320		)1321	}13221323	/// Delete collection property.1324	///1325	/// * `collection` - Collection handler.1326	/// * `sender` - The owner or administrator of the collection.1327	/// * `property` - The property to delete.1328	pub fn delete_collection_property(1329		collection: &CollectionHandle<T>,1330		sender: &T::CrossAccountId,1331		property_key: PropertyKey,1332	) -> DispatchResult {1333		Self::delete_collection_properties(collection, sender, [property_key].into_iter())1334	}13351336	/// Delete collection properties.1337	///1338	/// * `collection` - Collection handler.1339	/// * `sender` - The owner or administrator of the collection.1340	/// * `properties` - The properties to delete.1341	pub fn delete_collection_properties(1342		collection: &CollectionHandle<T>,1343		sender: &T::CrossAccountId,1344		property_keys: impl Iterator<Item = PropertyKey>,1345	) -> DispatchResult {1346		Self::modify_collection_properties(collection, sender, property_keys.map(|key| (key, None)))1347	}13481349	/// Set collection propetry permission without any checks.1350	///1351	/// Used for migrations.1352	///1353	/// * `collection` - Collection handler.1354	/// * `property_permissions` - Property permissions.1355	pub fn set_property_permission_unchecked(1356		collection: CollectionId,1357		property_permission: PropertyKeyPermission,1358	) -> DispatchResult {1359		<CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {1360			permissions.try_set(property_permission.key, property_permission.permission)1361		})1362		.map_err(<Error<T>>::from)?;1363		Ok(())1364	}13651366	/// Set collection property permission.1367	///1368	/// * `collection` - Collection handler.1369	/// * `sender` - The owner or administrator of the collection.1370	/// * `property_permission` - Property permission.1371	pub fn set_property_permission(1372		collection: &CollectionHandle<T>,1373		sender: &T::CrossAccountId,1374		property_permission: PropertyKeyPermission,1375	) -> DispatchResult {1376		Self::set_scoped_property_permission(1377			collection,1378			sender,1379			PropertyScope::None,1380			property_permission,1381		)1382	}13831384	/// Set collection property permission with scope.1385	///1386	/// * `collection` - Collection handler.1387	/// * `sender` - The owner or administrator of the collection.1388	/// * `scope` - Property scope.1389	/// * `property_permission` - Property permission.1390	pub fn set_scoped_property_permission(1391		collection: &CollectionHandle<T>,1392		sender: &T::CrossAccountId,1393		scope: PropertyScope,1394		property_permission: PropertyKeyPermission,1395	) -> DispatchResult {1396		collection.check_is_owner_or_admin(sender)?;13971398		let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);1399		let current_permission = all_permissions.get(&property_permission.key);1400		if matches![1401			current_permission,1402			Some(PropertyPermission { mutable: false, .. })1403		] {1404			return Err(<Error<T>>::NoPermission.into());1405		}14061407		CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {1408			let property_permission = property_permission.clone();1409			permissions.try_scoped_set(1410				scope,1411				property_permission.key,1412				property_permission.permission,1413			)1414		})1415		.map_err(<Error<T>>::from)?;14161417		Self::deposit_event(Event::PropertyPermissionSet(1418			collection.id,1419			property_permission.key,1420		));1421		<PalletEvm<T>>::deposit_log(1422			erc::CollectionHelpersEvents::CollectionChanged {1423				collection_id: eth::collection_id_to_address(collection.id),1424			}1425			.to_log(T::ContractAddress::get()),1426		);14271428		Ok(())1429	}14301431	/// Set token property permission.1432	///1433	/// * `collection` - Collection handler.1434	/// * `sender` - The owner or administrator of the collection.1435	/// * `property_permissions` - Property permissions.1436	#[transactional]1437	pub fn set_token_property_permissions(1438		collection: &CollectionHandle<T>,1439		sender: &T::CrossAccountId,1440		property_permissions: Vec<PropertyKeyPermission>,1441	) -> DispatchResult {1442		Self::set_scoped_token_property_permissions(1443			collection,1444			sender,1445			PropertyScope::None,1446			property_permissions,1447		)1448	}14491450	/// Set token property permission with scope.1451	///1452	/// * `collection` - Collection handler.1453	/// * `sender` - The owner or administrator of the collection.1454	/// * `scope` - Property scope.1455	/// * `property_permissions` - Property permissions.1456	#[transactional]1457	pub fn set_scoped_token_property_permissions(1458		collection: &CollectionHandle<T>,1459		sender: &T::CrossAccountId,1460		scope: PropertyScope,1461		property_permissions: Vec<PropertyKeyPermission>,1462	) -> DispatchResult {1463		for prop_pemission in property_permissions {1464			Self::set_scoped_property_permission(collection, sender, scope, prop_pemission)?;1465		}14661467		Ok(())1468	}14691470	/// Get collection property.1471	pub fn get_collection_property(1472		collection_id: CollectionId,1473		key: &PropertyKey,1474	) -> Option<PropertyValue> {1475		Self::collection_properties(collection_id).get(key).cloned()1476	}14771478	/// Convert byte vector to property key vector.1479	pub fn bytes_keys_to_property_keys(1480		keys: Vec<Vec<u8>>,1481	) -> Result<Vec<PropertyKey>, DispatchError> {1482		keys.into_iter()1483			.map(|key| -> Result<PropertyKey, DispatchError> {1484				key.try_into()1485					.map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1486			})1487			.collect::<Result<Vec<PropertyKey>, DispatchError>>()1488	}14891490	/// Get properties according to given keys.1491	pub fn filter_collection_properties(1492		collection_id: CollectionId,1493		keys: Option<Vec<PropertyKey>>,1494	) -> Result<Vec<Property>, DispatchError> {1495		let properties = Self::collection_properties(collection_id);14961497		let properties = keys1498			.map(|keys| {1499				keys.into_iter()1500					.filter_map(|key| {1501						properties.get(&key).map(|value| Property {1502							key,1503							value: value.clone(),1504						})1505					})1506					.collect()1507			})1508			.unwrap_or_else(|| {1509				properties1510					.into_iter()1511					.map(|(key, value)| Property { key, value })1512					.collect()1513			});15141515		Ok(properties)1516	}15171518	/// Get property permissions according to given keys.1519	pub fn filter_property_permissions(1520		collection_id: CollectionId,1521		keys: Option<Vec<PropertyKey>>,1522	) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1523		let permissions = Self::property_permissions(collection_id);15241525		let key_permissions = keys1526			.map(|keys| {1527				keys.into_iter()1528					.filter_map(|key| {1529						permissions1530							.get(&key)1531							.map(|permission| PropertyKeyPermission {1532								key,1533								permission: permission.clone(),1534							})1535					})1536					.collect()1537			})1538			.unwrap_or_else(|| {1539				permissions1540					.into_iter()1541					.map(|(key, permission)| PropertyKeyPermission { key, permission })1542					.collect()1543			});15441545		Ok(key_permissions)1546	}15471548	/// Toggle `user` participation in the `collection`'s allow list.1549	/// #### Store read/writes1550	/// 1 writes1551	pub fn toggle_allowlist(1552		collection: &CollectionHandle<T>,1553		sender: &T::CrossAccountId,1554		user: &T::CrossAccountId,1555		allowed: bool,1556	) -> DispatchResult {1557		collection.check_is_owner_or_admin(sender)?;15581559		// =========15601561		if allowed {1562			<Allowlist<T>>::insert((collection.id, user), true);1563			Self::deposit_event(Event::<T>::AllowListAddressAdded(1564				collection.id,1565				user.clone(),1566			));1567		} else {1568			<Allowlist<T>>::remove((collection.id, user));1569			Self::deposit_event(Event::<T>::AllowListAddressRemoved(1570				collection.id,1571				user.clone(),1572			));1573		}15741575		<PalletEvm<T>>::deposit_log(1576			erc::CollectionHelpersEvents::CollectionChanged {1577				collection_id: eth::collection_id_to_address(collection.id),1578			}1579			.to_log(T::ContractAddress::get()),1580		);15811582		Ok(())1583	}15841585	/// Toggle `user` participation in the `collection`'s admin list.1586	/// #### Store read/writes1587	/// 2 reads, 2 writes1588	pub fn toggle_admin(1589		collection: &CollectionHandle<T>,1590		sender: &T::CrossAccountId,1591		user: &T::CrossAccountId,1592		admin: bool,1593	) -> DispatchResult {1594		collection.check_is_internal()?;1595		collection.check_is_owner(sender)?;15961597		let is_admin = <IsAdmin<T>>::get((collection.id, user));1598		if is_admin == admin {1599			if admin {1600				return Ok(());1601			} else {1602				return Err(Error::<T>::UserIsNotCollectionAdmin.into());1603			}1604		}1605		let amount = <AdminAmount<T>>::get(collection.id);16061607		// =========16081609		if admin {1610			let amount = amount1611				.checked_add(1)1612				.ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1613			ensure!(1614				amount <= Self::collection_admins_limit(),1615				<Error<T>>::CollectionAdminCountExceeded,1616			);16171618			<AdminAmount<T>>::insert(collection.id, amount);1619			<IsAdmin<T>>::insert((collection.id, user), true);16201621			Self::deposit_event(Event::<T>::CollectionAdminAdded(1622				collection.id,1623				user.clone(),1624			));1625		} else {1626			<AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1627			<IsAdmin<T>>::remove((collection.id, user));16281629			Self::deposit_event(Event::<T>::CollectionAdminRemoved(1630				collection.id,1631				user.clone(),1632			));1633		}16341635		<PalletEvm<T>>::deposit_log(1636			erc::CollectionHelpersEvents::CollectionChanged {1637				collection_id: eth::collection_id_to_address(collection.id),1638			}1639			.to_log(T::ContractAddress::get()),1640		);16411642		Ok(())1643	}16441645	/// Update collection limits.1646	pub fn update_limits(1647		user: &T::CrossAccountId,1648		collection: &mut CollectionHandle<T>,1649		new_limit: CollectionLimits,1650	) -> DispatchResult {1651		collection.check_is_internal()?;1652		collection.check_is_owner_or_admin(user)?;16531654		collection.limits =1655			Self::clamp_limits(collection.mode.clone(), &collection.limits, new_limit)?;16561657		Self::deposit_event(Event::<T>::CollectionLimitSet(collection.id));1658		<PalletEvm<T>>::deposit_log(1659			erc::CollectionHelpersEvents::CollectionChanged {1660				collection_id: eth::collection_id_to_address(collection.id),1661			}1662			.to_log(T::ContractAddress::get()),1663		);16641665		collection.save()1666	}16671668	/// Merge set fields from `new_limit` to `old_limit`.1669	fn clamp_limits(1670		mode: CollectionMode,1671		old_limit: &CollectionLimits,1672		mut new_limit: CollectionLimits,1673	) -> Result<CollectionLimits, DispatchError> {1674		let limits = old_limit;1675		limit_default!(old_limit, new_limit,1676			account_token_ownership_limit => ensure!(1677				new_limit <= MAX_TOKEN_OWNERSHIP,1678				<Error<T>>::CollectionLimitBoundsExceeded,1679			),1680			sponsored_data_size => ensure!(1681				new_limit <= CUSTOM_DATA_LIMIT,1682				<Error<T>>::CollectionLimitBoundsExceeded,1683			),16841685			sponsored_data_rate_limit => {},1686			token_limit => ensure!(1687				old_limit >= new_limit && new_limit > 0,1688				<Error<T>>::CollectionTokenLimitExceeded1689			),16901691			sponsor_transfer_timeout(match mode {1692				CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1693				CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1694				CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1695			}) => ensure!(1696				new_limit <= MAX_SPONSOR_TIMEOUT,1697				<Error<T>>::CollectionLimitBoundsExceeded,1698			),1699			sponsor_approve_timeout => {},1700			owner_can_transfer => ensure!(1701				!limits.owner_can_transfer_instaled() ||1702				old_limit || !new_limit,1703				<Error<T>>::OwnerPermissionsCantBeReverted,1704			),1705			owner_can_destroy => ensure!(1706				old_limit || !new_limit,1707				<Error<T>>::OwnerPermissionsCantBeReverted,1708			),1709			transfers_enabled => {},1710		);1711		Ok(new_limit)1712	}17131714	/// Update collection permissions.1715	pub fn update_permissions(1716		user: &T::CrossAccountId,1717		collection: &mut CollectionHandle<T>,1718		new_permission: CollectionPermissions,1719	) -> DispatchResult {1720		collection.check_is_internal()?;1721		collection.check_is_owner_or_admin(user)?;1722		collection.permissions = Self::clamp_permissions(1723			collection.mode.clone(),1724			&collection.permissions,1725			new_permission,1726		)?;17271728		Self::deposit_event(Event::<T>::CollectionPermissionSet(collection.id));1729		<PalletEvm<T>>::deposit_log(1730			erc::CollectionHelpersEvents::CollectionChanged {1731				collection_id: eth::collection_id_to_address(collection.id),1732			}1733			.to_log(T::ContractAddress::get()),1734		);17351736		collection.save()1737	}17381739	/// Merge set fields from `new_permission` to `old_permission`.1740	fn clamp_permissions(1741		_mode: CollectionMode,1742		old_permission: &CollectionPermissions,1743		mut new_permission: CollectionPermissions,1744	) -> Result<CollectionPermissions, DispatchError> {1745		limit_default_clone!(old_permission, new_permission,1746			access => {},1747			mint_mode => {},1748			nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1749		);1750		Ok(new_permission)1751	}17521753	/// Repair possibly broken properties of a collection.1754	pub fn repair_collection(collection_id: CollectionId) -> DispatchResult {1755		CollectionProperties::<T>::mutate(collection_id, |properties| {1756			properties.recompute_consumed_space();1757		});17581759		Ok(())1760	}1761}17621763/// Indicates unsupported methods by returning [Error::UnsupportedOperation].1764#[macro_export]1765macro_rules! unsupported {1766	($runtime:path) => {1767		Err($crate::Error::<$runtime>::UnsupportedOperation.into())1768	};1769}17701771/// Return weights for various worst-case operations.1772pub trait CommonWeightInfo<CrossAccountId> {1773	/// Weight of item creation.1774	fn create_item() -> Weight;17751776	/// Weight of items creation.1777	fn create_multiple_items(amount: &[CreateItemData]) -> Weight;17781779	/// Weight of items creation.1780	fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;17811782	/// The weight of the burning item.1783	fn burn_item() -> Weight;17841785	/// Property setting weight.1786	///1787	/// * `amount`- The number of properties to set.1788	fn set_collection_properties(amount: u32) -> Weight;17891790	/// Collection property deletion weight.1791	///1792	/// * `amount`- The number of properties to set.1793	fn delete_collection_properties(amount: u32) -> Weight;17941795	/// Token property setting weight.1796	///1797	/// * `amount`- The number of properties to set.1798	fn set_token_properties(amount: u32) -> Weight;17991800	/// Token property deletion weight.1801	///1802	/// * `amount`- The number of properties to delete.1803	fn delete_token_properties(amount: u32) -> Weight;18041805	/// Token property permissions set weight.1806	///1807	/// * `amount`- The number of property permissions to set.1808	fn set_token_property_permissions(amount: u32) -> Weight;18091810	/// Transfer price of the token or its parts.1811	fn transfer() -> Weight;18121813	/// The price of setting the permission of the operation from another user.1814	fn approve() -> Weight;18151816	/// The price of setting the permission of the operation from another user for eth mirror.1817	fn approve_from() -> Weight;18181819	/// Transfer price from another user.1820	fn transfer_from() -> Weight;18211822	/// The price of burning a token from another user.1823	fn burn_from() -> Weight;18241825	/// Differs from burn_item in case of Fungible and Refungible, as it should burn1826	/// whole users's balance.1827	///1828	/// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1829	fn burn_recursively_self_raw() -> Weight;18301831	/// Cost of iterating over `amount` children while burning, without counting child burning itself.1832	///1833	/// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1834	fn burn_recursively_breadth_raw(amount: u32) -> Weight;18351836	/// The price of recursive burning a token.1837	///1838	/// `max_selfs` - The maximum burning weight of the token itself.1839	/// `max_breadth` - The maximum number of nested tokens to burn.1840	fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1841		Self::burn_recursively_self_raw()1842			.saturating_mul(max_selfs.max(1) as u64)1843			.saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1844	}18451846	/// The price of retrieving token owner1847	fn token_owner() -> Weight;18481849	/// The price of setting approval for all1850	fn set_allowance_for_all() -> Weight;18511852	/// The price of repairing an item.1853	fn force_repair_item() -> Weight;1854}18551856/// Weight info extension trait for refungible pallet.1857pub trait RefungibleExtensionsWeightInfo {1858	/// Weight of token repartition.1859	fn repartition() -> Weight;1860}18611862/// Common collection operations.1863///1864/// It wraps methods in Fungible, Nonfungible and Refungible pallets1865/// and adds weight info.1866pub trait CommonCollectionOperations<T: Config> {1867	/// Create token.1868	///1869	/// * `sender` - The user who mint the token and pays for the transaction.1870	/// * `to` - The user who will own the token.1871	/// * `data` - Token data.1872	/// * `nesting_budget` - A budget that can be spent on nesting tokens.1873	fn create_item(1874		&self,1875		sender: T::CrossAccountId,1876		to: T::CrossAccountId,1877		data: CreateItemData,1878		nesting_budget: &dyn Budget,1879	) -> DispatchResultWithPostInfo;18801881	/// Create multiple tokens.1882	///1883	/// * `sender` - The user who mint the token and pays for the transaction.1884	/// * `to` - The user who will own the token.1885	/// * `data` - Token data.1886	/// * `nesting_budget` - A budget that can be spent on nesting tokens.1887	fn create_multiple_items(1888		&self,1889		sender: T::CrossAccountId,1890		to: T::CrossAccountId,1891		data: Vec<CreateItemData>,1892		nesting_budget: &dyn Budget,1893	) -> DispatchResultWithPostInfo;18941895	/// Create multiple tokens.1896	///1897	/// * `sender` - The user who mint the token and pays for the transaction.1898	/// * `to` - The user who will own the token.1899	/// * `data` - Token data.1900	/// * `nesting_budget` - A budget that can be spent on nesting tokens.1901	fn create_multiple_items_ex(1902		&self,1903		sender: T::CrossAccountId,1904		data: CreateItemExData<T::CrossAccountId>,1905		nesting_budget: &dyn Budget,1906	) -> DispatchResultWithPostInfo;19071908	/// Burn token.1909	///1910	/// * `sender` - The user who owns the token.1911	/// * `token` - Token id that will burned.1912	/// * `amount` - The number of parts of the token that will be burned.1913	fn burn_item(1914		&self,1915		sender: T::CrossAccountId,1916		token: TokenId,1917		amount: u128,1918	) -> DispatchResultWithPostInfo;19191920	/// Burn token and all nested tokens recursievly.1921	///1922	/// * `sender` - The user who owns the token.1923	/// * `token` - Token id that will burned.1924	/// * `self_budget` - The budget that can be spent on burning tokens.1925	/// * `breadth_budget` - The budget that can be spent on burning nested tokens.1926	fn burn_item_recursively(1927		&self,1928		sender: T::CrossAccountId,1929		token: TokenId,1930		self_budget: &dyn Budget,1931		breadth_budget: &dyn Budget,1932	) -> DispatchResultWithPostInfo;19331934	/// Set collection properties.1935	///1936	/// * `sender` - Must be either the owner of the collection or its admin.1937	/// * `properties` - Properties to be set.1938	fn set_collection_properties(1939		&self,1940		sender: T::CrossAccountId,1941		properties: Vec<Property>,1942	) -> DispatchResultWithPostInfo;19431944	/// Delete collection properties.1945	///1946	/// * `sender` - Must be either the owner of the collection or its admin.1947	/// * `properties` - The properties to be removed.1948	fn delete_collection_properties(1949		&self,1950		sender: &T::CrossAccountId,1951		property_keys: Vec<PropertyKey>,1952	) -> DispatchResultWithPostInfo;19531954	/// Set token properties.1955	///1956	/// The appropriate [`PropertyPermission`] for the token property1957	/// must be set with [`Self::set_token_property_permissions`].1958	///1959	/// * `sender` - Must be either the owner of the token or its admin.1960	/// * `token_id` - The token for which the properties are being set.1961	/// * `properties` - Properties to be set.1962	/// * `budget` - Budget for setting properties.1963	fn set_token_properties(1964		&self,1965		sender: T::CrossAccountId,1966		token_id: TokenId,1967		properties: Vec<Property>,1968		budget: &dyn Budget,1969	) -> DispatchResultWithPostInfo;19701971	/// Remove token properties.1972	///1973	/// The appropriate [`PropertyPermission`] for the token property1974	/// must be set with [`Self::set_token_property_permissions`].1975	///1976	/// * `sender` - Must be either the owner of the token or its admin.1977	/// * `token_id` - The token for which the properties are being remove.1978	/// * `property_keys` - Keys to remove corresponding properties.1979	/// * `budget` - Budget for removing properties.1980	fn delete_token_properties(1981		&self,1982		sender: T::CrossAccountId,1983		token_id: TokenId,1984		property_keys: Vec<PropertyKey>,1985		budget: &dyn Budget,1986	) -> DispatchResultWithPostInfo;19871988	/// Set token property permissions.1989	///1990	/// * `sender` - Must be either the owner of the token or its admin.1991	/// * `token_id` - The token for which the properties are being set.1992	/// * `property_permissions` - Property permissions to be set.1993	/// * `budget` - Budget for setting properties.1994	fn set_token_property_permissions(1995		&self,1996		sender: &T::CrossAccountId,1997		property_permissions: Vec<PropertyKeyPermission>,1998	) -> DispatchResultWithPostInfo;19992000	/// Transfer amount of token pieces.2001	///2002	/// * `sender` - Donor user.2003	/// * `to` - Recepient user.2004	/// * `token` - The token of which parts are being sent.2005	/// * `amount` - The number of parts of the token that will be transferred.2006	/// * `budget` - The maximum budget that can be spent on the transfer.2007	fn transfer(2008		&self,2009		sender: T::CrossAccountId,2010		to: T::CrossAccountId,2011		token: TokenId,2012		amount: u128,2013		budget: &dyn Budget,2014	) -> DispatchResultWithPostInfo;20152016	/// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].2017	///2018	/// * `sender` - The user who grants access to the token.2019	/// * `spender` - The user to whom the rights are granted.2020	/// * `token` - The token to which access is granted.2021	/// * `amount` - The amount of pieces that another user can dispose of.2022	fn approve(2023		&self,2024		sender: T::CrossAccountId,2025		spender: T::CrossAccountId,2026		token: TokenId,2027		amount: u128,2028	) -> DispatchResultWithPostInfo;20292030	/// Grant access to another account to transfer parts of the token owned by the calling user's eth mirror via [Self::transfer_from].2031	///2032	/// * `sender` - The user who grants access to the token.2033	/// * `from` - Spender's eth mirror.2034	/// * `to` - The user to whom the rights are granted.2035	/// * `token` - The token to which access is granted.2036	/// * `amount` - The amount of pieces that another user can dispose of.2037	fn approve_from(2038		&self,2039		sender: T::CrossAccountId,2040		from: T::CrossAccountId,2041		to: T::CrossAccountId,2042		token: TokenId,2043		amount: u128,2044	) -> DispatchResultWithPostInfo;20452046	/// Send parts of a token owned by another user.2047	///2048	/// Before calling this method, you must grant rights to the calling user via [`Self::approve`].2049	///2050	/// * `sender` - The user who must have access to the token (see [`Self::approve`]).2051	/// * `from` - The user who owns the token.2052	/// * `to` - Recepient user.2053	/// * `token` - The token of which parts are being sent.2054	/// * `amount` - The number of parts of the token that will be transferred.2055	/// * `budget` - The maximum budget that can be spent on the transfer.2056	fn transfer_from(2057		&self,2058		sender: T::CrossAccountId,2059		from: T::CrossAccountId,2060		to: T::CrossAccountId,2061		token: TokenId,2062		amount: u128,2063		budget: &dyn Budget,2064	) -> DispatchResultWithPostInfo;20652066	/// Burn parts of a token owned by another user.2067	///2068	/// Before calling this method, you must grant rights to the calling user via [`Self::approve`].2069	///2070	/// * `sender` - The user who must have access to the token (see [`Self::approve`]).2071	/// * `from` - The user who owns the token.2072	/// * `token` - The token of which parts are being sent.2073	/// * `amount` - The number of parts of the token that will be transferred.2074	/// * `budget` - The maximum budget that can be spent on the burn.2075	fn burn_from(2076		&self,2077		sender: T::CrossAccountId,2078		from: T::CrossAccountId,2079		token: TokenId,2080		amount: u128,2081		budget: &dyn Budget,2082	) -> DispatchResultWithPostInfo;20832084	/// Check permission to nest token.2085	///2086	/// * `sender` - The user who initiated the check.2087	/// * `from` - The token that is checked for embedding.2088	/// * `under` - Token under which to check.2089	/// * `budget` - The maximum budget that can be spent on the check.2090	fn check_nesting(2091		&self,2092		sender: T::CrossAccountId,2093		from: (CollectionId, TokenId),2094		under: TokenId,2095		budget: &dyn Budget,2096	) -> DispatchResult;20972098	/// Nest one token into another.2099	///2100	/// * `under` - Token holder.2101	/// * `to_nest` - Nested token.2102	fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));21032104	/// Unnest token.2105	///2106	/// * `under` - Token holder.2107	/// * `to_nest` - Token to unnest.2108	fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));21092110	/// Get all user tokens.2111	///2112	/// * `account` - Account for which you need to get tokens.2113	fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;21142115	/// Get all the tokens in the collection.2116	fn collection_tokens(&self) -> Vec<TokenId>;21172118	/// Check if the token exists.2119	///2120	/// * `token` - Id token to check.2121	fn token_exists(&self, token: TokenId) -> bool;21222123	/// Get the id of the last minted token.2124	fn last_token_id(&self) -> TokenId;21252126	/// Get the owner of the token.2127	///2128	/// * `token` - The token for which you need to find out the owner.2129	fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;21302131	/// Returns 10 tokens owners in no particular order.2132	///2133	/// * `token` - The token for which you need to find out the owners.2134	fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId>;21352136	/// Get the value of the token property by key.2137	///2138	/// * `token` - Token with the property to get.2139	/// * `key` - Property name.2140	fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;21412142	/// Get a set of token properties by key vector.2143	///2144	/// * `token` - Token with the property to get.2145	/// * `keys` - Vector of property keys. If this parameter is [None](sp_std::result::Result),2146	/// then all properties are returned.2147	fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;21482149	/// Amount of unique collection tokens2150	fn total_supply(&self) -> u32;21512152	/// Amount of different tokens account has.2153	///2154	/// * `account` - The account for which need to get the balance.2155	fn account_balance(&self, account: T::CrossAccountId) -> u32;21562157	/// Amount of specific token account have.2158	fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;21592160	/// Amount of token pieces2161	fn total_pieces(&self, token: TokenId) -> Option<u128>;21622163	/// Get the number of parts of the token that a trusted user can manage.2164	///2165	/// * `sender` - Trusted user.2166	/// * `spender` - Owner of the token.2167	/// * `token` - The token for which to get the value.2168	fn allowance(2169		&self,2170		sender: T::CrossAccountId,2171		spender: T::CrossAccountId,2172		token: TokenId,2173	) -> u128;21742175	/// Get extension for RFT collection.2176	fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;21772178	/// The `operator` is allowed to transfer all tokens of the `owner` on their behalf.2179	/// * `owner` - Token owner2180	/// * `operator` - Operator2181	/// * `approve` - Should operator status be granted or revoked?2182	fn set_allowance_for_all(2183		&self,2184		owner: T::CrossAccountId,2185		operator: T::CrossAccountId,2186		approve: bool,2187	) -> DispatchResultWithPostInfo;21882189	/// Tells whether the given `owner` approves the `operator`.2190	fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool;21912192	/// Repairs a possibly broken item.2193	fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo;2194}21952196/// Extension for RFT collection.2197pub trait RefungibleExtensions<T>2198where2199	T: Config,2200{2201	/// Change the number of parts of the token.2202	///2203	/// When the value changes down, this function is equivalent to burning parts of the token.2204	///2205	/// * `sender` - The user calling the repartition operation. Must be the owner of the token.2206	/// * `token` - The token for which you want to change the number of parts.2207	/// * `amount` - The new value of the parts of the token.2208	fn repartition(2209		&self,2210		sender: &T::CrossAccountId,2211		token: TokenId,2212		amount: u128,2213	) -> DispatchResultWithPostInfo;2214}22152216/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].2217///2218/// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so.2219pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {2220	let post_info = PostDispatchInfo {2221		actual_weight: Some(weight),2222		pays_fee: Pays::Yes,2223	};2224	match res {2225		Ok(()) => Ok(post_info),2226		Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),2227	}2228}22292230impl<T: Config> From<PropertiesError> for Error<T> {2231	fn from(error: PropertiesError) -> Self {2232		match error {2233			PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,2234			PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,2235			PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,2236			PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,2237			PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,2238		}2239	}2240}
after · pallets/common/src/lib.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//! # Common pallet18//!19//! The Common pallet provides functionality for handling collections.20//!21//! ## Overview22//!23//! The Common pallet provides an interface for common collection operations for different collection types24//! (see [CommonCollectionOperations]), as well as a generic dispatcher for these, see [dispatch] module.25//! It also provides this functionality to EVM, see [erc] and [eth] modules.26//!27//! The Common pallet provides functions for:28//!29//! - Setting and approving collection sponsor.30//! - Get\set\delete allow list.31//! - Get\set\delete collection properties.32//! - Get\set\delete collection property permissions.33//! - Get\set\delete token property permissions.34//! - Get\set\delete collection administrators.35//! - Checking access permissions.36//!37//! ### Terminology38//! **Collection sponsor** - For the collection, you can set a sponsor, at whose expense it will39//! be possible to mint tokens.40//!41//! **Allow list** - List of users who have the right to minting tokens.42//!43//! **Collection properties** - Collection properties are simply key-value stores where various44//! metadata can be placed.45//!46//! **Permissions on token properties** - For each property in the token can be set permission47//! to change, see [`PropertyPermission`].48//!49//! **Collection administrator** - For a collection, you can set administrators who have the right50//! to most actions on the collection.5152#![warn(missing_docs)]53#![cfg_attr(not(feature = "std"), no_std)]54extern crate alloc;5556use core::ops::{Deref, DerefMut};57use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};58use sp_std::vec::Vec;59use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};60use evm_coder::ToLog;61use frame_support::{62	dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},63	ensure,64	traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},65	dispatch::Pays,66	transactional,67};68use pallet_evm::GasWeightMapping;69use up_data_structs::{70	COLLECTION_NUMBER_LIMIT,71	Collection,72	RpcCollection,73	CollectionFlags,74	RpcCollectionFlags,75	CollectionId,76	CreateItemData,77	MAX_TOKEN_PREFIX_LENGTH,78	COLLECTION_ADMINS_LIMIT,79	TokenId,80	TokenChild,81	CollectionStats,82	MAX_TOKEN_OWNERSHIP,83	CollectionMode,84	NFT_SPONSOR_TRANSFER_TIMEOUT,85	FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,86	REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,87	MAX_SPONSOR_TIMEOUT,88	CUSTOM_DATA_LIMIT,89	CollectionLimits,90	CreateCollectionData,91	SponsorshipState,92	CreateItemExData,93	SponsoringRateLimit,94	budget::Budget,95	PhantomType,96	Property,97	Properties,98	PropertiesPermissionMap,99	PropertyKey,100	PropertyValue,101	PropertyPermission,102	PropertiesError,103	PropertyKeyPermission,104	TokenData,105	TrySetProperty,106	PropertyScope,107	// RMRK108	RmrkCollectionInfo,109	RmrkInstanceInfo,110	RmrkResourceInfo,111	RmrkPropertyInfo,112	RmrkBaseInfo,113	RmrkPartType,114	RmrkBoundedTheme,115	RmrkNftChild,116	CollectionPermissions,117};118use up_pov_estimate_rpc::PovInfo;119120pub use pallet::*;121use sp_core::H160;122use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};123#[cfg(feature = "runtime-benchmarks")]124pub mod benchmarking;125pub mod dispatch;126pub mod erc;127pub mod eth;128pub mod weights;129130/// Weight info.131pub type SelfWeightOf<T> = <T as Config>::WeightInfo;132133/// Collection handle contains information about collection data and id.134/// Also provides functionality to count consumed gas.135///136/// CollectionHandle is used as a generic wrapper for collections of all types.137/// It allows to perform common operations and queries on any collection type,138/// both completely general for all, as well as their respective implementations of [`CommonCollectionOperations`].139#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]140pub struct CollectionHandle<T: Config> {141	/// Collection id142	pub id: CollectionId,143	collection: Collection<T::AccountId>,144	/// Substrate recorder for counting consumed gas145	pub recorder: SubstrateRecorder<T>,146}147148impl<T: Config> WithRecorder<T> for CollectionHandle<T> {149	fn recorder(&self) -> &SubstrateRecorder<T> {150		&self.recorder151	}152	fn into_recorder(self) -> SubstrateRecorder<T> {153		self.recorder154	}155}156157impl<T: Config> CollectionHandle<T> {158	/// Same as [CollectionHandle::new] but with an explicit gas limit.159	pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {160		<CollectionById<T>>::get(id).map(|collection| Self {161			id,162			collection,163			recorder: SubstrateRecorder::new(gas_limit),164		})165	}166167	/// Same as [CollectionHandle::new] but with an existed [`SubstrateRecorder`].168	pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {169		<CollectionById<T>>::get(id).map(|collection| Self {170			id,171			collection,172			recorder,173		})174	}175176	/// Retrives collection data from storage and creates collection handle with default parameters.177	/// If collection not found return `None`178	pub fn new(id: CollectionId) -> Option<Self> {179		Self::new_with_gas_limit(id, u64::MAX)180	}181182	/// Same as [`CollectionHandle::new`] but if collection not found [CollectionNotFound](Error::CollectionNotFound) returned.183	pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {184		Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)185	}186187	/// Consume gas for reading.188	pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {189		self.recorder190			.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(191				<T as frame_system::Config>::DbWeight::get()192					.read193					.saturating_mul(reads),194			)))195	}196197	/// Consume gas for writing.198	pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {199		self.recorder200			.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(201				<T as frame_system::Config>::DbWeight::get()202					.write203					.saturating_mul(writes),204			)))205	}206207	/// Consume gas for reading and writing.208	pub fn consume_store_reads_and_writes(209		&self,210		reads: u64,211		writes: u64,212	) -> evm_coder::execution::Result<()> {213		let weight = <T as frame_system::Config>::DbWeight::get();214		let reads = weight.read.saturating_mul(reads);215		let writes = weight.read.saturating_mul(writes);216		self.recorder217			.consume_gas(T::GasWeightMapping::weight_to_gas(Weight::from_ref_time(218				reads.saturating_add(writes),219			)))220	}221222	/// Save collection to storage.223	pub fn save(&self) -> DispatchResult {224		<CollectionById<T>>::insert(self.id, &self.collection);225		Ok(())226	}227228	/// Set collection sponsor.229	///230	/// Unique collections allows sponsoring for certain actions.231	/// This method allows you to set the sponsor of the collection.232	/// In order for sponsorship to become active, it must be confirmed through [`Self::confirm_sponsorship`].233	pub fn set_sponsor(234		&mut self,235		sender: &T::CrossAccountId,236		sponsor: T::AccountId,237	) -> DispatchResult {238		self.check_is_internal()?;239		self.check_is_owner_or_admin(sender)?;240241		self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor.clone());242243		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(self.id, sponsor));244		<PalletEvm<T>>::deposit_log(245			erc::CollectionHelpersEvents::CollectionChanged {246				collection_id: eth::collection_id_to_address(self.id),247			}248			.to_log(T::ContractAddress::get()),249		);250251		self.save()252	}253254	/// Force set `sponsor`.255	///256	/// Differs from [`set_sponsor`][`Self::set_sponsor`] in that confirmation257	/// from the `sponsor` is not required.258	///259	/// # Arguments260	///261	/// * `sender`: Caller's account.262	/// * `sponsor`: ID of the account of the sponsor-to-be.263	pub fn force_set_sponsor(&mut self, sponsor: T::AccountId) -> DispatchResult {264		self.check_is_internal()?;265266		self.collection.sponsorship = SponsorshipState::Confirmed(sponsor.clone());267268		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(self.id, sponsor.clone()));269		<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(self.id, sponsor));270		<PalletEvm<T>>::deposit_log(271			erc::CollectionHelpersEvents::CollectionChanged {272				collection_id: eth::collection_id_to_address(self.id),273			}274			.to_log(T::ContractAddress::get()),275		);276277		self.save()278	}279280	/// Confirm sponsorship281	///282	/// In order for the sponsorship to become active, the user set as the sponsor must confirm their participation.283	/// Before confirming sponsorship, the user must be specified as the sponsor of the collection via [`Self::set_sponsor`].284	pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> DispatchResult {285		self.check_is_internal()?;286		ensure!(287			self.collection.sponsorship.pending_sponsor() == Some(sender),288			Error::<T>::ConfirmSponsorshipFail289		);290291		self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());292293		<Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(self.id, sender.clone()));294		<PalletEvm<T>>::deposit_log(295			erc::CollectionHelpersEvents::CollectionChanged {296				collection_id: eth::collection_id_to_address(self.id),297			}298			.to_log(T::ContractAddress::get()),299		);300301		self.save()302	}303304	/// Remove collection sponsor.305	pub fn remove_sponsor(&mut self, sender: &T::CrossAccountId) -> DispatchResult {306		self.check_is_internal()?;307		self.check_is_owner_or_admin(sender)?;308309		self.collection.sponsorship = SponsorshipState::Disabled;310311		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(self.id));312		<PalletEvm<T>>::deposit_log(313			erc::CollectionHelpersEvents::CollectionChanged {314				collection_id: eth::collection_id_to_address(self.id),315			}316			.to_log(T::ContractAddress::get()),317		);318		self.save()319	}320321	/// Force remove `sponsor`.322	///323	/// Differs from `remove_sponsor` in that324	/// it doesn't require consent from the `owner` of the collection.325	pub fn force_remove_sponsor(&mut self) -> DispatchResult {326		self.check_is_internal()?;327328		self.collection.sponsorship = SponsorshipState::Disabled;329330		<Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(self.id));331		<PalletEvm<T>>::deposit_log(332			erc::CollectionHelpersEvents::CollectionChanged {333				collection_id: eth::collection_id_to_address(self.id),334			}335			.to_log(T::ContractAddress::get()),336		);337		self.save()338	}339340	/// Checks that the collection was created with, and must be operated upon through **Unique API**.341	/// Now check only the `external` flag and if it's **true**, then return [`Error::CollectionIsExternal`] error.342	pub fn check_is_internal(&self) -> DispatchResult {343		if self.flags.external {344			return Err(<Error<T>>::CollectionIsExternal)?;345		}346347		Ok(())348	}349350	/// Checks that the collection was created with, and must be operated upon through an **assimilated API**.351	/// Now check only the `external` flag and if it's **false**, then return [`Error::CollectionIsInternal`] error.352	pub fn check_is_external(&self) -> DispatchResult {353		if !self.flags.external {354			return Err(<Error<T>>::CollectionIsInternal)?;355		}356357		Ok(())358	}359}360361impl<T: Config> Deref for CollectionHandle<T> {362	type Target = Collection<T::AccountId>;363364	fn deref(&self) -> &Self::Target {365		&self.collection366	}367}368369impl<T: Config> DerefMut for CollectionHandle<T> {370	fn deref_mut(&mut self) -> &mut Self::Target {371		&mut self.collection372	}373}374375impl<T: Config> CollectionHandle<T> {376	/// Checks if the `user` is the owner of the collection.377	pub fn check_is_owner(&self, user: &T::CrossAccountId) -> DispatchResult {378		ensure!(*user.as_sub() == self.owner, <Error<T>>::NoPermission);379		Ok(())380	}381382	/// Returns **true** if the `user` is the owner or administrator of the collection.383	pub fn is_owner_or_admin(&self, user: &T::CrossAccountId) -> bool {384		*user.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, user))385	}386387	/// Checks if the `user` is the owner or administrator of the collection.388	pub fn check_is_owner_or_admin(&self, user: &T::CrossAccountId) -> DispatchResult {389		ensure!(self.is_owner_or_admin(user), <Error<T>>::NoPermission);390		Ok(())391	}392393	/// Returns **true** if394	/// * the `user`is a collection owner or admin395	/// * the collection limits allow the owner/admins to transfer/burn any collection token396	pub fn ignores_token_restrictions(&self, user: &T::CrossAccountId) -> bool {397		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)398	}399400	/// Return **true** if `user` does not have enough token parts, and he can ignore such restrictions.401	pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {402		self.limits.owner_can_transfer() && self.is_owner_or_admin(user)403	}404405	/// Checks if the user is in the allow list. If not [Error::AddressNotInAllowlist] returns.406	pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {407		ensure!(408			<Allowlist<T>>::get((self.id, user)),409			<Error<T>>::AddressNotInAllowlist410		);411		Ok(())412	}413414	/// Changes collection owner to another account415	/// #### Store read/writes416	/// 1 writes417	pub fn change_owner(418		&mut self,419		caller: T::CrossAccountId,420		new_owner: T::CrossAccountId,421	) -> DispatchResult {422		self.check_is_internal()?;423		self.check_is_owner(&caller)?;424		self.collection.owner = new_owner.as_sub().clone();425426		<Pallet<T>>::deposit_event(Event::<T>::CollectionOwnerChanged(427			self.id,428			new_owner.as_sub().clone(),429		));430		<PalletEvm<T>>::deposit_log(431			erc::CollectionHelpersEvents::CollectionChanged {432				collection_id: eth::collection_id_to_address(self.id),433			}434			.to_log(T::ContractAddress::get()),435		);436437		self.save()438	}439}440441#[frame_support::pallet]442pub mod pallet {443	use super::*;444	use dispatch::CollectionDispatch;445	use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};446	use frame_system::pallet_prelude::*;447	use frame_support::traits::Currency;448	use up_data_structs::{TokenId, mapping::TokenAddressMapping};449	use scale_info::TypeInfo;450	use weights::WeightInfo;451452	#[pallet::config]453	pub trait Config:454		frame_system::Config + pallet_evm_coder_substrate::Config + pallet_evm::Config + TypeInfo455	{456		/// Weight information for functions of this pallet.457		type WeightInfo: WeightInfo;458459		/// Events compatible with [`frame_system::Config::Event`].460		type RuntimeEvent: IsType<<Self as frame_system::Config>::RuntimeEvent> + From<Event<Self>>;461462		/// Handler of accounts and payment.463		type Currency: Currency<Self::AccountId>;464465		/// Set price to create a collection.466		#[pallet::constant]467		type CollectionCreationPrice: Get<468			<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,469		>;470471		/// Dispatcher of operations on collections.472		type CollectionDispatch: CollectionDispatch<Self>;473474		/// Account which holds the chain's treasury.475		type TreasuryAccountId: Get<Self::AccountId>;476477		/// Address under which the CollectionHelper contract would be available.478		#[pallet::constant]479		type ContractAddress: Get<H160>;480481		/// Mapper for token addresses to Ethereum addresses.482		type EvmTokenAddressMapping: TokenAddressMapping<H160>;483484		/// Mapper for token addresses to [`CrossAccountId`].485		type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;486	}487488	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);489490	#[pallet::pallet]491	#[pallet::storage_version(STORAGE_VERSION)]492	#[pallet::generate_store(pub(super) trait Store)]493	pub struct Pallet<T>(_);494495	#[pallet::extra_constants]496	impl<T: Config> Pallet<T> {497		/// Maximum admins per collection.498		pub fn collection_admins_limit() -> u32 {499			COLLECTION_ADMINS_LIMIT500		}501	}502503	impl<T: Config> Pallet<T> {504		/// Helper function that handles deposit events505		pub fn deposit_event(event: Event<T>) {506			let event = <T as Config>::RuntimeEvent::from(event);507			let event = event.into();508			<frame_system::Pallet<T>>::deposit_event(event)509		}510	}511512	#[pallet::event]513	pub enum Event<T: Config> {514		/// New collection was created515		CollectionCreated(516			/// Globally unique identifier of newly created collection.517			CollectionId,518			/// [`CollectionMode`] converted into _u8_.519			u8,520			/// Collection owner.521			T::AccountId,522		),523524		/// New collection was destroyed525		CollectionDestroyed(526			/// Globally unique identifier of collection.527			CollectionId,528		),529530		/// New item was created.531		ItemCreated(532			/// Id of the collection where item was created.533			CollectionId,534			/// Id of an item. Unique within the collection.535			TokenId,536			/// Owner of newly created item537			T::CrossAccountId,538			/// Always 1 for NFT539			u128,540		),541542		/// Collection item was burned.543		ItemDestroyed(544			/// Id of the collection where item was destroyed.545			CollectionId,546			/// Identifier of burned NFT.547			TokenId,548			/// Which user has destroyed its tokens.549			T::CrossAccountId,550			/// Amount of token pieces destroed. Always 1 for NFT.551			u128,552		),553554		/// Item was transferred555		Transfer(556			/// Id of collection to which item is belong.557			CollectionId,558			/// Id of an item.559			TokenId,560			/// Original owner of item.561			T::CrossAccountId,562			/// New owner of item.563			T::CrossAccountId,564			/// Amount of token pieces transfered. Always 1 for NFT.565			u128,566		),567568		/// Amount pieces of token owned by `sender` was approved for `spender`.569		Approved(570			/// Id of collection to which item is belong.571			CollectionId,572			/// Id of an item.573			TokenId,574			/// Original owner of item.575			T::CrossAccountId,576			/// Id for which the approval was granted.577			T::CrossAccountId,578			/// Amount of token pieces transfered. Always 1 for NFT.579			u128,580		),581582		/// A `sender` approves operations on all owned tokens for `spender`.583		ApprovedForAll(584			/// Id of collection to which item is belong.585			CollectionId,586			/// Owner of a wallet.587			T::CrossAccountId,588			/// Id for which operator status was granted or rewoked.589			T::CrossAccountId,590			/// Is operator status granted or revoked?591			bool,592		),593594		/// The colletion property has been added or edited.595		CollectionPropertySet(596			/// Id of collection to which property has been set.597			CollectionId,598			/// The property that was set.599			PropertyKey,600		),601602		/// The property has been deleted.603		CollectionPropertyDeleted(604			/// Id of collection to which property has been deleted.605			CollectionId,606			/// The property that was deleted.607			PropertyKey,608		),609610		/// The token property has been added or edited.611		TokenPropertySet(612			/// Identifier of the collection whose token has the property set.613			CollectionId,614			/// The token for which the property was set.615			TokenId,616			/// The property that was set.617			PropertyKey,618		),619620		/// The token property has been deleted.621		TokenPropertyDeleted(622			/// Identifier of the collection whose token has the property deleted.623			CollectionId,624			/// The token for which the property was deleted.625			TokenId,626			/// The property that was deleted.627			PropertyKey,628		),629630		/// The token property permission of a collection has been set.631		PropertyPermissionSet(632			/// ID of collection to which property permission has been set.633			CollectionId,634			/// The property permission that was set.635			PropertyKey,636		),637638		/// Address was added to the allow list.639		AllowListAddressAdded(640			/// ID of the affected collection.641			CollectionId,642			/// Address of the added account.643			T::CrossAccountId,644		),645646		/// Address was removed from the allow list.647		AllowListAddressRemoved(648			/// ID of the affected collection.649			CollectionId,650			/// Address of the removed account.651			T::CrossAccountId,652		),653654		/// Collection admin was added.655		CollectionAdminAdded(656			/// ID of the affected collection.657			CollectionId,658			/// Admin address.659			T::CrossAccountId,660		),661662		/// Collection admin was removed.663		CollectionAdminRemoved(664			/// ID of the affected collection.665			CollectionId,666			/// Removed admin address.667			T::CrossAccountId,668		),669670		/// Collection limits were set.671		CollectionLimitSet(672			/// ID of the affected collection.673			CollectionId,674		),675676		/// Collection owned was changed.677		CollectionOwnerChanged(678			/// ID of the affected collection.679			CollectionId,680			/// New owner address.681			T::AccountId,682		),683684		/// Collection permissions were set.685		CollectionPermissionSet(686			/// ID of the affected collection.687			CollectionId,688		),689690		/// Collection sponsor was set.691		CollectionSponsorSet(692			/// ID of the affected collection.693			CollectionId,694			/// New sponsor address.695			T::AccountId,696		),697698		/// New sponsor was confirm.699		SponsorshipConfirmed(700			/// ID of the affected collection.701			CollectionId,702			/// New sponsor address.703			T::AccountId,704		),705706		/// Collection sponsor was removed.707		CollectionSponsorRemoved(708			/// ID of the affected collection.709			CollectionId,710		),711	}712713	#[pallet::error]714	pub enum Error<T> {715		/// This collection does not exist.716		CollectionNotFound,717		/// Sender parameter and item owner must be equal.718		MustBeTokenOwner,719		/// No permission to perform action720		NoPermission,721		/// Destroying only empty collections is allowed722		CantDestroyNotEmptyCollection,723		/// Collection is not in mint mode.724		PublicMintingNotAllowed,725		/// Address is not in allow list.726		AddressNotInAllowlist,727728		/// Collection name can not be longer than 63 char.729		CollectionNameLimitExceeded,730		/// Collection description can not be longer than 255 char.731		CollectionDescriptionLimitExceeded,732		/// Token prefix can not be longer than 15 char.733		CollectionTokenPrefixLimitExceeded,734		/// Total collections bound exceeded.735		TotalCollectionsLimitExceeded,736		/// Exceeded max admin count737		CollectionAdminCountExceeded,738		/// Collection limit bounds per collection exceeded739		CollectionLimitBoundsExceeded,740		/// Tried to enable permissions which are only permitted to be disabled741		OwnerPermissionsCantBeReverted,742		/// Collection settings not allowing items transferring743		TransferNotAllowed,744		/// Account token limit exceeded per collection745		AccountTokenLimitExceeded,746		/// Collection token limit exceeded747		CollectionTokenLimitExceeded,748		/// Metadata flag frozen749		MetadataFlagFrozen,750751		/// Item does not exist752		TokenNotFound,753		/// Item is balance not enough754		TokenValueTooLow,755		/// Requested value is more than the approved756		ApprovedValueTooLow,757		/// Tried to approve more than owned758		CantApproveMoreThanOwned,759		/// Only spending from eth mirror could be approved760		AddressIsNotEthMirror,761762		/// Can't transfer tokens to ethereum zero address763		AddressIsZero,764765		/// The operation is not supported766		UnsupportedOperation,767768		/// Insufficient funds to perform an action769		NotSufficientFounds,770771		/// User does not satisfy the nesting rule772		UserIsNotAllowedToNest,773		/// Only tokens from specific collections may nest tokens under this one774		SourceCollectionIsNotAllowedToNest,775776		/// Tried to store more data than allowed in collection field777		CollectionFieldSizeExceeded,778779		/// Tried to store more property data than allowed780		NoSpaceForProperty,781782		/// Tried to store more property keys than allowed783		PropertyLimitReached,784785		/// Property key is too long786		PropertyKeyIsTooLong,787788		/// Only ASCII letters, digits, and symbols `_`, `-`, and `.` are allowed789		InvalidCharacterInPropertyKey,790791		/// Empty property keys are forbidden792		EmptyPropertyKey,793794		/// Tried to access an external collection with an internal API795		CollectionIsExternal,796797		/// Tried to access an internal collection with an external API798		CollectionIsInternal,799800		/// This address is not set as sponsor, use setCollectionSponsor first.801		ConfirmSponsorshipFail,802803		/// The user is not an administrator.804		UserIsNotCollectionAdmin,805	}806807	/// Storage of the count of created collections. Essentially contains the last collection ID.808	#[pallet::storage]809	pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;810811	/// Storage of the count of deleted collections.812	#[pallet::storage]813	pub type DestroyedCollectionCount<T> =814		StorageValue<Value = CollectionId, QueryKind = ValueQuery>;815816	/// Storage of collection info.817	#[pallet::storage]818	pub type CollectionById<T> = StorageMap<819		Hasher = Blake2_128Concat,820		Key = CollectionId,821		Value = Collection<<T as frame_system::Config>::AccountId>,822		QueryKind = OptionQuery,823	>;824825	/// Storage of collection properties.826	#[pallet::storage]827	#[pallet::getter(fn collection_properties)]828	pub type CollectionProperties<T> = StorageMap<829		Hasher = Blake2_128Concat,830		Key = CollectionId,831		Value = Properties,832		QueryKind = ValueQuery,833		OnEmpty = up_data_structs::CollectionProperties,834	>;835836	/// Storage of token property permissions of a collection.837	#[pallet::storage]838	#[pallet::getter(fn property_permissions)]839	pub type CollectionPropertyPermissions<T> = StorageMap<840		Hasher = Blake2_128Concat,841		Key = CollectionId,842		Value = PropertiesPermissionMap,843		QueryKind = ValueQuery,844	>;845846	/// Storage of the amount of collection admins.847	#[pallet::storage]848	pub type AdminAmount<T> = StorageMap<849		Hasher = Blake2_128Concat,850		Key = CollectionId,851		Value = u32,852		QueryKind = ValueQuery,853	>;854855	/// List of collection admins.856	#[pallet::storage]857	pub type IsAdmin<T: Config> = StorageNMap<858		Key = (859			Key<Blake2_128Concat, CollectionId>,860			Key<Blake2_128Concat, T::CrossAccountId>,861		),862		Value = bool,863		QueryKind = ValueQuery,864	>;865866	/// Allowlisted collection users.867	#[pallet::storage]868	pub type Allowlist<T: Config> = StorageNMap<869		Key = (870			Key<Blake2_128Concat, CollectionId>,871			Key<Blake2_128Concat, T::CrossAccountId>,872		),873		Value = bool,874		QueryKind = ValueQuery,875	>;876877	/// Not used by code, exists only to provide some types to metadata.878	#[pallet::storage]879	pub type DummyStorageValue<T: Config> = StorageValue<880		Value = (881			CollectionStats,882			CollectionId,883			TokenId,884			TokenChild,885			PhantomType<(886				TokenData<T::CrossAccountId>,887				RpcCollection<T::AccountId>,888				// RMRK889				RmrkCollectionInfo<T::AccountId>,890				RmrkInstanceInfo<T::AccountId>,891				RmrkResourceInfo,892				RmrkPropertyInfo,893				RmrkBaseInfo<T::AccountId>,894				RmrkPartType,895				RmrkBoundedTheme,896				RmrkNftChild,897				// PoV Estimate Info898				PovInfo,899			)>,900		),901		QueryKind = OptionQuery,902	>;903904	#[pallet::hooks]905	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {906		fn on_runtime_upgrade() -> Weight {907			StorageVersion::new(1).put::<Pallet<T>>();908909			Weight::zero()910		}911	}912}913914impl<T: Config> Pallet<T> {915	/// Enshure that receiver address is correct.916	///917	/// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens.918	pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {919		ensure!(920			&T::CrossAccountId::from_eth(H160([0; 20])) != receiver,921			<Error<T>>::AddressIsZero922		);923		Ok(())924	}925926	/// Get a vector of collection admins.927	pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {928		<IsAdmin<T>>::iter_prefix((collection,))929			.map(|(a, _)| a)930			.collect()931	}932933	/// Get a vector of users allowed to mint tokens.934	pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {935		<Allowlist<T>>::iter_prefix((collection,))936			.map(|(a, _)| a)937			.collect()938	}939940	/// Is `user` allowed to mint token in `collection`.941	pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {942		<Allowlist<T>>::get((collection, user))943	}944945	/// Get statistics of collections.946	pub fn collection_stats() -> CollectionStats {947		let created = <CreatedCollectionCount<T>>::get();948		let destroyed = <DestroyedCollectionCount<T>>::get();949		CollectionStats {950			created: created.0,951			destroyed: destroyed.0,952			alive: created.0 - destroyed.0,953		}954	}955956	/// Get the effective limits for the collection.957	pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {958		let collection = <CollectionById<T>>::get(collection)?;959		let limits = collection.limits;960		let effective_limits = CollectionLimits {961			account_token_ownership_limit: Some(limits.account_token_ownership_limit()),962			sponsored_data_size: Some(limits.sponsored_data_size()),963			sponsored_data_rate_limit: Some(964				limits965					.sponsored_data_rate_limit966					.unwrap_or(SponsoringRateLimit::SponsoringDisabled),967			),968			token_limit: Some(limits.token_limit()),969			sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(970				match collection.mode {971					CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,972					CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,973					CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,974				},975			)),976			sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),977			owner_can_transfer: Some(limits.owner_can_transfer()),978			owner_can_destroy: Some(limits.owner_can_destroy()),979			transfers_enabled: Some(limits.transfers_enabled()),980		};981982		Some(effective_limits)983	}984985	/// Returns information about the `collection` adapted for rpc.986	pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {987		let Collection {988			name,989			description,990			owner,991			mode,992			token_prefix,993			sponsorship,994			limits,995			permissions,996			flags,997		} = <CollectionById<T>>::get(collection)?;998999		let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)1000			.into_iter()1001			.map(|(key, permission)| PropertyKeyPermission { key, permission })1002			.collect();10031004		let properties = <CollectionProperties<T>>::get(collection)1005			.into_iter()1006			.map(|(key, value)| Property { key, value })1007			.collect();10081009		let permissions = CollectionPermissions {1010			access: Some(permissions.access()),1011			mint_mode: Some(permissions.mint_mode()),1012			nesting: Some(permissions.nesting().clone()),1013		};10141015		Some(RpcCollection {1016			name: name.into_inner(),1017			description: description.into_inner(),1018			owner,1019			mode,1020			token_prefix: token_prefix.into_inner(),1021			sponsorship,1022			limits,1023			permissions,1024			token_property_permissions,1025			properties,1026			read_only: flags.external,10271028			flags: RpcCollectionFlags {1029				foreign: flags.foreign,1030				erc721metadata: flags.erc721metadata,1031			},1032		})1033	}1034}10351036macro_rules! limit_default {1037	($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1038		$(1039			if let Some($new) = $new.$field {1040				let $old = $old.$field($($arg)?);1041				let _ = $new;1042				let _ = $old;1043				$check1044			} else {1045				$new.$field = $old.$field1046			}1047		)*1048	}};1049}1050macro_rules! limit_default_clone {1051	($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{1052		$(1053			if let Some($new) = $new.$field.clone() {1054				let $old = $old.$field($($arg)?);1055				let _ = $new;1056				let _ = $old;1057				$check1058			} else {1059				$new.$field = $old.$field.clone()1060			}1061		)*1062	}};1063}10641065impl<T: Config> Pallet<T> {1066	/// Create new collection.1067	///1068	/// * `owner` - The owner of the collection.1069	/// * `data` - Description of the created collection.1070	/// * `flags` - Extra flags to store.1071	pub fn init_collection(1072		owner: T::CrossAccountId,1073		payer: T::CrossAccountId,1074		data: CreateCollectionData<T::AccountId>,1075		flags: CollectionFlags,1076	) -> Result<CollectionId, DispatchError> {1077		{1078			ensure!(1079				data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,1080				Error::<T>::CollectionTokenPrefixLimitExceeded1081			);1082		}10831084		let created_count = <CreatedCollectionCount<T>>::get()1085			.01086			.checked_add(1)1087			.ok_or(ArithmeticError::Overflow)?;1088		let destroyed_count = <DestroyedCollectionCount<T>>::get().0;1089		let id = CollectionId(created_count);10901091		// bound Total number of collections1092		ensure!(1093			created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,1094			<Error<T>>::TotalCollectionsLimitExceeded1095		);10961097		// =========10981099		let collection = Collection {1100			owner: owner.as_sub().clone(),1101			name: data.name,1102			mode: data.mode.clone(),1103			description: data.description,1104			token_prefix: data.token_prefix,1105			sponsorship: data1106				.pending_sponsor1107				.map(SponsorshipState::Unconfirmed)1108				.unwrap_or_default(),1109			limits: data1110				.limits1111				.map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))1112				.unwrap_or_else(|| Ok(CollectionLimits::default()))?,1113			permissions: data1114				.permissions1115				.map(|permissions| {1116					Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)1117				})1118				.unwrap_or_else(|| Ok(CollectionPermissions::default()))?,1119			flags,1120		};11211122		let mut collection_properties = up_data_structs::CollectionProperties::get();1123		collection_properties1124			.try_set_from_iter(data.properties.into_iter())1125			.map_err(<Error<T>>::from)?;11261127		CollectionProperties::<T>::insert(id, collection_properties);11281129		let mut token_props_permissions = PropertiesPermissionMap::new();1130		token_props_permissions1131			.try_set_from_iter(data.token_property_permissions.into_iter())1132			.map_err(<Error<T>>::from)?;11331134		CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);11351136		// Take a (non-refundable) deposit of collection creation1137		{1138			let mut imbalance =1139				<<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();1140			imbalance.subsume(1141				<<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(1142					&T::TreasuryAccountId::get(),1143					T::CollectionCreationPrice::get(),1144				),1145			);1146			<T as Config>::Currency::settle(1147				payer.as_sub(),1148				imbalance,1149				WithdrawReasons::TRANSFER,1150				ExistenceRequirement::KeepAlive,1151			)1152			.map_err(|_| Error::<T>::NotSufficientFounds)?;1153		}11541155		<CreatedCollectionCount<T>>::put(created_count);1156		<Pallet<T>>::deposit_event(Event::CollectionCreated(1157			id,1158			data.mode.id(),1159			owner.as_sub().clone(),1160		));1161		<PalletEvm<T>>::deposit_log(1162			erc::CollectionHelpersEvents::CollectionCreated {1163				owner: *owner.as_eth(),1164				collection_id: eth::collection_id_to_address(id),1165			}1166			.to_log(T::ContractAddress::get()),1167		);1168		<CollectionById<T>>::insert(id, collection);1169		Ok(id)1170	}11711172	/// Destroy collection.1173	///1174	/// * `collection` - Collection handler.1175	/// * `sender` - The owner or administrator of the collection.1176	pub fn destroy_collection(1177		collection: CollectionHandle<T>,1178		sender: &T::CrossAccountId,1179	) -> DispatchResult {1180		ensure!(1181			collection.limits.owner_can_destroy(),1182			<Error<T>>::NoPermission,1183		);1184		collection.check_is_owner(sender)?;11851186		let destroyed_collections = <DestroyedCollectionCount<T>>::get()1187			.01188			.checked_add(1)1189			.ok_or(ArithmeticError::Overflow)?;11901191		// =========11921193		<DestroyedCollectionCount<T>>::put(destroyed_collections);1194		<CollectionById<T>>::remove(collection.id);1195		<AdminAmount<T>>::remove(collection.id);1196		let _ = <IsAdmin<T>>::clear_prefix((collection.id,), u32::MAX, None);1197		let _ = <Allowlist<T>>::clear_prefix((collection.id,), u32::MAX, None);1198		<CollectionProperties<T>>::remove(collection.id);11991200		<Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));12011202		<PalletEvm<T>>::deposit_log(1203			erc::CollectionHelpersEvents::CollectionDestroyed {1204				collection_id: eth::collection_id_to_address(collection.id),1205			}1206			.to_log(T::ContractAddress::get()),1207		);1208		Ok(())1209	}12101211	/// This function sets or removes a collection properties according to1212	/// `properties_updates` contents:1213	/// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`1214	/// * removes a property under the <key> if the value is `None` `(<key>, None)`.1215	///1216	/// This function fires an event for each property change.1217	/// In case of an error, all the changes (including the events) will be reverted1218	/// since the function is transactional.1219	#[transactional]1220	fn modify_collection_properties(1221		collection: &CollectionHandle<T>,1222		sender: &T::CrossAccountId,1223		properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,1224	) -> DispatchResult {1225		collection.check_is_owner_or_admin(sender)?;12261227		let mut stored_properties = <CollectionProperties<T>>::get(collection.id);12281229		for (key, value) in properties_updates {1230			match value {1231				Some(value) => {1232					stored_properties1233						.try_set(key.clone(), value)1234						.map_err(<Error<T>>::from)?;12351236					Self::deposit_event(Event::CollectionPropertySet(collection.id, key));1237					<PalletEvm<T>>::deposit_log(1238						erc::CollectionHelpersEvents::CollectionChanged {1239							collection_id: eth::collection_id_to_address(collection.id),1240						}1241						.to_log(T::ContractAddress::get()),1242					);1243				}1244				None => {1245					stored_properties.remove(&key).map_err(<Error<T>>::from)?;12461247					Self::deposit_event(Event::CollectionPropertyDeleted(collection.id, key));1248					<PalletEvm<T>>::deposit_log(1249						erc::CollectionHelpersEvents::CollectionChanged {1250							collection_id: eth::collection_id_to_address(collection.id),1251						}1252						.to_log(T::ContractAddress::get()),1253					);1254				}1255			}1256		}12571258		<CollectionProperties<T>>::set(collection.id, stored_properties);12591260		Ok(())1261	}12621263	/// Set collection property.1264	///1265	/// * `collection` - Collection handler.1266	/// * `sender` - The owner or administrator of the collection.1267	/// * `property` - The property to set.1268	pub fn set_collection_property(1269		collection: &CollectionHandle<T>,1270		sender: &T::CrossAccountId,1271		property: Property,1272	) -> DispatchResult {1273		Self::set_collection_properties(collection, sender, [property].into_iter())1274	}12751276	/// Set a scoped collection property, where the scope is a special prefix1277	/// prohibiting a user access to change the property directly.1278	///1279	/// * `collection_id` - ID of the collection for which the property is being set.1280	/// * `scope` - Property scope.1281	/// * `property` - The property to set.1282	pub fn set_scoped_collection_property(1283		collection_id: CollectionId,1284		scope: PropertyScope,1285		property: Property,1286	) -> DispatchResult {1287		CollectionProperties::<T>::try_mutate(collection_id, |properties| {1288			properties.try_scoped_set(scope, property.key, property.value)1289		})1290		.map_err(<Error<T>>::from)?;12911292		Ok(())1293	}12941295	/// Set scoped collection properties, where the scope is a special prefix1296	/// prohibiting a user access to change the properties directly.1297	///1298	/// * `collection_id` - ID of the collection for which the properties is being set.1299	/// * `scope` - Property scope.1300	/// * `properties` - The properties to set.1301	pub fn set_scoped_collection_properties(1302		collection_id: CollectionId,1303		scope: PropertyScope,1304		properties: impl Iterator<Item = Property>,1305	) -> DispatchResult {1306		CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {1307			stored_properties.try_scoped_set_from_iter(scope, properties)1308		})1309		.map_err(<Error<T>>::from)?;13101311		Ok(())1312	}13131314	/// Set collection properties.1315	///1316	/// * `collection` - Collection handler.1317	/// * `sender` - The owner or administrator of the collection.1318	/// * `properties` - The properties to set.1319	pub fn set_collection_properties(1320		collection: &CollectionHandle<T>,1321		sender: &T::CrossAccountId,1322		properties: impl Iterator<Item = Property>,1323	) -> DispatchResult {1324		Self::modify_collection_properties(1325			collection,1326			sender,1327			properties.map(|property| (property.key, Some(property.value))),1328		)1329	}13301331	/// Delete collection property.1332	///1333	/// * `collection` - Collection handler.1334	/// * `sender` - The owner or administrator of the collection.1335	/// * `property` - The property to delete.1336	pub fn delete_collection_property(1337		collection: &CollectionHandle<T>,1338		sender: &T::CrossAccountId,1339		property_key: PropertyKey,1340	) -> DispatchResult {1341		Self::delete_collection_properties(collection, sender, [property_key].into_iter())1342	}13431344	/// Delete collection properties.1345	///1346	/// * `collection` - Collection handler.1347	/// * `sender` - The owner or administrator of the collection.1348	/// * `properties` - The properties to delete.1349	pub fn delete_collection_properties(1350		collection: &CollectionHandle<T>,1351		sender: &T::CrossAccountId,1352		property_keys: impl Iterator<Item = PropertyKey>,1353	) -> DispatchResult {1354		Self::modify_collection_properties(collection, sender, property_keys.map(|key| (key, None)))1355	}13561357	/// Set collection propetry permission without any checks.1358	///1359	/// Used for migrations.1360	///1361	/// * `collection` - Collection handler.1362	/// * `property_permissions` - Property permissions.1363	pub fn set_property_permission_unchecked(1364		collection: CollectionId,1365		property_permission: PropertyKeyPermission,1366	) -> DispatchResult {1367		<CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {1368			permissions.try_set(property_permission.key, property_permission.permission)1369		})1370		.map_err(<Error<T>>::from)?;1371		Ok(())1372	}13731374	/// Set collection property permission.1375	///1376	/// * `collection` - Collection handler.1377	/// * `sender` - The owner or administrator of the collection.1378	/// * `property_permission` - Property permission.1379	pub fn set_property_permission(1380		collection: &CollectionHandle<T>,1381		sender: &T::CrossAccountId,1382		property_permission: PropertyKeyPermission,1383	) -> DispatchResult {1384		Self::set_scoped_property_permission(1385			collection,1386			sender,1387			PropertyScope::None,1388			property_permission,1389		)1390	}13911392	/// Set collection property permission with scope.1393	///1394	/// * `collection` - Collection handler.1395	/// * `sender` - The owner or administrator of the collection.1396	/// * `scope` - Property scope.1397	/// * `property_permission` - Property permission.1398	pub fn set_scoped_property_permission(1399		collection: &CollectionHandle<T>,1400		sender: &T::CrossAccountId,1401		scope: PropertyScope,1402		property_permission: PropertyKeyPermission,1403	) -> DispatchResult {1404		collection.check_is_owner_or_admin(sender)?;14051406		let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);1407		let current_permission = all_permissions.get(&property_permission.key);1408		if matches![1409			current_permission,1410			Some(PropertyPermission { mutable: false, .. })1411		] {1412			return Err(<Error<T>>::NoPermission.into());1413		}14141415		CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {1416			let property_permission = property_permission.clone();1417			permissions.try_scoped_set(1418				scope,1419				property_permission.key,1420				property_permission.permission,1421			)1422		})1423		.map_err(<Error<T>>::from)?;14241425		Self::deposit_event(Event::PropertyPermissionSet(1426			collection.id,1427			property_permission.key,1428		));1429		<PalletEvm<T>>::deposit_log(1430			erc::CollectionHelpersEvents::CollectionChanged {1431				collection_id: eth::collection_id_to_address(collection.id),1432			}1433			.to_log(T::ContractAddress::get()),1434		);14351436		Ok(())1437	}14381439	/// Set token property permission.1440	///1441	/// * `collection` - Collection handler.1442	/// * `sender` - The owner or administrator of the collection.1443	/// * `property_permissions` - Property permissions.1444	#[transactional]1445	pub fn set_token_property_permissions(1446		collection: &CollectionHandle<T>,1447		sender: &T::CrossAccountId,1448		property_permissions: Vec<PropertyKeyPermission>,1449	) -> DispatchResult {1450		Self::set_scoped_token_property_permissions(1451			collection,1452			sender,1453			PropertyScope::None,1454			property_permissions,1455		)1456	}14571458	/// Set token property permission with scope.1459	///1460	/// * `collection` - Collection handler.1461	/// * `sender` - The owner or administrator of the collection.1462	/// * `scope` - Property scope.1463	/// * `property_permissions` - Property permissions.1464	#[transactional]1465	pub fn set_scoped_token_property_permissions(1466		collection: &CollectionHandle<T>,1467		sender: &T::CrossAccountId,1468		scope: PropertyScope,1469		property_permissions: Vec<PropertyKeyPermission>,1470	) -> DispatchResult {1471		for prop_pemission in property_permissions {1472			Self::set_scoped_property_permission(collection, sender, scope, prop_pemission)?;1473		}14741475		Ok(())1476	}14771478	/// Get collection property.1479	pub fn get_collection_property(1480		collection_id: CollectionId,1481		key: &PropertyKey,1482	) -> Option<PropertyValue> {1483		Self::collection_properties(collection_id).get(key).cloned()1484	}14851486	/// Convert byte vector to property key vector.1487	pub fn bytes_keys_to_property_keys(1488		keys: Vec<Vec<u8>>,1489	) -> Result<Vec<PropertyKey>, DispatchError> {1490		keys.into_iter()1491			.map(|key| -> Result<PropertyKey, DispatchError> {1492				key.try_into()1493					.map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1494			})1495			.collect::<Result<Vec<PropertyKey>, DispatchError>>()1496	}14971498	/// Get properties according to given keys.1499	pub fn filter_collection_properties(1500		collection_id: CollectionId,1501		keys: Option<Vec<PropertyKey>>,1502	) -> Result<Vec<Property>, DispatchError> {1503		let properties = Self::collection_properties(collection_id);15041505		let properties = keys1506			.map(|keys| {1507				keys.into_iter()1508					.filter_map(|key| {1509						properties.get(&key).map(|value| Property {1510							key,1511							value: value.clone(),1512						})1513					})1514					.collect()1515			})1516			.unwrap_or_else(|| {1517				properties1518					.into_iter()1519					.map(|(key, value)| Property { key, value })1520					.collect()1521			});15221523		Ok(properties)1524	}15251526	/// Get property permissions according to given keys.1527	pub fn filter_property_permissions(1528		collection_id: CollectionId,1529		keys: Option<Vec<PropertyKey>>,1530	) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1531		let permissions = Self::property_permissions(collection_id);15321533		let key_permissions = keys1534			.map(|keys| {1535				keys.into_iter()1536					.filter_map(|key| {1537						permissions1538							.get(&key)1539							.map(|permission| PropertyKeyPermission {1540								key,1541								permission: permission.clone(),1542							})1543					})1544					.collect()1545			})1546			.unwrap_or_else(|| {1547				permissions1548					.into_iter()1549					.map(|(key, permission)| PropertyKeyPermission { key, permission })1550					.collect()1551			});15521553		Ok(key_permissions)1554	}15551556	/// Toggle `user` participation in the `collection`'s allow list.1557	/// #### Store read/writes1558	/// 1 writes1559	pub fn toggle_allowlist(1560		collection: &CollectionHandle<T>,1561		sender: &T::CrossAccountId,1562		user: &T::CrossAccountId,1563		allowed: bool,1564	) -> DispatchResult {1565		collection.check_is_owner_or_admin(sender)?;15661567		// =========15681569		if allowed {1570			<Allowlist<T>>::insert((collection.id, user), true);1571			Self::deposit_event(Event::<T>::AllowListAddressAdded(1572				collection.id,1573				user.clone(),1574			));1575		} else {1576			<Allowlist<T>>::remove((collection.id, user));1577			Self::deposit_event(Event::<T>::AllowListAddressRemoved(1578				collection.id,1579				user.clone(),1580			));1581		}15821583		<PalletEvm<T>>::deposit_log(1584			erc::CollectionHelpersEvents::CollectionChanged {1585				collection_id: eth::collection_id_to_address(collection.id),1586			}1587			.to_log(T::ContractAddress::get()),1588		);15891590		Ok(())1591	}15921593	/// Toggle `user` participation in the `collection`'s admin list.1594	/// #### Store read/writes1595	/// 2 reads, 2 writes1596	pub fn toggle_admin(1597		collection: &CollectionHandle<T>,1598		sender: &T::CrossAccountId,1599		user: &T::CrossAccountId,1600		admin: bool,1601	) -> DispatchResult {1602		collection.check_is_internal()?;1603		collection.check_is_owner(sender)?;16041605		let is_admin = <IsAdmin<T>>::get((collection.id, user));1606		if is_admin == admin {1607			if admin {1608				return Ok(());1609			} else {1610				return Err(Error::<T>::UserIsNotCollectionAdmin.into());1611			}1612		}1613		let amount = <AdminAmount<T>>::get(collection.id);16141615		// =========16161617		if admin {1618			let amount = amount1619				.checked_add(1)1620				.ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1621			ensure!(1622				amount <= Self::collection_admins_limit(),1623				<Error<T>>::CollectionAdminCountExceeded,1624			);16251626			<AdminAmount<T>>::insert(collection.id, amount);1627			<IsAdmin<T>>::insert((collection.id, user), true);16281629			Self::deposit_event(Event::<T>::CollectionAdminAdded(1630				collection.id,1631				user.clone(),1632			));1633		} else {1634			<AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1635			<IsAdmin<T>>::remove((collection.id, user));16361637			Self::deposit_event(Event::<T>::CollectionAdminRemoved(1638				collection.id,1639				user.clone(),1640			));1641		}16421643		<PalletEvm<T>>::deposit_log(1644			erc::CollectionHelpersEvents::CollectionChanged {1645				collection_id: eth::collection_id_to_address(collection.id),1646			}1647			.to_log(T::ContractAddress::get()),1648		);16491650		Ok(())1651	}16521653	/// Update collection limits.1654	pub fn update_limits(1655		user: &T::CrossAccountId,1656		collection: &mut CollectionHandle<T>,1657		new_limit: CollectionLimits,1658	) -> DispatchResult {1659		collection.check_is_internal()?;1660		collection.check_is_owner_or_admin(user)?;16611662		collection.limits =1663			Self::clamp_limits(collection.mode.clone(), &collection.limits, new_limit)?;16641665		Self::deposit_event(Event::<T>::CollectionLimitSet(collection.id));1666		<PalletEvm<T>>::deposit_log(1667			erc::CollectionHelpersEvents::CollectionChanged {1668				collection_id: eth::collection_id_to_address(collection.id),1669			}1670			.to_log(T::ContractAddress::get()),1671		);16721673		collection.save()1674	}16751676	/// Merge set fields from `new_limit` to `old_limit`.1677	fn clamp_limits(1678		mode: CollectionMode,1679		old_limit: &CollectionLimits,1680		mut new_limit: CollectionLimits,1681	) -> Result<CollectionLimits, DispatchError> {1682		let limits = old_limit;1683		limit_default!(old_limit, new_limit,1684			account_token_ownership_limit => ensure!(1685				new_limit <= MAX_TOKEN_OWNERSHIP,1686				<Error<T>>::CollectionLimitBoundsExceeded,1687			),1688			sponsored_data_size => ensure!(1689				new_limit <= CUSTOM_DATA_LIMIT,1690				<Error<T>>::CollectionLimitBoundsExceeded,1691			),16921693			sponsored_data_rate_limit => {},1694			token_limit => ensure!(1695				old_limit >= new_limit && new_limit > 0,1696				<Error<T>>::CollectionTokenLimitExceeded1697			),16981699			sponsor_transfer_timeout(match mode {1700				CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1701				CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1702				CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1703			}) => ensure!(1704				new_limit <= MAX_SPONSOR_TIMEOUT,1705				<Error<T>>::CollectionLimitBoundsExceeded,1706			),1707			sponsor_approve_timeout => {},1708			owner_can_transfer => ensure!(1709				!limits.owner_can_transfer_instaled() ||1710				old_limit || !new_limit,1711				<Error<T>>::OwnerPermissionsCantBeReverted,1712			),1713			owner_can_destroy => ensure!(1714				old_limit || !new_limit,1715				<Error<T>>::OwnerPermissionsCantBeReverted,1716			),1717			transfers_enabled => {},1718		);1719		Ok(new_limit)1720	}17211722	/// Update collection permissions.1723	pub fn update_permissions(1724		user: &T::CrossAccountId,1725		collection: &mut CollectionHandle<T>,1726		new_permission: CollectionPermissions,1727	) -> DispatchResult {1728		collection.check_is_internal()?;1729		collection.check_is_owner_or_admin(user)?;1730		collection.permissions = Self::clamp_permissions(1731			collection.mode.clone(),1732			&collection.permissions,1733			new_permission,1734		)?;17351736		Self::deposit_event(Event::<T>::CollectionPermissionSet(collection.id));1737		<PalletEvm<T>>::deposit_log(1738			erc::CollectionHelpersEvents::CollectionChanged {1739				collection_id: eth::collection_id_to_address(collection.id),1740			}1741			.to_log(T::ContractAddress::get()),1742		);17431744		collection.save()1745	}17461747	/// Merge set fields from `new_permission` to `old_permission`.1748	fn clamp_permissions(1749		_mode: CollectionMode,1750		old_permission: &CollectionPermissions,1751		mut new_permission: CollectionPermissions,1752	) -> Result<CollectionPermissions, DispatchError> {1753		limit_default_clone!(old_permission, new_permission,1754			access => {},1755			mint_mode => {},1756			nesting => { /* todo check for permissive, if only it gets out of benchmarks */ },1757		);1758		Ok(new_permission)1759	}17601761	/// Repair possibly broken properties of a collection.1762	pub fn repair_collection(collection_id: CollectionId) -> DispatchResult {1763		CollectionProperties::<T>::mutate(collection_id, |properties| {1764			properties.recompute_consumed_space();1765		});17661767		Ok(())1768	}1769}17701771/// Indicates unsupported methods by returning [Error::UnsupportedOperation].1772#[macro_export]1773macro_rules! unsupported {1774	($runtime:path) => {1775		Err($crate::Error::<$runtime>::UnsupportedOperation.into())1776	};1777}17781779/// Return weights for various worst-case operations.1780pub trait CommonWeightInfo<CrossAccountId> {1781	/// Weight of item creation.1782	fn create_item() -> Weight;17831784	/// Weight of items creation.1785	fn create_multiple_items(amount: &[CreateItemData]) -> Weight;17861787	/// Weight of items creation.1788	fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;17891790	/// The weight of the burning item.1791	fn burn_item() -> Weight;17921793	/// Property setting weight.1794	///1795	/// * `amount`- The number of properties to set.1796	fn set_collection_properties(amount: u32) -> Weight;17971798	/// Collection property deletion weight.1799	///1800	/// * `amount`- The number of properties to set.1801	fn delete_collection_properties(amount: u32) -> Weight;18021803	/// Token property setting weight.1804	///1805	/// * `amount`- The number of properties to set.1806	fn set_token_properties(amount: u32) -> Weight;18071808	/// Token property deletion weight.1809	///1810	/// * `amount`- The number of properties to delete.1811	fn delete_token_properties(amount: u32) -> Weight;18121813	/// Token property permissions set weight.1814	///1815	/// * `amount`- The number of property permissions to set.1816	fn set_token_property_permissions(amount: u32) -> Weight;18171818	/// Transfer price of the token or its parts.1819	fn transfer() -> Weight;18201821	/// The price of setting the permission of the operation from another user.1822	fn approve() -> Weight;18231824	/// The price of setting the permission of the operation from another user for eth mirror.1825	fn approve_from() -> Weight;18261827	/// Transfer price from another user.1828	fn transfer_from() -> Weight;18291830	/// The price of burning a token from another user.1831	fn burn_from() -> Weight;18321833	/// Differs from burn_item in case of Fungible and Refungible, as it should burn1834	/// whole users's balance.1835	///1836	/// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1837	fn burn_recursively_self_raw() -> Weight;18381839	/// Cost of iterating over `amount` children while burning, without counting child burning itself.1840	///1841	/// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead1842	fn burn_recursively_breadth_raw(amount: u32) -> Weight;18431844	/// The price of recursive burning a token.1845	///1846	/// `max_selfs` - The maximum burning weight of the token itself.1847	/// `max_breadth` - The maximum number of nested tokens to burn.1848	fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight {1849		Self::burn_recursively_self_raw()1850			.saturating_mul(max_selfs.max(1) as u64)1851			.saturating_add(Self::burn_recursively_breadth_raw(max_breadth))1852	}18531854	/// The price of retrieving token owner1855	fn token_owner() -> Weight;18561857	/// The price of setting approval for all1858	fn set_allowance_for_all() -> Weight;18591860	/// The price of repairing an item.1861	fn force_repair_item() -> Weight;1862}18631864/// Weight info extension trait for refungible pallet.1865pub trait RefungibleExtensionsWeightInfo {1866	/// Weight of token repartition.1867	fn repartition() -> Weight;1868}18691870/// Common collection operations.1871///1872/// It wraps methods in Fungible, Nonfungible and Refungible pallets1873/// and adds weight info.1874pub trait CommonCollectionOperations<T: Config> {1875	/// Create token.1876	///1877	/// * `sender` - The user who mint the token and pays for the transaction.1878	/// * `to` - The user who will own the token.1879	/// * `data` - Token data.1880	/// * `nesting_budget` - A budget that can be spent on nesting tokens.1881	fn create_item(1882		&self,1883		sender: T::CrossAccountId,1884		to: T::CrossAccountId,1885		data: CreateItemData,1886		nesting_budget: &dyn Budget,1887	) -> DispatchResultWithPostInfo;18881889	/// Create multiple tokens.1890	///1891	/// * `sender` - The user who mint the token and pays for the transaction.1892	/// * `to` - The user who will own the token.1893	/// * `data` - Token data.1894	/// * `nesting_budget` - A budget that can be spent on nesting tokens.1895	fn create_multiple_items(1896		&self,1897		sender: T::CrossAccountId,1898		to: T::CrossAccountId,1899		data: Vec<CreateItemData>,1900		nesting_budget: &dyn Budget,1901	) -> DispatchResultWithPostInfo;19021903	/// Create multiple tokens.1904	///1905	/// * `sender` - The user who mint the token and pays for the transaction.1906	/// * `to` - The user who will own the token.1907	/// * `data` - Token data.1908	/// * `nesting_budget` - A budget that can be spent on nesting tokens.1909	fn create_multiple_items_ex(1910		&self,1911		sender: T::CrossAccountId,1912		data: CreateItemExData<T::CrossAccountId>,1913		nesting_budget: &dyn Budget,1914	) -> DispatchResultWithPostInfo;19151916	/// Burn token.1917	///1918	/// * `sender` - The user who owns the token.1919	/// * `token` - Token id that will burned.1920	/// * `amount` - The number of parts of the token that will be burned.1921	fn burn_item(1922		&self,1923		sender: T::CrossAccountId,1924		token: TokenId,1925		amount: u128,1926	) -> DispatchResultWithPostInfo;19271928	/// Burn token and all nested tokens recursievly.1929	///1930	/// * `sender` - The user who owns the token.1931	/// * `token` - Token id that will burned.1932	/// * `self_budget` - The budget that can be spent on burning tokens.1933	/// * `breadth_budget` - The budget that can be spent on burning nested tokens.1934	fn burn_item_recursively(1935		&self,1936		sender: T::CrossAccountId,1937		token: TokenId,1938		self_budget: &dyn Budget,1939		breadth_budget: &dyn Budget,1940	) -> DispatchResultWithPostInfo;19411942	/// Set collection properties.1943	///1944	/// * `sender` - Must be either the owner of the collection or its admin.1945	/// * `properties` - Properties to be set.1946	fn set_collection_properties(1947		&self,1948		sender: T::CrossAccountId,1949		properties: Vec<Property>,1950	) -> DispatchResultWithPostInfo;19511952	/// Delete collection properties.1953	///1954	/// * `sender` - Must be either the owner of the collection or its admin.1955	/// * `properties` - The properties to be removed.1956	fn delete_collection_properties(1957		&self,1958		sender: &T::CrossAccountId,1959		property_keys: Vec<PropertyKey>,1960	) -> DispatchResultWithPostInfo;19611962	/// Set token properties.1963	///1964	/// The appropriate [`PropertyPermission`] for the token property1965	/// must be set with [`Self::set_token_property_permissions`].1966	///1967	/// * `sender` - Must be either the owner of the token or its admin.1968	/// * `token_id` - The token for which the properties are being set.1969	/// * `properties` - Properties to be set.1970	/// * `budget` - Budget for setting properties.1971	fn set_token_properties(1972		&self,1973		sender: T::CrossAccountId,1974		token_id: TokenId,1975		properties: Vec<Property>,1976		budget: &dyn Budget,1977	) -> DispatchResultWithPostInfo;19781979	/// Remove token properties.1980	///1981	/// The appropriate [`PropertyPermission`] for the token property1982	/// must be set with [`Self::set_token_property_permissions`].1983	///1984	/// * `sender` - Must be either the owner of the token or its admin.1985	/// * `token_id` - The token for which the properties are being remove.1986	/// * `property_keys` - Keys to remove corresponding properties.1987	/// * `budget` - Budget for removing properties.1988	fn delete_token_properties(1989		&self,1990		sender: T::CrossAccountId,1991		token_id: TokenId,1992		property_keys: Vec<PropertyKey>,1993		budget: &dyn Budget,1994	) -> DispatchResultWithPostInfo;19951996	/// Set token property permissions.1997	///1998	/// * `sender` - Must be either the owner of the token or its admin.1999	/// * `token_id` - The token for which the properties are being set.2000	/// * `property_permissions` - Property permissions to be set.2001	/// * `budget` - Budget for setting properties.2002	fn set_token_property_permissions(2003		&self,2004		sender: &T::CrossAccountId,2005		property_permissions: Vec<PropertyKeyPermission>,2006	) -> DispatchResultWithPostInfo;20072008	/// Transfer amount of token pieces.2009	///2010	/// * `sender` - Donor user.2011	/// * `to` - Recepient user.2012	/// * `token` - The token of which parts are being sent.2013	/// * `amount` - The number of parts of the token that will be transferred.2014	/// * `budget` - The maximum budget that can be spent on the transfer.2015	fn transfer(2016		&self,2017		sender: T::CrossAccountId,2018		to: T::CrossAccountId,2019		token: TokenId,2020		amount: u128,2021		budget: &dyn Budget,2022	) -> DispatchResultWithPostInfo;20232024	/// Grant access to another account to transfer parts of the token owned by the calling user via [Self::transfer_from].2025	///2026	/// * `sender` - The user who grants access to the token.2027	/// * `spender` - The user to whom the rights are granted.2028	/// * `token` - The token to which access is granted.2029	/// * `amount` - The amount of pieces that another user can dispose of.2030	fn approve(2031		&self,2032		sender: T::CrossAccountId,2033		spender: T::CrossAccountId,2034		token: TokenId,2035		amount: u128,2036	) -> DispatchResultWithPostInfo;20372038	/// Grant access to another account to transfer parts of the token owned by the calling user's eth mirror via [Self::transfer_from].2039	///2040	/// * `sender` - The user who grants access to the token.2041	/// * `from` - Spender's eth mirror.2042	/// * `to` - The user to whom the rights are granted.2043	/// * `token` - The token to which access is granted.2044	/// * `amount` - The amount of pieces that another user can dispose of.2045	fn approve_from(2046		&self,2047		sender: T::CrossAccountId,2048		from: T::CrossAccountId,2049		to: T::CrossAccountId,2050		token: TokenId,2051		amount: u128,2052	) -> DispatchResultWithPostInfo;20532054	/// Send parts of a token owned by another user.2055	///2056	/// Before calling this method, you must grant rights to the calling user via [`Self::approve`].2057	///2058	/// * `sender` - The user who must have access to the token (see [`Self::approve`]).2059	/// * `from` - The user who owns the token.2060	/// * `to` - Recepient user.2061	/// * `token` - The token of which parts are being sent.2062	/// * `amount` - The number of parts of the token that will be transferred.2063	/// * `budget` - The maximum budget that can be spent on the transfer.2064	fn transfer_from(2065		&self,2066		sender: T::CrossAccountId,2067		from: T::CrossAccountId,2068		to: T::CrossAccountId,2069		token: TokenId,2070		amount: u128,2071		budget: &dyn Budget,2072	) -> DispatchResultWithPostInfo;20732074	/// Burn parts of a token owned by another user.2075	///2076	/// Before calling this method, you must grant rights to the calling user via [`Self::approve`].2077	///2078	/// * `sender` - The user who must have access to the token (see [`Self::approve`]).2079	/// * `from` - The user who owns the token.2080	/// * `token` - The token of which parts are being sent.2081	/// * `amount` - The number of parts of the token that will be transferred.2082	/// * `budget` - The maximum budget that can be spent on the burn.2083	fn burn_from(2084		&self,2085		sender: T::CrossAccountId,2086		from: T::CrossAccountId,2087		token: TokenId,2088		amount: u128,2089		budget: &dyn Budget,2090	) -> DispatchResultWithPostInfo;20912092	/// Check permission to nest token.2093	///2094	/// * `sender` - The user who initiated the check.2095	/// * `from` - The token that is checked for embedding.2096	/// * `under` - Token under which to check.2097	/// * `budget` - The maximum budget that can be spent on the check.2098	fn check_nesting(2099		&self,2100		sender: T::CrossAccountId,2101		from: (CollectionId, TokenId),2102		under: TokenId,2103		budget: &dyn Budget,2104	) -> DispatchResult;21052106	/// Nest one token into another.2107	///2108	/// * `under` - Token holder.2109	/// * `to_nest` - Nested token.2110	fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));21112112	/// Unnest token.2113	///2114	/// * `under` - Token holder.2115	/// * `to_nest` - Token to unnest.2116	fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));21172118	/// Get all user tokens.2119	///2120	/// * `account` - Account for which you need to get tokens.2121	fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;21222123	/// Get all the tokens in the collection.2124	fn collection_tokens(&self) -> Vec<TokenId>;21252126	/// Check if the token exists.2127	///2128	/// * `token` - Id token to check.2129	fn token_exists(&self, token: TokenId) -> bool;21302131	/// Get the id of the last minted token.2132	fn last_token_id(&self) -> TokenId;21332134	/// Get the owner of the token.2135	///2136	/// * `token` - The token for which you need to find out the owner.2137	fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;21382139	/// Returns 10 tokens owners in no particular order.2140	///2141	/// * `token` - The token for which you need to find out the owners.2142	fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId>;21432144	/// Get the value of the token property by key.2145	///2146	/// * `token` - Token with the property to get.2147	/// * `key` - Property name.2148	fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;21492150	/// Get a set of token properties by key vector.2151	///2152	/// * `token` - Token with the property to get.2153	/// * `keys` - Vector of property keys. If this parameter is [None](sp_std::result::Result),2154	/// then all properties are returned.2155	fn token_properties(&self, token: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;21562157	/// Amount of unique collection tokens2158	fn total_supply(&self) -> u32;21592160	/// Amount of different tokens account has.2161	///2162	/// * `account` - The account for which need to get the balance.2163	fn account_balance(&self, account: T::CrossAccountId) -> u32;21642165	/// Amount of specific token account have.2166	fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;21672168	/// Amount of token pieces2169	fn total_pieces(&self, token: TokenId) -> Option<u128>;21702171	/// Get the number of parts of the token that a trusted user can manage.2172	///2173	/// * `sender` - Trusted user.2174	/// * `spender` - Owner of the token.2175	/// * `token` - The token for which to get the value.2176	fn allowance(2177		&self,2178		sender: T::CrossAccountId,2179		spender: T::CrossAccountId,2180		token: TokenId,2181	) -> u128;21822183	/// Get extension for RFT collection.2184	fn refungible_extensions(&self) -> Option<&dyn RefungibleExtensions<T>>;21852186	/// The `operator` is allowed to transfer all tokens of the `owner` on their behalf.2187	/// * `owner` - Token owner2188	/// * `operator` - Operator2189	/// * `approve` - Should operator status be granted or revoked?2190	fn set_allowance_for_all(2191		&self,2192		owner: T::CrossAccountId,2193		operator: T::CrossAccountId,2194		approve: bool,2195	) -> DispatchResultWithPostInfo;21962197	/// Tells whether the given `owner` approves the `operator`.2198	fn allowance_for_all(&self, owner: T::CrossAccountId, operator: T::CrossAccountId) -> bool;21992200	/// Repairs a possibly broken item.2201	fn repair_item(&self, token: TokenId) -> DispatchResultWithPostInfo;2202}22032204/// Extension for RFT collection.2205pub trait RefungibleExtensions<T>2206where2207	T: Config,2208{2209	/// Change the number of parts of the token.2210	///2211	/// When the value changes down, this function is equivalent to burning parts of the token.2212	///2213	/// * `sender` - The user calling the repartition operation. Must be the owner of the token.2214	/// * `token` - The token for which you want to change the number of parts.2215	/// * `amount` - The new value of the parts of the token.2216	fn repartition(2217		&self,2218		sender: &T::CrossAccountId,2219		token: TokenId,2220		amount: u128,2221	) -> DispatchResultWithPostInfo;2222}22232224/// Merge [`DispatchResult`] with [`Weight`] into [`DispatchResultWithPostInfo`].2225///2226/// Used for [`CommonCollectionOperations`] implementations and flexible enough to do so.2227pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {2228	let post_info = PostDispatchInfo {2229		actual_weight: Some(weight),2230		pays_fee: Pays::Yes,2231	};2232	match res {2233		Ok(()) => Ok(post_info),2234		Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),2235	}2236}22372238impl<T: Config> From<PropertiesError> for Error<T> {2239	fn from(error: PropertiesError) -> Self {2240		match error {2241			PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,2242			PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,2243			PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,2244			PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,2245			PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,2246		}2247	}2248}
modifiedpallets/evm-coder-substrate/src/lib.rsdiffbeforeafterboth
--- a/pallets/evm-coder-substrate/src/lib.rs
+++ b/pallets/evm-coder-substrate/src/lib.rs
@@ -41,7 +41,7 @@
 use evm_coder::{
 	abi::{AbiReader, AbiWrite, AbiWriter},
 	execution,
-	types::{Msg, value},
+	types::{Msg, Value},
 };
 
 pub use pallet::*;
@@ -256,7 +256,7 @@
 >(
 	caller: H160,
 	e: &mut E,
-	value: value,
+	value: Value,
 	input: &[u8],
 ) -> execution::Result<Option<AbiWriter>> {
 	let (selector, mut reader) = AbiReader::new_call(input)?;
modifiedpallets/evm-contract-helpers/src/eth.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/eth.rs
+++ b/pallets/evm-contract-helpers/src/eth.rs
@@ -49,25 +49,25 @@
 	ContractSponsorSet {
 		/// Contract address of the affected collection.
 		#[indexed]
-		contract_address: address,
+		contract_address: Address,
 		/// New sponsor address.
-		sponsor: address,
+		sponsor: Address,
 	},
 
 	/// New sponsor was confirm.
 	ContractSponsorshipConfirmed {
 		/// Contract address of the affected collection.
 		#[indexed]
-		contract_address: address,
+		contract_address: Address,
 		/// New sponsor address.
-		sponsor: address,
+		sponsor: Address,
 	},
 
 	/// Collection sponsor was removed.
 	ContractSponsorRemoved {
 		/// Contract address of the affected collection.
 		#[indexed]
-		contract_address: address,
+		contract_address: Address,
 	},
 }
 
@@ -96,7 +96,7 @@
 	/// @dev Returns zero address if contract does not exists
 	/// @param contractAddress Contract to get owner of
 	/// @return address Owner of contract
-	fn contract_owner(&self, contract_address: address) -> Result<address> {
+	fn contract_owner(&self, contract_address: Address) -> Result<Address> {
 		Ok(<Owner<T>>::get(contract_address))
 	}
 
@@ -105,10 +105,10 @@
 	/// @param sponsor User address who set as pending sponsor.
 	fn set_sponsor(
 		&mut self,
-		caller: caller,
-		contract_address: address,
-		sponsor: address,
-	) -> Result<void> {
+		caller: Caller,
+		contract_address: Address,
+		sponsor: Address,
+	) -> Result<()> {
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
@@ -125,7 +125,7 @@
 	/// Set contract as self sponsored.
 	///
 	/// @param contractAddress Contract for which a self sponsoring is being enabled.
-	fn self_sponsored_enable(&mut self, caller: caller, contract_address: address) -> Result<void> {
+	fn self_sponsored_enable(&mut self, caller: Caller, contract_address: Address) -> Result<()> {
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
@@ -146,7 +146,7 @@
 	/// Remove sponsor.
 	///
 	/// @param contractAddress Contract for which a sponsorship is being removed.
-	fn remove_sponsor(&mut self, caller: caller, contract_address: address) -> Result<void> {
+	fn remove_sponsor(&mut self, caller: Caller, contract_address: Address) -> Result<()> {
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
@@ -161,7 +161,7 @@
 	/// @dev Caller must be same that set via [`setSponsor`].
 	///
 	/// @param contractAddress Сontract for which need to confirm sponsorship.
-	fn confirm_sponsorship(&mut self, caller: caller, contract_address: address) -> Result<void> {
+	fn confirm_sponsorship(&mut self, caller: Caller, contract_address: Address) -> Result<()> {
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
@@ -175,7 +175,7 @@
 	///
 	/// @param contractAddress The contract for which a sponsor is requested.
 	/// @return Tuble with sponsor address and his substrate mirror. If there is no confirmed sponsor error "Contract has no sponsor" throw.
-	fn sponsor(&self, contract_address: address) -> Result<Option<eth::CrossAddress>> {
+	fn sponsor(&self, contract_address: Address) -> Result<Option<eth::CrossAddress>> {
 		Ok(match Pallet::<T>::get_sponsor(contract_address) {
 			Some(ref value) => Some(eth::CrossAddress::from_sub_cross_account::<T>(value)),
 			None => None,
@@ -186,7 +186,7 @@
 	///
 	/// @param contractAddress The contract for which the presence of a confirmed sponsor is checked.
 	/// @return **true** if contract has confirmed sponsor.
-	fn has_sponsor(&self, contract_address: address) -> Result<bool> {
+	fn has_sponsor(&self, contract_address: Address) -> Result<bool> {
 		Ok(Pallet::<T>::get_sponsor(contract_address).is_some())
 	}
 
@@ -194,23 +194,23 @@
 	///
 	/// @param contractAddress The contract for which the presence of a pending sponsor is checked.
 	/// @return **true** if contract has pending sponsor.
-	fn has_pending_sponsor(&self, contract_address: address) -> Result<bool> {
+	fn has_pending_sponsor(&self, contract_address: Address) -> Result<bool> {
 		Ok(match Sponsoring::<T>::get(contract_address) {
 			SponsorshipState::Disabled | SponsorshipState::Confirmed(_) => false,
 			SponsorshipState::Unconfirmed(_) => true,
 		})
 	}
 
-	fn sponsoring_enabled(&self, contract_address: address) -> Result<bool> {
+	fn sponsoring_enabled(&self, contract_address: Address) -> Result<bool> {
 		Ok(<Pallet<T>>::sponsoring_mode(contract_address) != SponsoringModeT::Disabled)
 	}
 
 	fn set_sponsoring_mode(
 		&mut self,
-		caller: caller,
-		contract_address: address,
+		caller: Caller,
+		contract_address: Address,
 		mode: SponsoringModeT,
-	) -> Result<void> {
+	) -> Result<()> {
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
@@ -223,7 +223,7 @@
 	/// Get current contract sponsoring rate limit
 	/// @param contractAddress Contract to get sponsoring rate limit of
 	/// @return uint32 Amount of blocks between two sponsored transactions
-	fn sponsoring_rate_limit(&self, contract_address: address) -> Result<uint32> {
+	fn sponsoring_rate_limit(&self, contract_address: Address) -> Result<u32> {
 		self.recorder().consume_sload()?;
 
 		Ok(<SponsoringRateLimit<T>>::get(contract_address)
@@ -239,10 +239,10 @@
 	/// @dev Only contract owner can change this setting
 	fn set_sponsoring_rate_limit(
 		&mut self,
-		caller: caller,
-		contract_address: address,
-		rate_limit: uint32,
-	) -> Result<void> {
+		caller: Caller,
+		contract_address: Address,
+		rate_limit: u32,
+	) -> Result<()> {
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
@@ -259,10 +259,10 @@
 	/// @dev Only contract owner can change this setting
 	fn set_sponsoring_fee_limit(
 		&mut self,
-		caller: caller,
-		contract_address: address,
-		fee_limit: uint256,
-	) -> Result<void> {
+		caller: Caller,
+		contract_address: Address,
+		fee_limit: U256,
+	) -> Result<()> {
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
@@ -276,7 +276,7 @@
 	/// @param contractAddress Contract to get sponsoring fee limit of
 	/// @return uint256 Maximum amount of fee that could be spent by single
 	///  transaction
-	fn sponsoring_fee_limit(&self, contract_address: address) -> Result<uint256> {
+	fn sponsoring_fee_limit(&self, contract_address: Address) -> Result<U256> {
 		self.recorder().consume_sload()?;
 
 		Ok(get_sponsoring_fee_limit::<T>(contract_address))
@@ -287,7 +287,7 @@
 	/// @param contractAddress Contract to check allowlist of
 	/// @param user User to check
 	/// @return bool Is specified users exists in contract allowlist
-	fn allowed(&self, contract_address: address, user: address) -> Result<bool> {
+	fn allowed(&self, contract_address: Address, user: Address) -> Result<bool> {
 		self.0.consume_sload()?;
 		Ok(<Pallet<T>>::allowed(contract_address, user))
 	}
@@ -300,11 +300,11 @@
 	/// @dev Only contract owner can change this setting
 	fn toggle_allowed(
 		&mut self,
-		caller: caller,
-		contract_address: address,
-		user: address,
+		caller: Caller,
+		contract_address: Address,
+		user: Address,
 		is_allowed: bool,
-	) -> Result<void> {
+	) -> Result<()> {
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
@@ -320,7 +320,7 @@
 	///  in case of allowlist access enabled, only users from allowlist may call this contract
 	/// @param contractAddress Contract to get allowlist access of
 	/// @return bool Is specified contract has allowlist access enabled
-	fn allowlist_enabled(&self, contract_address: address) -> Result<bool> {
+	fn allowlist_enabled(&self, contract_address: Address) -> Result<bool> {
 		Ok(<AllowlistEnabled<T>>::get(contract_address))
 	}
 
@@ -329,10 +329,10 @@
 	/// @param enabled Should allowlist access to be enabled?
 	fn toggle_allowlist(
 		&mut self,
-		caller: caller,
-		contract_address: address,
+		caller: Caller,
+		contract_address: Address,
 		enabled: bool,
-	) -> Result<void> {
+	) -> Result<()> {
 		self.recorder().consume_sload()?;
 		self.recorder().consume_sstore()?;
 
@@ -441,7 +441,7 @@
 	}
 }
 
-fn get_sponsoring_fee_limit<T: Config>(contract_address: address) -> uint256 {
+fn get_sponsoring_fee_limit<T: Config>(contract_address: Address) -> U256 {
 	<SponsoringFeeLimit<T>>::get(contract_address)
 		.get(&0xffffffff)
 		.cloned()
modifiedpallets/evm-contract-helpers/src/lib.rsdiffbeforeafterboth
--- a/pallets/evm-contract-helpers/src/lib.rs
+++ b/pallets/evm-contract-helpers/src/lib.rs
@@ -69,7 +69,7 @@
 	}
 
 	#[pallet::pallet]
-	#[pallet::generate_store(pub(super) trait Store)]
+	#[pallet::generate_store(trait Store)]
 	pub struct Pallet<T>(_);
 
 	/// Store owner for contract.
@@ -80,9 +80,9 @@
 	pub(super) type Owner<T: Config> =
 		StorageMap<Hasher = Twox128, Key = H160, Value = H160, QueryKind = ValueQuery>;
 
+	/// Deprecated: this storage is deprecated
 	#[pallet::storage]
-	#[deprecated]
-	pub(super) type SelfSponsoring<T: Config> =
+	type SelfSponsoring<T: Config> =
 		StorageMap<Hasher = Twox128, Key = H160, Value = bool, QueryKind = ValueQuery>;
 
 	/// Store for contract sponsorship state.
@@ -349,6 +349,7 @@
 		}
 
 		/// Get current sponsoring mode, performing lazy migration from legacy storage
+		/// Deprecated: this method is for deprecated storage
 		pub fn sponsoring_mode(contract: H160) -> SponsoringModeT {
 			<SponsoringMode<T>>::get(contract)
 				.or_else(|| {
@@ -359,6 +360,7 @@
 		}
 
 		/// Reconfigure contract sponsoring mode
+		/// Deprecated: this method is for deprecated storage
 		pub fn set_sponsoring_mode(contract: H160, mode: SponsoringModeT) {
 			if mode == SponsoringModeT::Disabled {
 				<SponsoringMode<T>>::remove(contract);
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -32,7 +32,7 @@
 use pallet_evm::{account::CrossAccountId, PrecompileHandle};
 use pallet_evm_coder_substrate::{call, dispatch_to_evm};
 use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
-use sp_core::Get;
+use sp_core::{U256, Get};
 
 use crate::{
 	Allowance, Balance, Config, FungibleHandle, Pallet, SelfWeightOf, TotalSupply,
@@ -43,50 +43,50 @@
 pub enum ERC20Events {
 	Transfer {
 		#[indexed]
-		from: address,
+		from: Address,
 		#[indexed]
-		to: address,
-		value: uint256,
+		to: Address,
+		value: U256,
 	},
 	Approval {
 		#[indexed]
-		owner: address,
+		owner: Address,
 		#[indexed]
-		spender: address,
-		value: uint256,
+		spender: Address,
+		value: U256,
 	},
 }
 
 #[solidity_interface(name = ERC20, events(ERC20Events))]
 impl<T: Config> FungibleHandle<T> {
-	fn name(&self) -> Result<string> {
+	fn name(&self) -> Result<String> {
 		Ok(decode_utf16(self.name.iter().copied())
 			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
-			.collect::<string>())
+			.collect::<String>())
 	}
-	fn symbol(&self) -> Result<string> {
-		Ok(string::from_utf8_lossy(&self.token_prefix).into())
+	fn symbol(&self) -> Result<String> {
+		Ok(String::from_utf8_lossy(&self.token_prefix).into())
 	}
-	fn total_supply(&self) -> Result<uint256> {
+	fn total_supply(&self) -> Result<U256> {
 		self.consume_store_reads(1)?;
 		Ok(<TotalSupply<T>>::get(self.id).into())
 	}
 
-	fn decimals(&self) -> Result<uint8> {
+	fn decimals(&self) -> Result<u8> {
 		Ok(if let CollectionMode::Fungible(decimals) = &self.mode {
 			*decimals
 		} else {
 			unreachable!()
 		})
 	}
-	fn balance_of(&self, owner: address) -> Result<uint256> {
+	fn balance_of(&self, owner: Address) -> Result<U256> {
 		self.consume_store_reads(1)?;
 		let owner = T::CrossAccountId::from_eth(owner);
 		let balance = <Balance<T>>::get((self.id, owner));
 		Ok(balance.into())
 	}
 	#[weight(<SelfWeightOf<T>>::transfer())]
-	fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {
+	fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
 		let amount = amount.try_into().map_err(|_| "amount overflow")?;
@@ -101,10 +101,10 @@
 	#[weight(<SelfWeightOf<T>>::transfer_from())]
 	fn transfer_from(
 		&mut self,
-		caller: caller,
-		from: address,
-		to: address,
-		amount: uint256,
+		caller: Caller,
+		from: Address,
+		to: Address,
+		amount: U256,
 	) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = T::CrossAccountId::from_eth(from);
@@ -119,7 +119,7 @@
 		Ok(true)
 	}
 	#[weight(<SelfWeightOf<T>>::approve())]
-	fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {
+	fn approve(&mut self, caller: Caller, spender: Address, amount: U256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let spender = T::CrossAccountId::from_eth(spender);
 		let amount = amount.try_into().map_err(|_| "amount overflow")?;
@@ -128,7 +128,7 @@
 			.map_err(dispatch_to_evm::<T>)?;
 		Ok(true)
 	}
-	fn allowance(&self, owner: address, spender: address) -> Result<uint256> {
+	fn allowance(&self, owner: Address, spender: Address) -> Result<U256> {
 		self.consume_store_reads(1)?;
 		let owner = T::CrossAccountId::from_eth(owner);
 		let spender = T::CrossAccountId::from_eth(spender);
@@ -137,7 +137,7 @@
 	}
 
 	/// @notice Returns collection helper contract address
-	fn collection_helper_address(&self) -> Result<address> {
+	fn collection_helper_address(&self) -> Result<Address> {
 		Ok(T::ContractAddress::get())
 	}
 }
@@ -148,7 +148,7 @@
 	/// @param to account that will receive minted tokens
 	/// @param amount amount of tokens to mint
 	#[weight(<SelfWeightOf<T>>::create_item())]
-	fn mint(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {
+	fn mint(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
 		let amount = amount.try_into().map_err(|_| "amount overflow")?;
@@ -167,18 +167,18 @@
 	T::AccountId: From<[u8; 32]>,
 {
 	/// @notice A description for the collection.
-	fn description(&self) -> Result<string> {
+	fn description(&self) -> Result<String> {
 		Ok(decode_utf16(self.description.iter().copied())
 			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
-			.collect::<string>())
+			.collect::<String>())
 	}
 
 	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		to: pallet_common::eth::CrossAddress,
-		amount: uint256,
+		amount: U256,
 	) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = to.into_sub_cross_account::<T>()?;
@@ -194,9 +194,9 @@
 	#[weight(<SelfWeightOf<T>>::approve())]
 	fn approve_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		spender: pallet_common::eth::CrossAddress,
-		amount: uint256,
+		amount: U256,
 	) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let spender = spender.into_sub_cross_account::<T>()?;
@@ -214,7 +214,7 @@
 	/// @param amount The amount that will be burnt.
 	#[solidity(hide)]
 	#[weight(<SelfWeightOf<T>>::burn_from())]
-	fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {
+	fn burn_from(&mut self, caller: Caller, from: Address, amount: U256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = T::CrossAccountId::from_eth(from);
 		let amount = amount.try_into().map_err(|_| "amount overflow")?;
@@ -235,9 +235,9 @@
 	#[weight(<SelfWeightOf<T>>::burn_from())]
 	fn burn_from_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		from: pallet_common::eth::CrossAddress,
-		amount: uint256,
+		amount: U256,
 	) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = from.into_sub_cross_account::<T>()?;
@@ -254,7 +254,7 @@
 	/// Mint tokens for multiple accounts.
 	/// @param amounts array of pairs of account address and amount
 	#[weight(<SelfWeightOf<T>>::create_multiple_items_ex(amounts.len() as u32))]
-	fn mint_bulk(&mut self, caller: caller, amounts: Vec<(address, uint256)>) -> Result<bool> {
+	fn mint_bulk(&mut self, caller: Caller, amounts: Vec<(Address, U256)>) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let budget = self
 			.recorder
@@ -277,9 +277,9 @@
 	#[weight(<SelfWeightOf<T>>::transfer())]
 	fn transfer_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		to: pallet_common::eth::CrossAddress,
-		amount: uint256,
+		amount: U256,
 	) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = to.into_sub_cross_account::<T>()?;
@@ -295,10 +295,10 @@
 	#[weight(<SelfWeightOf<T>>::transfer_from())]
 	fn transfer_from_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		from: pallet_common::eth::CrossAddress,
 		to: pallet_common::eth::CrossAddress,
-		amount: uint256,
+		amount: U256,
 	) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = from.into_sub_cross_account::<T>()?;
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
@@ -274,11 +274,9 @@
 
 	/// Set the collection access method.
 	/// @param mode Access mode
-	/// 	0 for Normal
-	/// 	1 for AllowList
 	/// @dev EVM selector for this function is: 0x41835d4c,
 	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(uint8 mode) public {
+	function setCollectionAccess(AccessMode mode) public {
 		require(false, stub_error);
 		mode;
 		dummy = 0;
@@ -443,6 +441,14 @@
 	uint256 sub;
 }
 
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+enum AccessMode {
+	/// Access grant for owner and admins. Used as default.
+	Normal,
+	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+	AllowList
+}
+
 /// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
 struct CollectionNestingPermission {
 	CollectionPermissionField field;
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -43,7 +43,7 @@
 use pallet_evm::{account::CrossAccountId, PrecompileHandle};
 use pallet_evm_coder_substrate::call;
 use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
-use sp_core::Get;
+use sp_core::{U256, Get};
 
 use crate::{
 	AccountBalance, Config, CreateItemData, NonfungibleHandle, Pallet, TokenData, TokensMinted,
@@ -63,8 +63,8 @@
 	#[solidity(hide)]
 	fn set_token_property_permission(
 		&mut self,
-		caller: caller,
-		key: string,
+		caller: Caller,
+		key: String,
 		is_mutable: bool,
 		collection_admin: bool,
 		token_owner: bool,
@@ -93,7 +93,7 @@
 	#[weight(<SelfWeightOf<T>>::set_token_property_permissions(permissions.len() as u32))]
 	fn set_token_property_permissions(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		permissions: Vec<eth::TokenPropertyPermission>,
 	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -121,10 +121,10 @@
 	#[weight(<SelfWeightOf<T>>::set_token_properties(1))]
 	fn set_property(
 		&mut self,
-		caller: caller,
-		token_id: uint256,
-		key: string,
-		value: bytes,
+		caller: Caller,
+		token_id: U256,
+		key: String,
+		value: Bytes,
 	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
@@ -154,8 +154,8 @@
 	#[weight(<SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]
 	fn set_properties(
 		&mut self,
-		caller: caller,
-		token_id: uint256,
+		caller: Caller,
+		token_id: U256,
 		properties: Vec<eth::Property>,
 	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -187,7 +187,7 @@
 	/// @param key Property key.
 	#[solidity(hide)]
 	#[weight(<SelfWeightOf<T>>::delete_token_properties(1))]
-	fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> {
+	fn delete_property(&mut self, token_id: U256, caller: Caller, key: String) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
 		let key = <Vec<u8>>::from(key)
@@ -209,9 +209,9 @@
 	#[weight(<SelfWeightOf<T>>::delete_token_properties(keys.len() as u32))]
 	fn delete_properties(
 		&mut self,
-		token_id: uint256,
-		caller: caller,
-		keys: Vec<string>,
+		token_id: U256,
+		caller: Caller,
+		keys: Vec<String>,
 	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
@@ -239,7 +239,7 @@
 	/// @param tokenId ID of the token.
 	/// @param key Property key.
 	/// @return Property value bytes
-	fn property(&self, token_id: uint256, key: string) -> Result<bytes> {
+	fn property(&self, token_id: U256, key: String) -> Result<Bytes> {
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
 		let key = <Vec<u8>>::from(key)
 			.try_into()
@@ -261,11 +261,11 @@
 	///  any transfer, the approved address for that NFT (if any) is reset to none.
 	Transfer {
 		#[indexed]
-		from: address,
+		from: Address,
 		#[indexed]
-		to: address,
+		to: Address,
 		#[indexed]
-		token_id: uint256,
+		token_id: U256,
 	},
 	/// @dev This emits when the approved address for an NFT is changed or
 	///  reaffirmed. The zero address indicates there is no approved address.
@@ -273,30 +273,24 @@
 	///  address for that NFT (if any) is reset to none.
 	Approval {
 		#[indexed]
-		owner: address,
+		owner: Address,
 		#[indexed]
-		approved: address,
+		approved: Address,
 		#[indexed]
-		token_id: uint256,
+		token_id: U256,
 	},
 	/// @dev This emits when an operator is enabled or disabled for an owner.
 	///  The operator can manage all NFTs of the owner.
 	#[allow(dead_code)]
 	ApprovalForAll {
 		#[indexed]
-		owner: address,
+		owner: Address,
 		#[indexed]
-		operator: address,
+		operator: Address,
 		approved: bool,
 	},
 }
 
-#[derive(ToLog)]
-pub enum ERC721UniqueMintableEvents {
-	#[allow(dead_code)]
-	MintingFinished {},
-}
-
 /// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
 /// @dev See https://eips.ethereum.org/EIPS/eip-721
 #[solidity_interface(name = ERC721Metadata, expect_selector = 0x5b5e139f)]
@@ -307,14 +301,14 @@
 	/// @notice A descriptive name for a collection of NFTs in this contract
 	/// @dev real implementation of this function lies in `ERC721UniqueExtensions`
 	#[solidity(hide, rename_selector = "name")]
-	fn name_proxy(&self) -> Result<string> {
+	fn name_proxy(&self) -> Result<String> {
 		self.name()
 	}
 
 	/// @notice An abbreviated name for NFTs in this contract
 	/// @dev real implementation of this function lies in `ERC721UniqueExtensions`
 	#[solidity(hide, rename_selector = "symbol")]
-	fn symbol_proxy(&self) -> Result<string> {
+	fn symbol_proxy(&self) -> Result<String> {
 		self.symbol()
 	}
 
@@ -328,7 +322,7 @@
 	///
 	/// @return token's const_metadata
 	#[solidity(rename_selector = "tokenURI")]
-	fn token_uri(&self, token_id: uint256) -> Result<string> {
+	fn token_uri(&self, token_id: U256) -> Result<String> {
 		let token_id_u32: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
 
 		match get_token_property(self, token_id_u32, &key::url()).as_deref() {
@@ -341,7 +335,7 @@
 		let base_uri =
 			pallet_common::Pallet::<T>::get_collection_property(self.id, &key::base_uri())
 				.map(BoundedVec::into_inner)
-				.map(string::from_utf8)
+				.map(String::from_utf8)
 				.transpose()
 				.map_err(|e| {
 					Error::Revert(alloc::format!(
@@ -374,12 +368,12 @@
 	/// @param index A counter less than `totalSupply()`
 	/// @return The token identifier for the `index`th NFT,
 	///  (sort order not specified)
-	fn token_by_index(&self, index: uint256) -> Result<uint256> {
+	fn token_by_index(&self, index: U256) -> Result<U256> {
 		Ok(index)
 	}
 
 	/// @dev Not implemented
-	fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {
+	fn token_of_owner_by_index(&self, _owner: Address, _index: U256) -> Result<U256> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
@@ -387,7 +381,7 @@
 	/// @notice Count NFTs tracked by this contract
 	/// @return A count of valid NFTs tracked by this contract, where each one of
 	///  them has an assigned and queryable owner not equal to the zero address
-	fn total_supply(&self) -> Result<uint256> {
+	fn total_supply(&self) -> Result<U256> {
 		self.consume_store_reads(1)?;
 		Ok(<Pallet<T>>::total_supply(self).into())
 	}
@@ -402,7 +396,7 @@
 	///  function throws for queries about the zero address.
 	/// @param owner An address for whom to query the balance
 	/// @return The number of NFTs owned by `owner`, possibly zero
-	fn balance_of(&self, owner: address) -> Result<uint256> {
+	fn balance_of(&self, owner: Address) -> Result<U256> {
 		self.consume_store_reads(1)?;
 		let owner = T::CrossAccountId::from_eth(owner);
 		let balance = <AccountBalance<T>>::get((self.id, owner));
@@ -413,7 +407,7 @@
 	///  about them do throw.
 	/// @param tokenId The identifier for an NFT
 	/// @return The address of the owner of the NFT
-	fn owner_of(&self, token_id: uint256) -> Result<address> {
+	fn owner_of(&self, token_id: U256) -> Result<Address> {
 		self.consume_store_reads(1)?;
 		let token: TokenId = token_id.try_into()?;
 		Ok(*<TokenData<T>>::get((self.id, token))
@@ -425,21 +419,16 @@
 	#[solidity(rename_selector = "safeTransferFrom")]
 	fn safe_transfer_from_with_data(
 		&mut self,
-		_from: address,
-		_to: address,
-		_token_id: uint256,
-		_data: bytes,
-	) -> Result<void> {
+		_from: Address,
+		_to: Address,
+		_token_id: U256,
+		_data: Bytes,
+	) -> Result<()> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
 	/// @dev Not implemented
-	fn safe_transfer_from(
-		&mut self,
-		_from: address,
-		_to: address,
-		_token_id: uint256,
-	) -> Result<void> {
+	fn safe_transfer_from(&mut self, _from: Address, _to: Address, _token_id: U256) -> Result<()> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
@@ -456,11 +445,11 @@
 	#[weight(<SelfWeightOf<T>>::transfer_from())]
 	fn transfer_from(
 		&mut self,
-		caller: caller,
-		from: address,
-		to: address,
-		token_id: uint256,
-	) -> Result<void> {
+		caller: Caller,
+		from: Address,
+		to: Address,
+		token_id: U256,
+	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = T::CrossAccountId::from_eth(from);
 		let to = T::CrossAccountId::from_eth(to);
@@ -481,7 +470,7 @@
 	/// @param approved The new approved NFT controller
 	/// @param tokenId The NFT to approve
 	#[weight(<SelfWeightOf<T>>::approve())]
-	fn approve(&mut self, caller: caller, approved: address, token_id: uint256) -> Result<void> {
+	fn approve(&mut self, caller: Caller, approved: Address, token_id: U256) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let approved = T::CrossAccountId::from_eth(approved);
 		let token = token_id.try_into()?;
@@ -498,10 +487,10 @@
 	#[weight(<SelfWeightOf<T>>::set_allowance_for_all())]
 	fn set_approval_for_all(
 		&mut self,
-		caller: caller,
-		operator: address,
+		caller: Caller,
+		operator: Address,
 		approved: bool,
-	) -> Result<void> {
+	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let operator = T::CrossAccountId::from_eth(operator);
 
@@ -511,14 +500,14 @@
 	}
 
 	/// @dev Not implemented
-	fn get_approved(&self, _token_id: uint256) -> Result<address> {
+	fn get_approved(&self, _token_id: U256) -> Result<Address> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
 
 	/// @notice Tells whether the given `owner` approves the `operator`.
 	#[weight(<SelfWeightOf<T>>::allowance_for_all())]
-	fn is_approved_for_all(&self, owner: address, operator: address) -> Result<bool> {
+	fn is_approved_for_all(&self, owner: Address, operator: Address) -> Result<bool> {
 		let owner = T::CrossAccountId::from_eth(owner);
 		let operator = T::CrossAccountId::from_eth(operator);
 
@@ -534,7 +523,7 @@
 	///  operator of the current owner.
 	/// @param tokenId The NFT to approve
 	#[weight(<SelfWeightOf<T>>::burn_item())]
-	fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {
+	fn burn(&mut self, caller: Caller, token_id: U256) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token = token_id.try_into()?;
 
@@ -544,18 +533,14 @@
 }
 
 /// @title ERC721 minting logic.
-#[solidity_interface(name = ERC721UniqueMintable, events(ERC721UniqueMintableEvents))]
+#[solidity_interface(name = ERC721UniqueMintable)]
 impl<T: Config> NonfungibleHandle<T> {
-	fn minting_finished(&self) -> Result<bool> {
-		Ok(false)
-	}
-
 	/// @notice Function to mint a token.
 	/// @param to The new owner
 	/// @return uint256 The id of the newly minted token
 	#[weight(<SelfWeightOf<T>>::create_item())]
-	fn mint(&mut self, caller: caller, to: address) -> Result<uint256> {
-		let token_id: uint256 = <TokensMinted<T>>::get(self.id)
+	fn mint(&mut self, caller: Caller, to: Address) -> Result<U256> {
+		let token_id: U256 = <TokensMinted<T>>::get(self.id)
 			.checked_add(1)
 			.ok_or("item id overflow")?
 			.into();
@@ -570,7 +555,7 @@
 	/// @param tokenId ID of the minted NFT
 	#[solidity(hide, rename_selector = "mint")]
 	#[weight(<SelfWeightOf<T>>::create_item())]
-	fn mint_check_id(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {
+	fn mint_check_id(&mut self, caller: Caller, to: Address, token_id: U256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
 		let token_id: u32 = token_id.try_into()?;
@@ -608,11 +593,11 @@
 	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint_with_token_uri(
 		&mut self,
-		caller: caller,
-		to: address,
-		token_uri: string,
-	) -> Result<uint256> {
-		let token_id: uint256 = <TokensMinted<T>>::get(self.id)
+		caller: Caller,
+		to: Address,
+		token_uri: String,
+	) -> Result<U256> {
+		let token_id: U256 = <TokensMinted<T>>::get(self.id)
 			.checked_add(1)
 			.ok_or("item id overflow")?
 			.into();
@@ -630,10 +615,10 @@
 	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint_with_token_uri_check_id(
 		&mut self,
-		caller: caller,
-		to: address,
-		token_id: uint256,
-		token_uri: string,
+		caller: Caller,
+		to: Address,
+		token_id: U256,
+		token_uri: String,
 	) -> Result<bool> {
 		let key = key::url();
 		let permission = get_token_permission::<T>(self.id, &key)?;
@@ -678,11 +663,6 @@
 		)
 		.map_err(dispatch_to_evm::<T>)?;
 		Ok(true)
-	}
-
-	/// @dev Not implemented
-	fn finish_minting(&mut self, _caller: caller) -> Result<bool> {
-		Err("not implementable".into())
 	}
 }
 
@@ -690,12 +670,12 @@
 	collection: &CollectionHandle<T>,
 	token_id: u32,
 	key: &up_data_structs::PropertyKey,
-) -> Result<string> {
+) -> Result<String> {
 	collection.consume_store_reads(1)?;
 	let properties = <TokenProperties<T>>::try_get((collection.id, token_id))
 		.map_err(|_| Error::Revert("Token properties not found".into()))?;
 	if let Some(property) = properties.get(key) {
-		return Ok(string::from_utf8_lossy(property).into());
+		return Ok(String::from_utf8_lossy(property).into());
 	}
 
 	Err("Property tokenURI not found".into())
@@ -711,7 +691,7 @@
 		.get(key)
 		.map(Clone::clone)
 		.ok_or_else(|| {
-			let key = string::from_utf8(key.clone().into_inner()).unwrap_or_default();
+			let key = String::from_utf8(key.clone().into_inner()).unwrap_or_default();
 			Error::Revert(alloc::format!("No permission for key {}", key))
 		})?;
 	Ok(a)
@@ -724,28 +704,28 @@
 	T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,
 {
 	/// @notice A descriptive name for a collection of NFTs in this contract
-	fn name(&self) -> Result<string> {
+	fn name(&self) -> Result<String> {
 		Ok(decode_utf16(self.name.iter().copied())
 			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
-			.collect::<string>())
+			.collect::<String>())
 	}
 
 	/// @notice An abbreviated name for NFTs in this contract
-	fn symbol(&self) -> Result<string> {
-		Ok(string::from_utf8_lossy(&self.token_prefix).into())
+	fn symbol(&self) -> Result<String> {
+		Ok(String::from_utf8_lossy(&self.token_prefix).into())
 	}
 
 	/// @notice A description for the collection.
-	fn description(&self) -> Result<string> {
+	fn description(&self) -> Result<String> {
 		Ok(decode_utf16(self.description.iter().copied())
 			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
-			.collect::<string>())
+			.collect::<String>())
 	}
 
 	/// Returns the owner (in cross format) of the token.
 	///
 	/// @param tokenId Id for the token.
-	fn cross_owner_of(&self, token_id: uint256) -> Result<eth::CrossAddress> {
+	fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {
 		Self::token_owner(&self, token_id.try_into()?)
 			.map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))
 			.ok_or(Error::Revert("key too large".into()))
@@ -756,7 +736,7 @@
 	/// @param tokenId Id for the token.
 	/// @param keys Properties keys. Empty keys for all propertyes.
 	/// @return Vector of properties key/value pairs.
-	fn properties(&self, token_id: uint256, keys: Vec<string>) -> Result<Vec<eth::Property>> {
+	fn properties(&self, token_id: U256, keys: Vec<String>) -> Result<Vec<eth::Property>> {
 		let keys = keys
 			.into_iter()
 			.map(|key| {
@@ -785,10 +765,10 @@
 	#[weight(<SelfWeightOf<T>>::approve())]
 	fn approve_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		approved: eth::CrossAddress,
-		token_id: uint256,
-	) -> Result<void> {
+		token_id: U256,
+	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let approved = approved.into_sub_cross_account::<T>()?;
 		let token = token_id.try_into()?;
@@ -804,7 +784,7 @@
 	/// @param to The new owner
 	/// @param tokenId The NFT to transfer
 	#[weight(<SelfWeightOf<T>>::transfer())]
-	fn transfer(&mut self, caller: caller, to: address, token_id: uint256) -> Result<void> {
+	fn transfer(&mut self, caller: Caller, to: Address, token_id: U256) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
 		let token = token_id.try_into()?;
@@ -824,10 +804,10 @@
 	#[weight(<SelfWeightOf<T>>::transfer())]
 	fn transfer_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		to: eth::CrossAddress,
-		token_id: uint256,
-	) -> Result<void> {
+		token_id: U256,
+	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = to.into_sub_cross_account::<T>()?;
 		let token = token_id.try_into()?;
@@ -848,11 +828,11 @@
 	#[weight(<SelfWeightOf<T>>::transfer())]
 	fn transfer_from_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		from: eth::CrossAddress,
 		to: eth::CrossAddress,
-		token_id: uint256,
-	) -> Result<void> {
+		token_id: U256,
+	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = from.into_sub_cross_account::<T>()?;
 		let to = to.into_sub_cross_account::<T>()?;
@@ -873,7 +853,7 @@
 	/// @param tokenId The NFT to transfer
 	#[solidity(hide)]
 	#[weight(<SelfWeightOf<T>>::burn_from())]
-	fn burn_from(&mut self, caller: caller, from: address, token_id: uint256) -> Result<void> {
+	fn burn_from(&mut self, caller: Caller, from: Address, token_id: U256) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = T::CrossAccountId::from_eth(from);
 		let token = token_id.try_into()?;
@@ -895,10 +875,10 @@
 	#[weight(<SelfWeightOf<T>>::burn_from())]
 	fn burn_from_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		from: eth::CrossAddress,
-		token_id: uint256,
-	) -> Result<void> {
+		token_id: U256,
+	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = from.into_sub_cross_account::<T>()?;
 		let token = token_id.try_into()?;
@@ -912,7 +892,7 @@
 	}
 
 	/// @notice Returns next free NFT ID.
-	fn next_token_id(&self) -> Result<uint256> {
+	fn next_token_id(&self) -> Result<U256> {
 		self.consume_store_reads(1)?;
 		Ok(<TokensMinted<T>>::get(self.id)
 			.checked_add(1)
@@ -927,7 +907,7 @@
 	/// @param tokenIds IDs of the minted NFTs
 	#[solidity(hide)]
 	#[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]
-	fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {
+	fn mint_bulk(&mut self, caller: Caller, to: Address, token_ids: Vec<U256>) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
 		let mut expected_index = <TokensMinted<T>>::get(self.id)
@@ -966,9 +946,9 @@
 	#[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]
 	fn mint_bulk_with_token_uri(
 		&mut self,
-		caller: caller,
-		to: address,
-		tokens: Vec<(uint256, string)>,
+		caller: Caller,
+		to: Address,
+		tokens: Vec<(U256, String)>,
 	) -> Result<bool> {
 		let key = key::url();
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -1017,10 +997,10 @@
 	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		to: eth::CrossAddress,
 		properties: Vec<eth::Property>,
-	) -> Result<uint256> {
+	) -> Result<U256> {
 		let token_id = <TokensMinted<T>>::get(self.id)
 			.checked_add(1)
 			.ok_or("item id overflow")?;
@@ -1055,7 +1035,7 @@
 	}
 
 	/// @notice Returns collection helper contract address
-	fn collection_helper_address(&self) -> Result<address> {
+	fn collection_helper_address(&self) -> Result<Address> {
 		Ok(T::ContractAddress::get())
 	}
 }
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
@@ -416,11 +416,9 @@
 
 	/// Set the collection access method.
 	/// @param mode Access mode
-	/// 	0 for Normal
-	/// 	1 for AllowList
 	/// @dev EVM selector for this function is: 0x41835d4c,
 	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(uint8 mode) public {
+	function setCollectionAccess(AccessMode mode) public {
 		require(false, stub_error);
 		mode;
 		dummy = 0;
@@ -585,6 +583,14 @@
 	uint256 sub;
 }
 
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+enum AccessMode {
+	/// Access grant for owner and admins. Used as default.
+	Normal,
+	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+	AllowList
+}
+
 /// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
 struct CollectionNestingPermission {
 	CollectionPermissionField field;
@@ -700,22 +706,9 @@
 	}
 }
 
-/// @dev inlined interface
-contract ERC721UniqueMintableEvents {
-	event MintingFinished();
-}
-
 /// @title ERC721 minting logic.
-/// @dev the ERC-165 identifier for this interface is 0x476ff149
-contract ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents {
-	/// @dev EVM selector for this function is: 0x05d2035b,
-	///  or in textual repr: mintingFinished()
-	function mintingFinished() public view returns (bool) {
-		require(false, stub_error);
-		dummy;
-		return false;
-	}
-
+/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6
+contract ERC721UniqueMintable is Dummy, ERC165 {
 	/// @notice Function to mint a token.
 	/// @param to The new owner
 	/// @return uint256 The id of the newly minted token
@@ -756,7 +749,6 @@
 		dummy = 0;
 		return 0;
 	}
-
 	// /// @notice Function to mint token with the given tokenUri.
 	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
 	// ///  unlike standard, you can't specify it manually
@@ -774,14 +766,6 @@
 	// 	return false;
 	// }
 
-	/// @dev Not implemented
-	/// @dev EVM selector for this function is: 0x7d64bcb4,
-	///  or in textual repr: finishMinting()
-	function finishMinting() public returns (bool) {
-		require(false, stub_error);
-		dummy = 0;
-		return false;
-	}
 }
 
 /// @title Unique extensions for ERC721.
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc.rs
+++ b/pallets/refungible/src/erc.rs
@@ -39,7 +39,7 @@
 use pallet_evm::{account::CrossAccountId, PrecompileHandle};
 use pallet_evm_coder_substrate::{call, dispatch_to_evm};
 use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
-use sp_core::{H160, Get};
+use sp_core::{H160, U256, Get};
 use sp_std::{collections::btree_map::BTreeMap, vec::Vec, vec};
 use up_data_structs::{
 	CollectionId, CollectionPropertiesVec, mapping::TokenAddressMapping, Property, PropertyKey,
@@ -66,8 +66,8 @@
 	#[solidity(hide)]
 	fn set_token_property_permission(
 		&mut self,
-		caller: caller,
-		key: string,
+		caller: Caller,
+		key: String,
 		is_mutable: bool,
 		collection_admin: bool,
 		token_owner: bool,
@@ -96,7 +96,7 @@
 	#[weight(<SelfWeightOf<T>>::set_token_property_permissions(permissions.len() as u32))]
 	fn set_token_property_permissions(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		permissions: Vec<eth::TokenPropertyPermission>,
 	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -124,10 +124,10 @@
 	#[weight(<SelfWeightOf<T>>::set_token_properties(1))]
 	fn set_property(
 		&mut self,
-		caller: caller,
-		token_id: uint256,
-		key: string,
-		value: bytes,
+		caller: Caller,
+		token_id: U256,
+		key: String,
+		value: Bytes,
 	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
@@ -157,8 +157,8 @@
 	#[weight(<SelfWeightOf<T>>::set_token_properties(properties.len() as u32))]
 	fn set_properties(
 		&mut self,
-		caller: caller,
-		token_id: uint256,
+		caller: Caller,
+		token_id: U256,
 		properties: Vec<eth::Property>,
 	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -190,7 +190,7 @@
 	/// @param key Property key.
 	#[solidity(hide)]
 	#[weight(<SelfWeightOf<T>>::delete_token_properties(1))]
-	fn delete_property(&mut self, token_id: uint256, caller: caller, key: string) -> Result<()> {
+	fn delete_property(&mut self, token_id: U256, caller: Caller, key: String) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
 		let key = <Vec<u8>>::from(key)
@@ -212,9 +212,9 @@
 	#[weight(<SelfWeightOf<T>>::delete_token_properties(keys.len() as u32))]
 	fn delete_properties(
 		&mut self,
-		token_id: uint256,
-		caller: caller,
-		keys: Vec<string>,
+		token_id: U256,
+		caller: Caller,
+		keys: Vec<String>,
 	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
@@ -242,7 +242,7 @@
 	/// @param tokenId ID of the token.
 	/// @param key Property key.
 	/// @return Property value bytes
-	fn property(&self, token_id: uint256, key: string) -> Result<bytes> {
+	fn property(&self, token_id: U256, key: String) -> Result<Bytes> {
 		let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
 		let key = <Vec<u8>>::from(key)
 			.try_into()
@@ -262,37 +262,30 @@
 	///  may be created and assigned without emitting Transfer.
 	Transfer {
 		#[indexed]
-		from: address,
+		from: Address,
 		#[indexed]
-		to: address,
+		to: Address,
 		#[indexed]
-		token_id: uint256,
+		token_id: U256,
 	},
 	/// @dev Not supported
 	Approval {
 		#[indexed]
-		owner: address,
+		owner: Address,
 		#[indexed]
-		approved: address,
+		approved: Address,
 		#[indexed]
-		token_id: uint256,
+		token_id: U256,
 	},
 	/// @dev Not supported
 	#[allow(dead_code)]
 	ApprovalForAll {
 		#[indexed]
-		owner: address,
+		owner: Address,
 		#[indexed]
-		operator: address,
+		operator: Address,
 		approved: bool,
 	},
-}
-
-#[derive(ToLog)]
-pub enum ERC721UniqueMintableEvents {
-	/// @dev Not supported
-	#[allow(dead_code)]
-	MintingFinished {},
 }
 
 /// @title ERC-721 Non-Fungible Token Standard, optional metadata extension
@@ -305,14 +298,14 @@
 	/// @notice A descriptive name for a collection of NFTs in this contract
 	/// @dev real implementation of this function lies in `ERC721UniqueExtensions`
 	#[solidity(hide, rename_selector = "name")]
-	fn name_proxy(&self) -> Result<string> {
+	fn name_proxy(&self) -> Result<String> {
 		self.name()
 	}
 
 	/// @notice An abbreviated name for NFTs in this contract
 	/// @dev real implementation of this function lies in `ERC721UniqueExtensions`
 	#[solidity(hide, rename_selector = "symbol")]
-	fn symbol_proxy(&self) -> Result<string> {
+	fn symbol_proxy(&self) -> Result<String> {
 		self.symbol()
 	}
 
@@ -326,7 +319,7 @@
 	///
 	/// @return token's const_metadata
 	#[solidity(rename_selector = "tokenURI")]
-	fn token_uri(&self, token_id: uint256) -> Result<string> {
+	fn token_uri(&self, token_id: U256) -> Result<String> {
 		let token_id_u32: u32 = token_id.try_into().map_err(|_| "token id overflow")?;
 
 		match get_token_property(self, token_id_u32, &key::url()).as_deref() {
@@ -339,7 +332,7 @@
 		let base_uri =
 			pallet_common::Pallet::<T>::get_collection_property(self.id, &key::base_uri())
 				.map(BoundedVec::into_inner)
-				.map(string::from_utf8)
+				.map(String::from_utf8)
 				.transpose()
 				.map_err(|e| {
 					Error::Revert(alloc::format!(
@@ -372,12 +365,12 @@
 	/// @param index A counter less than `totalSupply()`
 	/// @return The token identifier for the `index`th NFT,
 	///  (sort order not specified)
-	fn token_by_index(&self, index: uint256) -> Result<uint256> {
+	fn token_by_index(&self, index: U256) -> Result<U256> {
 		Ok(index)
 	}
 
 	/// Not implemented
-	fn token_of_owner_by_index(&self, _owner: address, _index: uint256) -> Result<uint256> {
+	fn token_of_owner_by_index(&self, _owner: Address, _index: U256) -> Result<U256> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
@@ -385,7 +378,7 @@
 	/// @notice Count RFTs tracked by this contract
 	/// @return A count of valid RFTs tracked by this contract, where each one of
 	///  them has an assigned and queryable owner not equal to the zero address
-	fn total_supply(&self) -> Result<uint256> {
+	fn total_supply(&self) -> Result<U256> {
 		self.consume_store_reads(1)?;
 		Ok(<Pallet<T>>::total_supply(self).into())
 	}
@@ -400,7 +393,7 @@
 	///  function throws for queries about the zero address.
 	/// @param owner An address for whom to query the balance
 	/// @return The number of RFTs owned by `owner`, possibly zero
-	fn balance_of(&self, owner: address) -> Result<uint256> {
+	fn balance_of(&self, owner: Address) -> Result<U256> {
 		self.consume_store_reads(1)?;
 		let owner = T::CrossAccountId::from_eth(owner);
 		let balance = <AccountBalance<T>>::get((self.id, owner));
@@ -414,7 +407,7 @@
 	///  the tokens that are partially owned.
 	/// @param tokenId The identifier for an RFT
 	/// @return The address of the owner of the RFT
-	fn owner_of(&self, token_id: uint256) -> Result<address> {
+	fn owner_of(&self, token_id: U256) -> Result<Address> {
 		self.consume_store_reads(2)?;
 		let token = token_id.try_into()?;
 		let owner = <Pallet<T>>::token_owner(self.id, token);
@@ -427,23 +420,18 @@
 	#[solidity(rename_selector = "safeTransferFrom")]
 	fn safe_transfer_from_with_data(
 		&mut self,
-		_from: address,
-		_to: address,
-		_token_id: uint256,
-		_data: bytes,
-	) -> Result<void> {
+		_from: Address,
+		_to: Address,
+		_token_id: U256,
+		_data: Bytes,
+	) -> Result<()> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
 
 	/// @dev Not implemented
 	#[solidity(rename_selector = "safeTransferFrom")]
-	fn safe_transfer_from(
-		&mut self,
-		_from: address,
-		_to: address,
-		_token_id: uint256,
-	) -> Result<void> {
+	fn safe_transfer_from(&mut self, _from: Address, _to: Address, _token_id: U256) -> Result<()> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
@@ -461,11 +449,11 @@
 	#[weight(<SelfWeightOf<T>>::transfer_from_creating_removing())]
 	fn transfer_from(
 		&mut self,
-		caller: caller,
-		from: address,
-		to: address,
-		token_id: uint256,
-	) -> Result<void> {
+		caller: Caller,
+		from: Address,
+		to: Address,
+		token_id: U256,
+	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = T::CrossAccountId::from_eth(from);
 		let to = T::CrossAccountId::from_eth(to);
@@ -484,7 +472,7 @@
 	}
 
 	/// @dev Not implemented
-	fn approve(&mut self, _caller: caller, _approved: address, _token_id: uint256) -> Result<void> {
+	fn approve(&mut self, _caller: Caller, _approved: Address, _token_id: U256) -> Result<()> {
 		Err("not implemented".into())
 	}
 
@@ -495,10 +483,10 @@
 	#[weight(<SelfWeightOf<T>>::set_allowance_for_all())]
 	fn set_approval_for_all(
 		&mut self,
-		caller: caller,
-		operator: address,
+		caller: Caller,
+		operator: Address,
 		approved: bool,
-	) -> Result<void> {
+	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let operator = T::CrossAccountId::from_eth(operator);
 
@@ -508,14 +496,14 @@
 	}
 
 	/// @dev Not implemented
-	fn get_approved(&self, _token_id: uint256) -> Result<address> {
+	fn get_approved(&self, _token_id: U256) -> Result<Address> {
 		// TODO: Not implemetable
 		Err("not implemented".into())
 	}
 
 	/// @notice Tells whether the given `owner` approves the `operator`.
 	#[weight(<SelfWeightOf<T>>::allowance_for_all())]
-	fn is_approved_for_all(&self, owner: address, operator: address) -> Result<bool> {
+	fn is_approved_for_all(&self, owner: Address, operator: Address) -> Result<bool> {
 		let owner = T::CrossAccountId::from_eth(owner);
 		let operator = T::CrossAccountId::from_eth(operator);
 
@@ -563,7 +551,7 @@
 	///  operator of the current owner.
 	/// @param tokenId The RFT to approve
 	#[weight(<SelfWeightOf<T>>::burn_item_fully())]
-	fn burn(&mut self, caller: caller, token_id: uint256) -> Result<void> {
+	fn burn(&mut self, caller: Caller, token_id: U256) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let token = token_id.try_into()?;
 
@@ -576,18 +564,14 @@
 }
 
 /// @title ERC721 minting logic.
-#[solidity_interface(name = ERC721UniqueMintable, events(ERC721UniqueMintableEvents))]
+#[solidity_interface(name = ERC721UniqueMintable)]
 impl<T: Config> RefungibleHandle<T> {
-	fn minting_finished(&self) -> Result<bool> {
-		Ok(false)
-	}
-
 	/// @notice Function to mint a token.
 	/// @param to The new owner
 	/// @return uint256 The id of the newly minted token
 	#[weight(<SelfWeightOf<T>>::create_item())]
-	fn mint(&mut self, caller: caller, to: address) -> Result<uint256> {
-		let token_id: uint256 = <TokensMinted<T>>::get(self.id)
+	fn mint(&mut self, caller: Caller, to: Address) -> Result<U256> {
+		let token_id: U256 = <TokensMinted<T>>::get(self.id)
 			.checked_add(1)
 			.ok_or("item id overflow")?
 			.into();
@@ -602,7 +586,7 @@
 	/// @param tokenId ID of the minted RFT
 	#[solidity(hide, rename_selector = "mint")]
 	#[weight(<SelfWeightOf<T>>::create_item())]
-	fn mint_check_id(&mut self, caller: caller, to: address, token_id: uint256) -> Result<bool> {
+	fn mint_check_id(&mut self, caller: Caller, to: Address, token_id: U256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
 		let token_id: u32 = token_id.try_into()?;
@@ -645,11 +629,11 @@
 	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint_with_token_uri(
 		&mut self,
-		caller: caller,
-		to: address,
-		token_uri: string,
-	) -> Result<uint256> {
-		let token_id: uint256 = <TokensMinted<T>>::get(self.id)
+		caller: Caller,
+		to: Address,
+		token_uri: String,
+	) -> Result<U256> {
+		let token_id: U256 = <TokensMinted<T>>::get(self.id)
 			.checked_add(1)
 			.ok_or("item id overflow")?
 			.into();
@@ -667,10 +651,10 @@
 	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint_with_token_uri_check_id(
 		&mut self,
-		caller: caller,
-		to: address,
-		token_id: uint256,
-		token_uri: string,
+		caller: Caller,
+		to: Address,
+		token_id: U256,
+		token_uri: String,
 	) -> Result<bool> {
 		let key = key::url();
 		let permission = get_token_permission::<T>(self.id, &key)?;
@@ -717,11 +701,6 @@
 		)
 		.map_err(dispatch_to_evm::<T>)?;
 		Ok(true)
-	}
-
-	/// @dev Not implemented
-	fn finish_minting(&mut self, _caller: caller) -> Result<bool> {
-		Err("not implementable".into())
 	}
 }
 
@@ -729,12 +708,12 @@
 	collection: &CollectionHandle<T>,
 	token_id: u32,
 	key: &up_data_structs::PropertyKey,
-) -> Result<string> {
+) -> Result<String> {
 	collection.consume_store_reads(1)?;
 	let properties = <TokenProperties<T>>::try_get((collection.id, token_id))
 		.map_err(|_| Error::Revert("Token properties not found".into()))?;
 	if let Some(property) = properties.get(key) {
-		return Ok(string::from_utf8_lossy(property).into());
+		return Ok(String::from_utf8_lossy(property).into());
 	}
 
 	Err("Property tokenURI not found".into())
@@ -750,7 +729,7 @@
 		.get(key)
 		.map(Clone::clone)
 		.ok_or_else(|| {
-			let key = string::from_utf8(key.clone().into_inner()).unwrap_or_default();
+			let key = String::from_utf8(key.clone().into_inner()).unwrap_or_default();
 			Error::Revert(alloc::format!("No permission for key {}", key))
 		})?;
 	Ok(a)
@@ -763,28 +742,28 @@
 	T::AccountId: From<[u8; 32]> + AsRef<[u8; 32]>,
 {
 	/// @notice A descriptive name for a collection of NFTs in this contract
-	fn name(&self) -> Result<string> {
+	fn name(&self) -> Result<String> {
 		Ok(decode_utf16(self.name.iter().copied())
 			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
-			.collect::<string>())
+			.collect::<String>())
 	}
 
 	/// @notice An abbreviated name for NFTs in this contract
-	fn symbol(&self) -> Result<string> {
-		Ok(string::from_utf8_lossy(&self.token_prefix).into())
+	fn symbol(&self) -> Result<String> {
+		Ok(String::from_utf8_lossy(&self.token_prefix).into())
 	}
 
 	/// @notice A description for the collection.
-	fn description(&self) -> Result<string> {
+	fn description(&self) -> Result<String> {
 		Ok(decode_utf16(self.description.iter().copied())
 			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
-			.collect::<string>())
+			.collect::<String>())
 	}
 
 	/// Returns the owner (in cross format) of the token.
 	///
 	/// @param tokenId Id for the token.
-	fn cross_owner_of(&self, token_id: uint256) -> Result<eth::CrossAddress> {
+	fn cross_owner_of(&self, token_id: U256) -> Result<eth::CrossAddress> {
 		Self::token_owner(&self, token_id.try_into()?)
 			.map(|o| eth::CrossAddress::from_sub_cross_account::<T>(&o))
 			.ok_or(Error::Revert("key too large".into()))
@@ -795,7 +774,7 @@
 	/// @param tokenId Id for the token.
 	/// @param keys Properties keys. Empty keys for all propertyes.
 	/// @return Vector of properties key/value pairs.
-	fn properties(&self, token_id: uint256, keys: Vec<string>) -> Result<Vec<eth::Property>> {
+	fn properties(&self, token_id: U256, keys: Vec<String>) -> Result<Vec<eth::Property>> {
 		let keys = keys
 			.into_iter()
 			.map(|key| {
@@ -821,7 +800,7 @@
 	/// @param to The new owner
 	/// @param tokenId The RFT to transfer
 	#[weight(<SelfWeightOf<T>>::transfer_creating_removing())]
-	fn transfer(&mut self, caller: caller, to: address, token_id: uint256) -> Result<void> {
+	fn transfer(&mut self, caller: Caller, to: Address, token_id: U256) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
 		let token = token_id.try_into()?;
@@ -846,10 +825,10 @@
 	#[weight(<SelfWeightOf<T>>::transfer_creating_removing())]
 	fn transfer_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		to: eth::CrossAddress,
-		token_id: uint256,
-	) -> Result<void> {
+		token_id: U256,
+	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = to.into_sub_cross_account::<T>()?;
 		let token = token_id.try_into()?;
@@ -874,11 +853,11 @@
 	#[weight(<SelfWeightOf<T>>::transfer_creating_removing())]
 	fn transfer_from_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		from: eth::CrossAddress,
 		to: eth::CrossAddress,
-		token_id: uint256,
-	) -> Result<void> {
+		token_id: U256,
+	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = from.into_sub_cross_account::<T>()?;
 		let to = to.into_sub_cross_account::<T>()?;
@@ -904,7 +883,7 @@
 	/// @param tokenId The RFT to transfer
 	#[solidity(hide)]
 	#[weight(<SelfWeightOf<T>>::burn_from())]
-	fn burn_from(&mut self, caller: caller, from: address, token_id: uint256) -> Result<void> {
+	fn burn_from(&mut self, caller: Caller, from: Address, token_id: U256) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = T::CrossAccountId::from_eth(from);
 		let token = token_id.try_into()?;
@@ -930,10 +909,10 @@
 	#[weight(<SelfWeightOf<T>>::burn_from())]
 	fn burn_from_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		from: eth::CrossAddress,
-		token_id: uint256,
-	) -> Result<void> {
+		token_id: U256,
+	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = from.into_sub_cross_account::<T>()?;
 		let token = token_id.try_into()?;
@@ -950,7 +929,7 @@
 	}
 
 	/// @notice Returns next free RFT ID.
-	fn next_token_id(&self) -> Result<uint256> {
+	fn next_token_id(&self) -> Result<U256> {
 		self.consume_store_reads(1)?;
 		Ok(<TokensMinted<T>>::get(self.id)
 			.checked_add(1)
@@ -965,7 +944,7 @@
 	/// @param tokenIds IDs of the minted RFTs
 	#[solidity(hide)]
 	#[weight(<SelfWeightOf<T>>::create_multiple_items(token_ids.len() as u32))]
-	fn mint_bulk(&mut self, caller: caller, to: address, token_ids: Vec<uint256>) -> Result<bool> {
+	fn mint_bulk(&mut self, caller: Caller, to: Address, token_ids: Vec<U256>) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
 		let mut expected_index = <TokensMinted<T>>::get(self.id)
@@ -1010,9 +989,9 @@
 	#[weight(<SelfWeightOf<T>>::create_multiple_items(tokens.len() as u32))]
 	fn mint_bulk_with_token_uri(
 		&mut self,
-		caller: caller,
-		to: address,
-		tokens: Vec<(uint256, string)>,
+		caller: Caller,
+		to: Address,
+		tokens: Vec<(U256, String)>,
 	) -> Result<bool> {
 		let key = key::url();
 		let caller = T::CrossAccountId::from_eth(caller);
@@ -1067,10 +1046,10 @@
 	#[weight(<SelfWeightOf<T>>::create_item())]
 	fn mint_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		to: eth::CrossAddress,
 		properties: Vec<eth::Property>,
-	) -> Result<uint256> {
+	) -> Result<U256> {
 		let token_id = <TokensMinted<T>>::get(self.id)
 			.checked_add(1)
 			.ok_or("item id overflow")?;
@@ -1109,7 +1088,7 @@
 	/// Returns EVM address for refungible token
 	///
 	/// @param token ID of the token
-	fn token_contract_address(&self, token: uint256) -> Result<address> {
+	fn token_contract_address(&self, token: U256) -> Result<Address> {
 		Ok(T::EvmTokenAddressMapping::token_to_address(
 			self.id,
 			token.try_into().map_err(|_| "token id overflow")?,
@@ -1117,7 +1096,7 @@
 	}
 
 	/// @notice Returns collection helper contract address
-	fn collection_helper_address(&self) -> Result<address> {
+	fn collection_helper_address(&self) -> Result<Address> {
 		Ok(T::ContractAddress::get())
 	}
 }
modifiedpallets/refungible/src/erc_token.rsdiffbeforeafterboth
--- a/pallets/refungible/src/erc_token.rs
+++ b/pallets/refungible/src/erc_token.rs
@@ -25,7 +25,8 @@
 	ops::Deref,
 };
 use evm_coder::{
-	abi::AbiType, ToLog, execution::*, generate_stubgen, solidity_interface, types::*, weight,
+	abi::AbiType, ToLog, execution::*, generate_stubgen, solidity_interface, solidity, types::*,
+	weight,
 };
 use pallet_common::{
 	CommonWeightInfo,
@@ -36,6 +37,7 @@
 use pallet_evm_coder_substrate::{call, dispatch_to_evm, WithRecorder};
 use pallet_structure::{SelfWeightOf as StructureWeight, weights::WeightInfo as _};
 use sp_std::vec::Vec;
+use sp_core::U256;
 use up_data_structs::TokenId;
 
 use crate::{
@@ -50,11 +52,11 @@
 
 #[solidity_interface(name = ERC1633)]
 impl<T: Config> RefungibleTokenHandle<T> {
-	fn parent_token(&self) -> Result<address> {
+	fn parent_token(&self) -> Result<Address> {
 		Ok(collection_id_to_address(self.id))
 	}
 
-	fn parent_token_id(&self) -> Result<uint256> {
+	fn parent_token_id(&self) -> Result<U256> {
 		Ok(self.1.into())
 	}
 }
@@ -67,19 +69,19 @@
 	/// of burning tokens the transfer is to 0.
 	Transfer {
 		#[indexed]
-		from: address,
+		from: Address,
 		#[indexed]
-		to: address,
-		value: uint256,
+		to: Address,
+		value: U256,
 	},
 	/// @dev This event is emitted when the amount of tokens (value) is approved
 	/// by the owner to be used by the spender.
 	Approval {
 		#[indexed]
-		owner: address,
+		owner: Address,
 		#[indexed]
-		spender: address,
-		value: uint256,
+		spender: Address,
+		value: U256,
 	},
 }
 
@@ -90,25 +92,25 @@
 #[solidity_interface(name = ERC20, events(ERC20Events))]
 impl<T: Config> RefungibleTokenHandle<T> {
 	/// @return the name of the token.
-	fn name(&self) -> Result<string> {
+	fn name(&self) -> Result<String> {
 		Ok(decode_utf16(self.name.iter().copied())
 			.map(|r| r.unwrap_or(REPLACEMENT_CHARACTER))
-			.collect::<string>())
+			.collect::<String>())
 	}
 
 	/// @return the symbol of the token.
-	fn symbol(&self) -> Result<string> {
-		Ok(string::from_utf8_lossy(&self.token_prefix).into())
+	fn symbol(&self) -> Result<String> {
+		Ok(String::from_utf8_lossy(&self.token_prefix).into())
 	}
 
 	/// @dev Total number of tokens in existence
-	fn total_supply(&self) -> Result<uint256> {
+	fn total_supply(&self) -> Result<U256> {
 		self.consume_store_reads(1)?;
 		Ok(<TotalSupply<T>>::get((self.id, self.1)).into())
 	}
 
 	/// @dev Not supported
-	fn decimals(&self) -> Result<uint8> {
+	fn decimals(&self) -> Result<u8> {
 		// Decimals aren't supported for refungible tokens
 		Ok(0)
 	}
@@ -116,7 +118,7 @@
 	/// @dev Gets the balance of the specified address.
 	/// @param owner The address to query the balance of.
 	/// @return An uint256 representing the amount owned by the passed address.
-	fn balance_of(&self, owner: address) -> Result<uint256> {
+	fn balance_of(&self, owner: Address) -> Result<U256> {
 		self.consume_store_reads(1)?;
 		let owner = T::CrossAccountId::from_eth(owner);
 		let balance = <Balance<T>>::get((self.id, self.1, owner));
@@ -127,7 +129,7 @@
 	/// @param to The address to transfer to.
 	/// @param amount The amount to be transferred.
 	#[weight(<CommonWeights<T>>::transfer())]
-	fn transfer(&mut self, caller: caller, to: address, amount: uint256) -> Result<bool> {
+	fn transfer(&mut self, caller: Caller, to: Address, amount: U256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = T::CrossAccountId::from_eth(to);
 		let amount = amount.try_into().map_err(|_| "amount overflow")?;
@@ -147,10 +149,10 @@
 	#[weight(<CommonWeights<T>>::transfer_from())]
 	fn transfer_from(
 		&mut self,
-		caller: caller,
-		from: address,
-		to: address,
-		amount: uint256,
+		caller: Caller,
+		from: Address,
+		to: Address,
+		amount: U256,
 	) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = T::CrossAccountId::from_eth(from);
@@ -173,7 +175,7 @@
 	/// @param spender The address which will spend the funds.
 	/// @param amount The amount of tokens to be spent.
 	#[weight(<SelfWeightOf<T>>::approve())]
-	fn approve(&mut self, caller: caller, spender: address, amount: uint256) -> Result<bool> {
+	fn approve(&mut self, caller: Caller, spender: Address, amount: U256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let spender = T::CrossAccountId::from_eth(spender);
 		let amount = amount.try_into().map_err(|_| "amount overflow")?;
@@ -187,7 +189,7 @@
 	/// @param owner address The address which owns the funds.
 	/// @param spender address The address which will spend the funds.
 	/// @return A uint256 specifying the amount of tokens still available for the spender.
-	fn allowance(&self, owner: address, spender: address) -> Result<uint256> {
+	fn allowance(&self, owner: Address, spender: Address) -> Result<U256> {
 		self.consume_store_reads(1)?;
 		let owner = T::CrossAccountId::from_eth(owner);
 		let spender = T::CrossAccountId::from_eth(spender);
@@ -206,7 +208,8 @@
 	/// @param from The account whose tokens will be burnt.
 	/// @param amount The amount that will be burnt.
 	#[weight(<SelfWeightOf<T>>::burn_from())]
-	fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {
+	#[solidity(hide)]
+	fn burn_from(&mut self, caller: Caller, from: Address, amount: U256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = T::CrossAccountId::from_eth(from);
 		let amount = amount.try_into().map_err(|_| "amount overflow")?;
@@ -226,9 +229,9 @@
 	#[weight(<SelfWeightOf<T>>::burn_from())]
 	fn burn_from_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		from: pallet_common::eth::CrossAddress,
-		amount: uint256,
+		amount: U256,
 	) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = from.into_sub_cross_account::<T>()?;
@@ -252,9 +255,9 @@
 	#[weight(<SelfWeightOf<T>>::approve())]
 	fn approve_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		spender: pallet_common::eth::CrossAddress,
-		amount: uint256,
+		amount: U256,
 	) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let spender = spender.into_sub_cross_account::<T>()?;
@@ -268,7 +271,7 @@
 	///  Throws if `msg.sender` doesn't owns all of the tokens.
 	/// @param amount New total amount of the tokens.
 	#[weight(<SelfWeightOf<T>>::repartition_item())]
-	fn repartition(&mut self, caller: caller, amount: uint256) -> Result<bool> {
+	fn repartition(&mut self, caller: Caller, amount: U256) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let amount = amount.try_into().map_err(|_| "amount overflow")?;
 
@@ -282,9 +285,9 @@
 	#[weight(<CommonWeights<T>>::transfer())]
 	fn transfer_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		to: pallet_common::eth::CrossAddress,
-		amount: uint256,
+		amount: U256,
 	) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let to = to.into_sub_cross_account::<T>()?;
@@ -305,10 +308,10 @@
 	#[weight(<CommonWeights<T>>::transfer_from())]
 	fn transfer_from_cross(
 		&mut self,
-		caller: caller,
+		caller: Caller,
 		from: pallet_common::eth::CrossAddress,
 		to: pallet_common::eth::CrossAddress,
-		amount: uint256,
+		amount: U256,
 	) -> Result<bool> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let from = from.into_sub_cross_account::<T>()?;
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
@@ -416,11 +416,9 @@
 
 	/// Set the collection access method.
 	/// @param mode Access mode
-	/// 	0 for Normal
-	/// 	1 for AllowList
 	/// @dev EVM selector for this function is: 0x41835d4c,
 	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(uint8 mode) public {
+	function setCollectionAccess(AccessMode mode) public {
 		require(false, stub_error);
 		mode;
 		dummy = 0;
@@ -585,6 +583,14 @@
 	uint256 sub;
 }
 
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+enum AccessMode {
+	/// Access grant for owner and admins. Used as default.
+	Normal,
+	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+	AllowList
+}
+
 /// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
 struct CollectionNestingPermission {
 	CollectionPermissionField field;
@@ -700,22 +706,9 @@
 	}
 }
 
-/// @dev inlined interface
-contract ERC721UniqueMintableEvents {
-	event MintingFinished();
-}
-
 /// @title ERC721 minting logic.
-/// @dev the ERC-165 identifier for this interface is 0x476ff149
-contract ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents {
-	/// @dev EVM selector for this function is: 0x05d2035b,
-	///  or in textual repr: mintingFinished()
-	function mintingFinished() public view returns (bool) {
-		require(false, stub_error);
-		dummy;
-		return false;
-	}
-
+/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6
+contract ERC721UniqueMintable is Dummy, ERC165 {
 	/// @notice Function to mint a token.
 	/// @param to The new owner
 	/// @return uint256 The id of the newly minted token
@@ -756,7 +749,6 @@
 		dummy = 0;
 		return 0;
 	}
-
 	// /// @notice Function to mint token with the given tokenUri.
 	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
 	// ///  unlike standard, you can't specify it manually
@@ -774,14 +766,6 @@
 	// 	return false;
 	// }
 
-	/// @dev Not implemented
-	/// @dev EVM selector for this function is: 0x7d64bcb4,
-	///  or in textual repr: finishMinting()
-	function finishMinting() public returns (bool) {
-		require(false, stub_error);
-		dummy = 0;
-		return false;
-	}
 }
 
 /// @title Unique extensions for ERC721.
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
@@ -38,19 +38,19 @@
 
 /// @dev the ERC-165 identifier for this interface is 0xe17a7d2b
 contract ERC20UniqueExtensions is Dummy, ERC165 {
-	/// @dev Function that burns an amount of the token of a given account,
-	/// deducting from the sender's allowance for said account.
-	/// @param from The account whose tokens will be burnt.
-	/// @param amount The amount that will be burnt.
-	/// @dev EVM selector for this function is: 0x79cc6790,
-	///  or in textual repr: burnFrom(address,uint256)
-	function burnFrom(address from, uint256 amount) public returns (bool) {
-		require(false, stub_error);
-		from;
-		amount;
-		dummy = 0;
-		return false;
-	}
+	// /// @dev Function that burns an amount of the token of a given account,
+	// /// deducting from the sender's allowance for said account.
+	// /// @param from The account whose tokens will be burnt.
+	// /// @param amount The amount that will be burnt.
+	// /// @dev EVM selector for this function is: 0x79cc6790,
+	// ///  or in textual repr: burnFrom(address,uint256)
+	// function burnFrom(address from, uint256 amount) public returns (bool) {
+	// 	require(false, stub_error);
+	// 	from;
+	// 	amount;
+	// 	dummy = 0;
+	// 	return false;
+	// }
 
 	/// @dev Function that burns an amount of the token of a given account,
 	/// deducting from the sender's allowance for said account.
modifiedpallets/unique/src/eth/mod.rsdiffbeforeafterboth
--- a/pallets/unique/src/eth/mod.rs
+++ b/pallets/unique/src/eth/mod.rs
@@ -56,10 +56,10 @@
 }
 
 fn convert_data<T: Config>(
-	caller: caller,
-	name: string,
-	description: string,
-	token_prefix: string,
+	caller: Caller,
+	name: String,
+	description: String,
+	token_prefix: String,
 ) -> Result<(
 	T::CrossAccountId,
 	CollectionName,
@@ -87,13 +87,13 @@
 
 #[inline(always)]
 fn create_collection_internal<T: Config>(
-	caller: caller,
-	value: value,
-	name: string,
+	caller: Caller,
+	value: Value,
+	name: String,
 	collection_mode: CollectionMode,
-	description: string,
-	token_prefix: string,
-) -> Result<address> {
+	description: String,
+	token_prefix: String,
+) -> Result<Address> {
 	let (caller, name, description, token_prefix) =
 		convert_data::<T>(caller, name, description, token_prefix)?;
 	let data = CreateCollectionData {
@@ -118,7 +118,7 @@
 	Ok(address)
 }
 
-fn check_sent_amount_equals_collection_creation_price<T: Config>(value: value) -> Result<()> {
+fn check_sent_amount_equals_collection_creation_price<T: Config>(value: Value) -> Result<()> {
 	let value = value.as_u128();
 	let creation_price: u128 = T::CollectionCreationPrice::get()
 		.try_into()
@@ -149,12 +149,12 @@
 	#[solidity(rename_selector = "createNFTCollection")]
 	fn create_nft_collection(
 		&mut self,
-		caller: caller,
-		value: value,
-		name: string,
-		description: string,
-		token_prefix: string,
-	) -> Result<address> {
+		caller: Caller,
+		value: Value,
+		name: String,
+		description: String,
+		token_prefix: String,
+	) -> Result<Address> {
 		let (caller, name, description, token_prefix) =
 			convert_data::<T>(caller, name, description, token_prefix)?;
 		let data = CreateCollectionData {
@@ -188,12 +188,12 @@
 	#[solidity(hide)]
 	fn create_nonfungible_collection(
 		&mut self,
-		caller: caller,
-		value: value,
-		name: string,
-		description: string,
-		token_prefix: string,
-	) -> Result<address> {
+		caller: Caller,
+		value: Value,
+		name: String,
+		description: String,
+		token_prefix: String,
+	) -> Result<Address> {
 		create_collection_internal::<T>(
 			caller,
 			value,
@@ -208,12 +208,12 @@
 	#[solidity(rename_selector = "createRFTCollection")]
 	fn create_rft_collection(
 		&mut self,
-		caller: caller,
-		value: value,
-		name: string,
-		description: string,
-		token_prefix: string,
-	) -> Result<address> {
+		caller: Caller,
+		value: Value,
+		name: String,
+		description: String,
+		token_prefix: String,
+	) -> Result<Address> {
 		create_collection_internal::<T>(
 			caller,
 			value,
@@ -228,13 +228,13 @@
 	#[solidity(rename_selector = "createFTCollection")]
 	fn create_fungible_collection(
 		&mut self,
-		caller: caller,
-		value: value,
-		name: string,
-		decimals: uint8,
-		description: string,
-		token_prefix: string,
-	) -> Result<address> {
+		caller: Caller,
+		value: Value,
+		name: String,
+		decimals: u8,
+		description: String,
+		token_prefix: String,
+	) -> Result<Address> {
 		create_collection_internal::<T>(
 			caller,
 			value,
@@ -248,9 +248,9 @@
 	#[solidity(rename_selector = "makeCollectionERC721MetadataCompatible")]
 	fn make_collection_metadata_compatible(
 		&mut self,
-		caller: caller,
-		collection: address,
-		base_uri: string,
+		caller: Caller,
+		collection: Address,
+		base_uri: String,
 	) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 		let collection =
@@ -334,7 +334,7 @@
 	}
 
 	#[weight(<SelfWeightOf<T>>::destroy_collection())]
-	fn destroy_collection(&mut self, caller: caller, collection_address: address) -> Result<void> {
+	fn destroy_collection(&mut self, caller: Caller, collection_address: Address) -> Result<()> {
 		let caller = T::CrossAccountId::from_eth(caller);
 
 		let collection_id = pallet_common::eth::map_eth_to_id(&collection_address)
@@ -346,7 +346,7 @@
 	/// Check if a collection exists
 	/// @param collectionAddress Address of the collection in question
 	/// @return bool Does the collection exist?
-	fn is_collection_exist(&self, _caller: caller, collection_address: address) -> Result<bool> {
+	fn is_collection_exist(&self, _caller: Caller, collection_address: Address) -> Result<bool> {
 		if let Some(id) = pallet_common::eth::map_eth_to_id(&collection_address) {
 			let collection_id = id;
 			return Ok(<CollectionById<T>>::contains_key(collection_id));
@@ -355,7 +355,7 @@
 		Ok(false)
 	}
 
-	fn collection_creation_fee(&self) -> Result<value> {
+	fn collection_creation_fee(&self) -> Result<Value> {
 		let price: u128 = T::CollectionCreationPrice::get()
 			.try_into()
 			.map_err(|_| ()) // workaround for `expect` requiring `Debug` trait
@@ -366,14 +366,14 @@
 	/// Returns address of a collection.
 	/// @param collectionId  - CollectionId  of the collection
 	/// @return eth mirror address of the collection
-	fn collection_address(&self, collection_id: uint32) -> Result<address> {
+	fn collection_address(&self, collection_id: u32) -> Result<Address> {
 		Ok(collection_id_to_address(collection_id.into()))
 	}
 
 	/// Returns collectionId of a collection.
 	/// @param collectionAddress  - Eth address of the collection
 	/// @return collectionId of the collection
-	fn collection_id(&self, collection_address: address) -> Result<uint32> {
+	fn collection_id(&self, collection_address: Address) -> Result<u32> {
 		map_eth_to_id(&collection_address)
 			.map(|id| id.0)
 			.ok_or(Error::Revert(format!(
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -266,10 +266,12 @@
 		/// * `token_prefix`: Byte string containing the token prefix to mark a collection
 		/// to which a token belongs (limit [`MAX_TOKEN_PREFIX_LENGTH`]).
 		/// * `mode`: Type of items stored in the collection and type dependent data.
-		// returns collection ID
+		///
+		/// returns collection ID
+		///
+		/// Deprecated: `create_collection_ex` is more up-to-date and advanced, prefer it instead.
 		#[weight = <SelfWeightOf<T>>::create_collection()]
-		#[deprecated(note = "`create_collection_ex` is more up-to-date and advanced, prefer it instead")]
-		pub fn create_collection(
+		fn create_collection(
 			origin,
 			collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,
 			collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,
modifiedruntime/common/ethereum/sponsoring/refungible.rsdiffbeforeafterboth
--- a/runtime/common/ethereum/sponsoring/refungible.rs
+++ b/runtime/common/ethereum/sponsoring/refungible.rs
@@ -265,11 +265,9 @@
 
 		match call {
 			// Readonly
-			ERC165Call(_, _) | MintingFinished => None,
+			ERC165Call(_, _) => None,
 
-			// Not sponsored
-			FinishMinting => None,
-
+			// Sponsored
 			Mint { .. }
 			| MintCheckId { .. }
 			| MintWithTokenUri { .. }
modifiedruntime/tests/src/tests.rsdiffbeforeafterboth
--- a/runtime/tests/src/tests.rs
+++ b/runtime/tests/src/tests.rs
@@ -323,7 +323,7 @@
 				.map(|d| { d.into() })
 				.collect()
 		));
-		for (index, data) in items_data.into_iter().enumerate() {
+		for (index, _data) in items_data.into_iter().enumerate() {
 			let balance = <pallet_refungible::Balance<Test>>::get((
 				CollectionId(1),
 				TokenId((index + 1) as u32),
modifiedtests/src/benchmarks/mintFee/benchmark.tsdiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/benchmark.ts
+++ b/tests/src/benchmarks/mintFee/benchmark.ts
@@ -293,6 +293,8 @@
       const evmContract = await helper.ethNativeContract.collection(
         helper.ethAddress.fromCollectionId(collection.collectionId),
         'nft',
+        undefined,
+        true,
       );
 
       const subTokenId = await evmContract.methods.nextTokenId().call();
@@ -351,9 +353,7 @@
       encodedCall = await evmContract.methods
         .setProperties(
           subTokenId,
-          PROPERTIES.slice(0, setup.propertiesNumber).map((p) => {
-            return {field_0: p.key, field_1: p.value};
-          }),
+          PROPERTIES.slice(0, setup.propertiesNumber),
         )
         .encodeABI();
 
@@ -394,9 +394,7 @@
         .mintToSubstrateBulkProperty(
           helper.ethAddress.fromCollectionId(collection.collectionId),
           susbstrateReceiver.addressRaw,
-          PROPERTIES.slice(0, setup.propertiesNumber).map((p) => {
-            return {field_0: p.key, field_1: p.value};
-          }),
+          PROPERTIES.slice(0, setup.propertiesNumber),
         )
         .send({from: ethSigner, gas: 25_000_000});
     },
modifiedtests/src/benchmarks/mintFee/proxyContract.soldiffbeforeafterboth
--- a/tests/src/benchmarks/mintFee/proxyContract.sol
+++ b/tests/src/benchmarks/mintFee/proxyContract.sol
@@ -3,21 +3,44 @@
 import {CollectionHelpers} from "../../eth/api/CollectionHelpers.sol";
 import {ContractHelpers} from "../../eth/api/ContractHelpers.sol";
 import {UniqueRefungibleToken} from "../../eth/api/UniqueRefungibleToken.sol";
-import {UniqueRefungible, Collection, EthCrossAccount as RftCrossAccountId, Tuple20 as RftProperties} from "../../eth/api/UniqueRefungible.sol";
-import {UniqueNFT, EthCrossAccount as NftCrossAccountId, Tuple21 as NftProperty, TokenProperties} from "../../eth/api/UniqueNFT.sol";
+import {UniqueRefungible, Collection, CrossAddress as RftCrossAccountId, Property as RftProperty} from "../../eth/api/UniqueRefungible.sol";
+import {UniqueNFT, CrossAddress as NftCrossAccountId, Property as NftProperty} from "../../eth/api/UniqueNFT.sol";
 
 struct Property {
 	string key;
 	bytes value;
 }
 
+interface SoftDeprecatedMethods {
+	/// @notice Set token property value.
+	/// @dev Throws error if `msg.sender` has no permission to edit the property.
+	/// @param tokenId ID of the token.
+	/// @param key Property key.
+	/// @param value Property value.
+	/// @dev EVM selector for this function is: 0x1752d67b,
+	///  or in textual repr: setProperty(uint256,string,bytes)
+	function setProperty(
+		uint256 tokenId,
+		string memory key,
+		bytes memory value
+	) external;
+}
+
+interface BenchUniqueRefungible is UniqueRefungible, SoftDeprecatedMethods {}
+interface BenchUniqueNFT is UniqueNFT, SoftDeprecatedMethods {}
+
+
+
 contract ProxyMint {
 	bytes32 constant REFUNGIBLE_COLLECTION_TYPE = keccak256(bytes("ReFungible"));
 	bytes32 constant NONFUNGIBLE_COLLECTION_TYPE = keccak256(bytes("NFT"));
 
 	modifier checkRestrictions(address _collection) {
 		Collection commonContract = Collection(_collection);
-		require(commonContract.isOwnerOrAdmin(msg.sender), "Only collection admin/owner can call this method");
+		require(
+			commonContract.isOwnerOrAdminCross(RftCrossAccountId(msg.sender, 0)),
+			"Only collection admin/owner can call this method"
+		);
 		_;
 	}
 
@@ -58,9 +81,9 @@
 	function mintToSubstrateWithProperty(
 		address _collection,
 		uint256 _substrateReceiver,
-		Property[] calldata properties
+		Property[] calldata _properties
 	) external checkRestrictions(_collection) {
-		uint256 propertiesLength = properties.length;
+		uint256 propertiesLength = _properties.length;
 		require(propertiesLength > 0, "Properies is empty");
 
 		Collection commonContract = Collection(_collection);
@@ -68,11 +91,12 @@
 		uint256 tokenId;
 
 		if (collectionType == REFUNGIBLE_COLLECTION_TYPE) {
-			UniqueRefungible rftCollection = UniqueRefungible(_collection);
+			BenchUniqueRefungible rftCollection = BenchUniqueRefungible(_collection);
 			tokenId = rftCollection.nextTokenId();
 			rftCollection.mint(address(this));
+
 			for (uint256 i = 0; i < propertiesLength; ++i) {
-				rftCollection.setProperty(tokenId, properties[i].key, properties[i].value);
+				rftCollection.setProperty(tokenId, _properties[i].key, _properties[i].value);
 			}
 			rftCollection.transferFromCross(
 				RftCrossAccountId(address(this), 0),
@@ -80,10 +104,10 @@
 				tokenId
 			);
 		} else if (collectionType == NONFUNGIBLE_COLLECTION_TYPE) {
-			UniqueNFT nftCollection = UniqueNFT(_collection);
+			BenchUniqueNFT nftCollection = BenchUniqueNFT(_collection);
 			tokenId = nftCollection.mint(address(this));
 			for (uint256 i = 0; i < propertiesLength; ++i) {
-				nftCollection.setProperty(tokenId, properties[i].key, properties[i].value);
+				nftCollection.setProperty(tokenId, _properties[i].key, _properties[i].value);
 			}
 			nftCollection.transferFromCross(
 				NftCrossAccountId(address(this), 0),
modifiedtests/src/check-event/burnItemEvent.test.tsdiffbeforeafterboth
--- a/tests/src/check-event/burnItemEvent.test.ts
+++ b/tests/src/check-event/burnItemEvent.test.ts
@@ -32,6 +32,7 @@
     const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
     const token = await collection.mintToken(alice, {Substrate: alice.address});
     await token.burn(alice);
+    await helper.wait.newBlocks(1);
 
     const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
     const eventStrings = event.map(e => `${e.section}.${e.method}`);
modifiedtests/src/check-event/createCollectionEvent.test.tsdiffbeforeafterboth
--- a/tests/src/check-event/createCollectionEvent.test.ts
+++ b/tests/src/check-event/createCollectionEvent.test.ts
@@ -29,6 +29,7 @@
   });
   itSub('Check event from createCollection(): ', async ({helper}) => {
     await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
+    await helper.wait.newBlocks(1);
     const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
     const eventStrings = event.map(e => `${e.section}.${e.method}`);
 
modifiedtests/src/check-event/createItemEvent.test.tsdiffbeforeafterboth
--- a/tests/src/check-event/createItemEvent.test.ts
+++ b/tests/src/check-event/createItemEvent.test.ts
@@ -30,6 +30,7 @@
   itSub('Check event from createItem(): ', async ({helper}) => {
     const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
     await collection.mintToken(alice, {Substrate: alice.address});
+    await helper.wait.newBlocks(1);
     const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
     const eventStrings = event.map(e => `${e.section}.${e.method}`);
 
modifiedtests/src/check-event/createMultipleItemsEvent.test.tsdiffbeforeafterboth
--- a/tests/src/check-event/createMultipleItemsEvent.test.ts
+++ b/tests/src/check-event/createMultipleItemsEvent.test.ts
@@ -35,6 +35,7 @@
       {owner: {Substrate: alice.address}},
     ]);
 
+    await helper.wait.newBlocks(1);
     const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
     const eventStrings = event.map(e => `${e.section}.${e.method}`);
 
modifiedtests/src/check-event/destroyCollectionEvent.test.tsdiffbeforeafterboth
--- a/tests/src/check-event/destroyCollectionEvent.test.ts
+++ b/tests/src/check-event/destroyCollectionEvent.test.ts
@@ -31,6 +31,7 @@
   itSub('Check event from destroyCollection(): ', async ({helper}) => {
     const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
     await collection.burn(alice);
+    await helper.wait.newBlocks(1);
     const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
     const eventStrings = event.map(e => `${e.section}.${e.method}`);
 
modifiedtests/src/check-event/transferEvent.test.tsdiffbeforeafterboth
--- a/tests/src/check-event/transferEvent.test.ts
+++ b/tests/src/check-event/transferEvent.test.ts
@@ -34,6 +34,7 @@
     const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
     const token = await collection.mintToken(alice, {Substrate: alice.address});
     await token.transfer(alice, {Substrate: bob.address});
+    await helper.wait.newBlocks(1);
     const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
     const eventStrings = event.map(e => `${e.section}.${e.method}`);
 
modifiedtests/src/check-event/transferFromEvent.test.tsdiffbeforeafterboth
--- a/tests/src/check-event/transferFromEvent.test.ts
+++ b/tests/src/check-event/transferFromEvent.test.ts
@@ -33,6 +33,7 @@
     const collection = await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'});
     const token = await collection.mintToken(alice, {Substrate: alice.address});
     await token.transferFrom(alice, {Substrate: alice.address}, {Substrate: bob.address});
+    await helper.wait.newBlocks(1);
     const event = helper.chainLog[helper.chainLog.length - 1].events as IEvent[];
     const eventStrings = event.map(e => `${e.section}.${e.method}`);
 
modifiedtests/src/eth/abi/fungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/fungible.json
+++ b/tests/src/eth/abi/fungible.json
@@ -488,7 +488,9 @@
     "type": "function"
   },
   {
-    "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],
+    "inputs": [
+      { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
+    ],
     "name": "setCollectionAccess",
     "outputs": [],
     "stateMutability": "nonpayable",
modifiedtests/src/eth/abi/nonFungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/nonFungible.json
+++ b/tests/src/eth/abi/nonFungible.json
@@ -51,12 +51,6 @@
   },
   {
     "anonymous": false,
-    "inputs": [],
-    "name": "MintingFinished",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
     "inputs": [
       {
         "indexed": true,
@@ -420,13 +414,6 @@
     "name": "description",
     "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
     "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "finishMinting",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
     "type": "function"
   },
   {
@@ -513,13 +500,6 @@
     "name": "mintWithTokenURI",
     "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
     "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "mintingFinished",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
     "type": "function"
   },
   {
@@ -650,7 +630,9 @@
     "type": "function"
   },
   {
-    "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],
+    "inputs": [
+      { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
+    ],
     "name": "setCollectionAccess",
     "outputs": [],
     "stateMutability": "nonpayable",
modifiedtests/src/eth/abi/reFungible.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/reFungible.json
+++ b/tests/src/eth/abi/reFungible.json
@@ -51,12 +51,6 @@
   },
   {
     "anonymous": false,
-    "inputs": [],
-    "name": "MintingFinished",
-    "type": "event"
-  },
-  {
-    "anonymous": false,
     "inputs": [
       {
         "indexed": true,
@@ -402,13 +396,6 @@
     "name": "description",
     "outputs": [{ "internalType": "string", "name": "", "type": "string" }],
     "stateMutability": "view",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "finishMinting",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
     "type": "function"
   },
   {
@@ -495,13 +482,6 @@
     "name": "mintWithTokenURI",
     "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }],
     "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [],
-    "name": "mintingFinished",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "view",
     "type": "function"
   },
   {
@@ -632,7 +612,9 @@
     "type": "function"
   },
   {
-    "inputs": [{ "internalType": "uint8", "name": "mode", "type": "uint8" }],
+    "inputs": [
+      { "internalType": "enum AccessMode", "name": "mode", "type": "uint8" }
+    ],
     "name": "setCollectionAccess",
     "outputs": [],
     "stateMutability": "nonpayable",
modifiedtests/src/eth/abi/reFungibleToken.jsondiffbeforeafterboth
--- a/tests/src/eth/abi/reFungibleToken.json
+++ b/tests/src/eth/abi/reFungibleToken.json
@@ -98,16 +98,6 @@
   },
   {
     "inputs": [
-      { "internalType": "address", "name": "from", "type": "address" },
-      { "internalType": "uint256", "name": "amount", "type": "uint256" }
-    ],
-    "name": "burnFrom",
-    "outputs": [{ "internalType": "bool", "name": "", "type": "bool" }],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
       {
         "components": [
           { "internalType": "address", "name": "eth", "type": "address" },
modifiedtests/src/eth/api/UniqueFungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueFungible.sol
+++ b/tests/src/eth/api/UniqueFungible.sol
@@ -175,11 +175,9 @@
 
 	/// Set the collection access method.
 	/// @param mode Access mode
-	/// 	0 for Normal
-	/// 	1 for AllowList
 	/// @dev EVM selector for this function is: 0x41835d4c,
 	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(uint8 mode) external;
+	function setCollectionAccess(AccessMode mode) external;
 
 	/// Checks that user allowed to operate with collection.
 	///
@@ -285,6 +283,14 @@
 	uint256 sub;
 }
 
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+enum AccessMode {
+	/// Access grant for owner and admins. Used as default.
+	Normal,
+	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+	AllowList
+}
+
 /// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
 struct CollectionNestingPermission {
 	CollectionPermissionField field;
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -275,11 +275,9 @@
 
 	/// Set the collection access method.
 	/// @param mode Access mode
-	/// 	0 for Normal
-	/// 	1 for AllowList
 	/// @dev EVM selector for this function is: 0x41835d4c,
 	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(uint8 mode) external;
+	function setCollectionAccess(AccessMode mode) external;
 
 	/// Checks that user allowed to operate with collection.
 	///
@@ -385,6 +383,14 @@
 	uint256 sub;
 }
 
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+enum AccessMode {
+	/// Access grant for owner and admins. Used as default.
+	Normal,
+	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+	AllowList
+}
+
 /// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
 struct CollectionNestingPermission {
 	CollectionPermissionField field;
@@ -481,20 +487,11 @@
 	/// @dev EVM selector for this function is: 0x42966c68,
 	///  or in textual repr: burn(uint256)
 	function burn(uint256 tokenId) external;
-}
-
-/// @dev inlined interface
-interface ERC721UniqueMintableEvents {
-	event MintingFinished();
 }
 
 /// @title ERC721 minting logic.
-/// @dev the ERC-165 identifier for this interface is 0x476ff149
-interface ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents {
-	/// @dev EVM selector for this function is: 0x05d2035b,
-	///  or in textual repr: mintingFinished()
-	function mintingFinished() external view returns (bool);
-
+/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6
+interface ERC721UniqueMintable is Dummy, ERC165 {
 	/// @notice Function to mint a token.
 	/// @param to The new owner
 	/// @return uint256 The id of the newly minted token
@@ -518,7 +515,6 @@
 	/// @dev EVM selector for this function is: 0x45c17782,
 	///  or in textual repr: mintWithTokenURI(address,string)
 	function mintWithTokenURI(address to, string memory tokenUri) external returns (uint256);
-
 	// /// @notice Function to mint token with the given tokenUri.
 	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
 	// ///  unlike standard, you can't specify it manually
@@ -529,10 +525,6 @@
 	// ///  or in textual repr: mintWithTokenURI(address,uint256,string)
 	// function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);
 
-	/// @dev Not implemented
-	/// @dev EVM selector for this function is: 0x7d64bcb4,
-	///  or in textual repr: finishMinting()
-	function finishMinting() external returns (bool);
 }
 
 /// @title Unique extensions for ERC721.
modifiedtests/src/eth/api/UniqueRefungible.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungible.sol
+++ b/tests/src/eth/api/UniqueRefungible.sol
@@ -275,11 +275,9 @@
 
 	/// Set the collection access method.
 	/// @param mode Access mode
-	/// 	0 for Normal
-	/// 	1 for AllowList
 	/// @dev EVM selector for this function is: 0x41835d4c,
 	///  or in textual repr: setCollectionAccess(uint8)
-	function setCollectionAccess(uint8 mode) external;
+	function setCollectionAccess(AccessMode mode) external;
 
 	/// Checks that user allowed to operate with collection.
 	///
@@ -385,6 +383,14 @@
 	uint256 sub;
 }
 
+/// Ethereum representation of `AccessMode` (see [`up_data_structs::AccessMode`]).
+enum AccessMode {
+	/// Access grant for owner and admins. Used as default.
+	Normal,
+	/// Like a [`Normal`](AccessMode::Normal) but also users in allow list.
+	AllowList
+}
+
 /// Ethereum representation of `NestingPermissions` (see [`up_data_structs::NestingPermissions`]) field.
 struct CollectionNestingPermission {
 	CollectionPermissionField field;
@@ -481,20 +487,11 @@
 	/// @dev EVM selector for this function is: 0x42966c68,
 	///  or in textual repr: burn(uint256)
 	function burn(uint256 tokenId) external;
-}
-
-/// @dev inlined interface
-interface ERC721UniqueMintableEvents {
-	event MintingFinished();
 }
 
 /// @title ERC721 minting logic.
-/// @dev the ERC-165 identifier for this interface is 0x476ff149
-interface ERC721UniqueMintable is Dummy, ERC165, ERC721UniqueMintableEvents {
-	/// @dev EVM selector for this function is: 0x05d2035b,
-	///  or in textual repr: mintingFinished()
-	function mintingFinished() external view returns (bool);
-
+/// @dev the ERC-165 identifier for this interface is 0x3fd94ea6
+interface ERC721UniqueMintable is Dummy, ERC165 {
 	/// @notice Function to mint a token.
 	/// @param to The new owner
 	/// @return uint256 The id of the newly minted token
@@ -518,7 +515,6 @@
 	/// @dev EVM selector for this function is: 0x45c17782,
 	///  or in textual repr: mintWithTokenURI(address,string)
 	function mintWithTokenURI(address to, string memory tokenUri) external returns (uint256);
-
 	// /// @notice Function to mint token with the given tokenUri.
 	// /// @dev `tokenId` should be obtained with `nextTokenId` method,
 	// ///  unlike standard, you can't specify it manually
@@ -529,10 +525,6 @@
 	// ///  or in textual repr: mintWithTokenURI(address,uint256,string)
 	// function mintWithTokenURI(address to, uint256 tokenId, string memory tokenUri) external returns (bool);
 
-	/// @dev Not implemented
-	/// @dev EVM selector for this function is: 0x7d64bcb4,
-	///  or in textual repr: finishMinting()
-	function finishMinting() external returns (bool);
 }
 
 /// @title Unique extensions for ERC721.
modifiedtests/src/eth/api/UniqueRefungibleToken.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueRefungibleToken.sol
+++ b/tests/src/eth/api/UniqueRefungibleToken.sol
@@ -25,13 +25,13 @@
 
 /// @dev the ERC-165 identifier for this interface is 0xe17a7d2b
 interface ERC20UniqueExtensions is Dummy, ERC165 {
-	/// @dev Function that burns an amount of the token of a given account,
-	/// deducting from the sender's allowance for said account.
-	/// @param from The account whose tokens will be burnt.
-	/// @param amount The amount that will be burnt.
-	/// @dev EVM selector for this function is: 0x79cc6790,
-	///  or in textual repr: burnFrom(address,uint256)
-	function burnFrom(address from, uint256 amount) external returns (bool);
+	// /// @dev Function that burns an amount of the token of a given account,
+	// /// deducting from the sender's allowance for said account.
+	// /// @param from The account whose tokens will be burnt.
+	// /// @param amount The amount that will be burnt.
+	// /// @dev EVM selector for this function is: 0x79cc6790,
+	// ///  or in textual repr: burnFrom(address,uint256)
+	// function burnFrom(address from, uint256 amount) external returns (bool);
 
 	/// @dev Function that burns an amount of the token of a given account,
 	/// deducting from the sender's allowance for said account.
modifiedtests/src/eth/base.test.tsdiffbeforeafterboth
--- a/tests/src/eth/base.test.ts
+++ b/tests/src/eth/base.test.ts
@@ -108,10 +108,6 @@
     await checkInterface(helper, '0x5b5e139f', false, true);
   });
 
-  itEth('ERC721UniqueMintable - 0x476ff149 - support', async ({helper}) => {
-    await checkInterface(helper, '0x476ff149', true, true);
-  });
-
   itEth('ERC721Enumerable - 0x780e9d63 - support', async ({helper}) => {
     await checkInterface(helper, '0x780e9d63', true, true);
   });