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

difftreelog

CORE-386 Fix names and tests

Trubnikov Sergey2022-06-10parent: #84e2b3d.patch.diff
in: master

8 files changed

modifiedpallets/common/src/erc.rsdiffbeforeafterboth
before · pallets/common/src/erc.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/>.1617use evm_coder::{18	solidity_interface, solidity, ToLog,19	types::*,20	execution::{Result, Error},21};22pub use pallet_evm::{PrecompileOutput, PrecompileResult, PrecompileHandle, account::CrossAccountId};23use pallet_evm_coder_substrate::dispatch_to_evm;24use sp_std::vec::Vec;25use up_data_structs::{26	Property, SponsoringRateLimit, NestingRule, OwnerRestrictedSet, AccessMode,27	CollectionPermissions,28};29use alloc::format;3031use crate::{Pallet, CollectionHandle, Config, CollectionProperties};3233#[derive(ToLog)]34pub enum CollectionHelpersEvents {35	CollectionCreated {36		#[indexed]37		owner: address,38		#[indexed]39		collection_id: address,40	},41}4243/// Does not always represent a full collection, for RFT it is either44/// collection (Implementing ERC721), or specific collection token (Implementing ERC20)45pub trait CommonEvmHandler {46	const CODE: &'static [u8];4748	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;49}5051#[solidity_interface(name = "Collection")]52impl<T: Config> CollectionHandle<T>53where54	T::AccountId: From<[u8; 32]>,55{56	fn set_collection_property(&mut self, caller: caller, key: string, value: bytes) -> Result<void> {57		let caller = T::CrossAccountId::from_eth(caller);58		let key = <Vec<u8>>::from(key)59			.try_into()60			.map_err(|_| "key too large")?;61		let value = value.try_into().map_err(|_| "value too large")?;6263		<Pallet<T>>::set_collection_property(self, &caller, Property { key, value })64			.map_err(dispatch_to_evm::<T>)65	}6667	fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {68		let caller = T::CrossAccountId::from_eth(caller);69		let key = <Vec<u8>>::from(key)70			.try_into()71			.map_err(|_| "key too large")?;7273		<Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)74	}7576	/// Throws error if key not found77	fn collection_property(&self, key: string) -> Result<bytes> {78		let key = <Vec<u8>>::from(key)79			.try_into()80			.map_err(|_| "key too large")?;8182		let props = <CollectionProperties<T>>::get(self.id);83		let prop = props.get(&key).ok_or("key not found")?;8485		Ok(prop.to_vec())86	}8788	fn set_collection_sponsor(&mut self, caller: caller, sponsor: address) -> Result<void> {89		check_is_owner_or_admin(caller, self)?;9091		let sponsor = T::CrossAccountId::from_eth(sponsor);92		self.set_sponsor(sponsor.as_sub().clone())93			.map_err(dispatch_to_evm::<T>)?;94		save(self)95	}9697	fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {98		let caller = T::CrossAccountId::from_eth(caller);99		if !self100			.confirm_sponsorship(caller.as_sub())101			.map_err(dispatch_to_evm::<T>)?102		{103			return Err("Caller is not set as sponsor".into());104		}105		save(self)106	}107108	#[solidity(rename_selector = "setCollectionLimit")]109	fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result<void> {110		check_is_owner_or_admin(caller, self)?;111		let mut limits = self.limits.clone();112113		match limit.as_str() {114			"accountTokenOwnershipLimit" => {115				limits.account_token_ownership_limit = Some(value);116			}117			"sponsoredDataSize" => {118				limits.sponsored_data_size = Some(value);119			}120			"sponsoredDataRateLimit" => {121				limits.sponsored_data_rate_limit = Some(SponsoringRateLimit::Blocks(value));122			}123			"tokenLimit" => {124				limits.token_limit = Some(value);125			}126			"sponsorTransferTimeout" => {127				limits.sponsor_transfer_timeout = Some(value);128			}129			"sponsorApproveTimeout" => {130				limits.sponsor_approve_timeout = Some(value);131			}132			_ => {133				return Err(Error::Revert(format!(134					"Unknown integer limit \"{}\"",135					limit136				)))137			}138		}139		self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)140			.map_err(dispatch_to_evm::<T>)?;141		save(self)142	}143144	#[solidity(rename_selector = "setCollectionLimit")]145	fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result<void> {146		check_is_owner_or_admin(caller, self)?;147		let mut limits = self.limits.clone();148149		match limit.as_str() {150			"ownerCanTransfer" => {151				limits.owner_can_transfer = Some(value);152			}153			"ownerCanDestroy" => {154				limits.owner_can_destroy = Some(value);155			}156			"transfersEnabled" => {157				limits.transfers_enabled = Some(value);158			}159			_ => {160				return Err(Error::Revert(format!(161					"Unknown boolean limit \"{}\"",162					limit163				)))164			}165		}166		self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)167			.map_err(dispatch_to_evm::<T>)?;168		save(self)169	}170171	fn contract_address(&self, _caller: caller) -> Result<address> {172		Ok(crate::eth::collection_id_to_address(self.id))173	}174175	fn add_collection_admin_substrate(&self, caller: caller, new_admin: uint256) -> Result<void> {176		let caller = T::CrossAccountId::from_eth(caller);177		let mut new_admin_arr: [u8; 32] = Default::default();178		new_admin.to_big_endian(&mut new_admin_arr);179		let account_id = T::AccountId::from(new_admin_arr);180		let new_admin = T::CrossAccountId::from_sub(account_id);181		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;182		Ok(())183	}184185	fn remove_collection_admin_substrate(186		&self,187		caller: caller,188		new_admin: uint256,189	) -> Result<void> {190		let caller = T::CrossAccountId::from_eth(caller);191		let mut new_admin_arr: [u8; 32] = Default::default();192		new_admin.to_big_endian(&mut new_admin_arr);193		let account_id = T::AccountId::from(new_admin_arr);194		let new_admin = T::CrossAccountId::from_sub(account_id);195		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, false)196			.map_err(dispatch_to_evm::<T>)?;197		Ok(())198	}199200	fn add_collection_admin(&self, caller: caller, new_admin: address) -> Result<void> {201		let caller = T::CrossAccountId::from_eth(caller);202		let new_admin = T::CrossAccountId::from_eth(new_admin);203		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;204		Ok(())205	}206207	fn remove_collection_admin(&self, caller: caller, admin: address) -> Result<void> {208		let caller = T::CrossAccountId::from_eth(caller);209		let admin = T::CrossAccountId::from_eth(admin);210		<Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;211		Ok(())212	}213214	#[solidity(rename_selector = "setNesting")]215	fn set_nesting_bool(&mut self, caller: caller, enable: bool) -> Result<void> {216		check_is_owner_or_admin(caller, self)?;217		let permissions = CollectionPermissions {218			nesting: Some(match enable {219				false => NestingRule::Disabled,220				true => NestingRule::Owner,221			}),222			..Default::default()223		};224		self.collection.permissions = <Pallet<T>>::clamp_permissions(225			self.collection.mode.clone(),226			&self.collection.permissions,227			permissions,228		)229		.map_err(dispatch_to_evm::<T>)?;230231		save(self)232	}233234	#[solidity(rename_selector = "setNesting")]235	fn set_nesting(236		&mut self,237		caller: caller,238		enable: bool,239		collections: Vec<address>,240	) -> Result<void> {241		if collections.is_empty() {242			return Err("No addresses provided".into());243		}244		if collections.len() >= OwnerRestrictedSet::bound() {245			return Err(Error::Revert(format!(246				"Out of bound: {} >= {}",247				collections.len(),248				OwnerRestrictedSet::bound()249			)));250		}251		check_is_owner_or_admin(caller, self)?;252		let permissions = CollectionPermissions {253			nesting: Some(match enable {254				false => NestingRule::Disabled,255				true => {256					let mut bv = OwnerRestrictedSet::new();257					for i in collections {258						bv.try_insert(crate::eth::map_eth_to_id(&i).ok_or_else(|| {259							Error::Revert("Can't convert address into collection id".into())260						})?)261						.map_err(|e| Error::Revert(format!("{:?}", e)))?;262					}263					NestingRule::OwnerRestricted(bv)264				}265			}),266			..Default::default()267		};268		self.collection.permissions = <Pallet<T>>::clamp_permissions(269			self.collection.mode.clone(),270			&self.collection.permissions,271			permissions,272		)273		.map_err(dispatch_to_evm::<T>)?;274		275		save(self)276	}277278	fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result<void> {279		check_is_owner_or_admin(caller, self)?;280		let permissions = CollectionPermissions{281			access: Some(match mode {282				0 => AccessMode::Normal,283				1 => AccessMode::AllowList,284				_ => return Err("Not supported access mode".into()),285			}),286			.. Default::default()287		};288		self.collection.permissions = <Pallet<T>>::clamp_permissions(289			self.collection.mode.clone(),290			&self.collection.permissions,291			permissions,292		)293		.map_err(dispatch_to_evm::<T>)?;294295		save(self)296	}297298	fn add_to_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {299		let caller = T::CrossAccountId::from_eth(caller);300		let user = T::CrossAccountId::from_eth(user);301		<Pallet<T>>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;302		Ok(())303	}304305	fn remove_from_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {306		let caller = T::CrossAccountId::from_eth(caller);307		let user = T::CrossAccountId::from_eth(user);308		<Pallet<T>>::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::<T>)?;309		Ok(())310	}311312	fn set_mint_mode(&mut self, caller: caller, mode: bool) -> Result<void> {313		check_is_owner_or_admin(caller, self)?;314		let permissions = CollectionPermissions { mint_mode: Some(mode), .. Default::default() };315		self.collection.permissions = <Pallet<T>>::clamp_permissions(316			self.collection.mode.clone(),317			&self.collection.permissions,318			permissions,319		)320		.map_err(dispatch_to_evm::<T>)?;321322		save(self)323	}324}325326fn check_is_owner_or_admin<T: Config>(327	caller: caller,328	collection: &CollectionHandle<T>,329) -> Result<T::CrossAccountId> {330	let caller = T::CrossAccountId::from_eth(caller);331	collection332		.check_is_owner_or_admin(&caller)333		.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;334	Ok(caller)335}336337fn save<T: Config>(collection: &CollectionHandle<T>) -> Result<void> {338	// TODO possibly delete for the lack of transaction339	collection340		.check_is_internal()341		.map_err(dispatch_to_evm::<T>)?;342	<crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());343	Ok(())344}345346pub fn token_uri_key() -> up_data_structs::PropertyKey {347	b"tokenURI"348		.to_vec()349		.try_into()350		.expect("length < limit; qed")351}
after · pallets/common/src/erc.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/>.1617use evm_coder::{18	solidity_interface, solidity, ToLog,19	types::*,20	execution::{Result, Error},21};22pub use pallet_evm::{PrecompileOutput, PrecompileResult, PrecompileHandle, account::CrossAccountId};23use pallet_evm_coder_substrate::dispatch_to_evm;24use sp_std::vec::Vec;25use up_data_structs::{26	Property, SponsoringRateLimit, NestingRule, OwnerRestrictedSet, AccessMode,27	CollectionPermissions,28};29use alloc::format;3031use crate::{Pallet, CollectionHandle, Config, CollectionProperties};3233#[derive(ToLog)]34pub enum CollectionHelpersEvents {35	CollectionCreated {36		#[indexed]37		owner: address,38		#[indexed]39		collection_id: address,40	},41}4243/// Does not always represent a full collection, for RFT it is either44/// collection (Implementing ERC721), or specific collection token (Implementing ERC20)45pub trait CommonEvmHandler {46	const CODE: &'static [u8];4748	fn call(self, handle: &mut impl PrecompileHandle) -> Option<PrecompileResult>;49}5051#[solidity_interface(name = "Collection")]52impl<T: Config> CollectionHandle<T>53where54	T::AccountId: From<[u8; 32]>,55{56	fn set_collection_property(&mut self, caller: caller, key: string, value: bytes) -> Result<void> {57		let caller = T::CrossAccountId::from_eth(caller);58		let key = <Vec<u8>>::from(key)59			.try_into()60			.map_err(|_| "key too large")?;61		let value = value.try_into().map_err(|_| "value too large")?;6263		<Pallet<T>>::set_collection_property(self, &caller, Property { key, value })64			.map_err(dispatch_to_evm::<T>)65	}6667	fn delete_collection_property(&mut self, caller: caller, key: string) -> Result<()> {68		let caller = T::CrossAccountId::from_eth(caller);69		let key = <Vec<u8>>::from(key)70			.try_into()71			.map_err(|_| "key too large")?;7273		<Pallet<T>>::delete_collection_property(self, &caller, key).map_err(dispatch_to_evm::<T>)74	}7576	/// Throws error if key not found77	fn collection_property(&self, key: string) -> Result<bytes> {78		let key = <Vec<u8>>::from(key)79			.try_into()80			.map_err(|_| "key too large")?;8182		let props = <CollectionProperties<T>>::get(self.id);83		let prop = props.get(&key).ok_or("key not found")?;8485		Ok(prop.to_vec())86	}8788	fn set_collection_sponsor(&mut self, caller: caller, sponsor: address) -> Result<void> {89		check_is_owner_or_admin(caller, self)?;9091		let sponsor = T::CrossAccountId::from_eth(sponsor);92		self.set_sponsor(sponsor.as_sub().clone())93			.map_err(dispatch_to_evm::<T>)?;94		save(self)95	}9697	fn confirm_collection_sponsorship(&mut self, caller: caller) -> Result<void> {98		let caller = T::CrossAccountId::from_eth(caller);99		if !self100			.confirm_sponsorship(caller.as_sub())101			.map_err(dispatch_to_evm::<T>)?102		{103			return Err("Caller is not set as sponsor".into());104		}105		save(self)106	}107108	#[solidity(rename_selector = "setCollectionLimit")]109	fn set_int_limit(&mut self, caller: caller, limit: string, value: uint32) -> Result<void> {110		check_is_owner_or_admin(caller, self)?;111		let mut limits = self.limits.clone();112113		match limit.as_str() {114			"accountTokenOwnershipLimit" => {115				limits.account_token_ownership_limit = Some(value);116			}117			"sponsoredDataSize" => {118				limits.sponsored_data_size = Some(value);119			}120			"sponsoredDataRateLimit" => {121				limits.sponsored_data_rate_limit = Some(SponsoringRateLimit::Blocks(value));122			}123			"tokenLimit" => {124				limits.token_limit = Some(value);125			}126			"sponsorTransferTimeout" => {127				limits.sponsor_transfer_timeout = Some(value);128			}129			"sponsorApproveTimeout" => {130				limits.sponsor_approve_timeout = Some(value);131			}132			_ => {133				return Err(Error::Revert(format!(134					"Unknown integer limit \"{}\"",135					limit136				)))137			}138		}139		self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)140			.map_err(dispatch_to_evm::<T>)?;141		save(self)142	}143144	#[solidity(rename_selector = "setCollectionLimit")]145	fn set_bool_limit(&mut self, caller: caller, limit: string, value: bool) -> Result<void> {146		check_is_owner_or_admin(caller, self)?;147		let mut limits = self.limits.clone();148149		match limit.as_str() {150			"ownerCanTransfer" => {151				limits.owner_can_transfer = Some(value);152			}153			"ownerCanDestroy" => {154				limits.owner_can_destroy = Some(value);155			}156			"transfersEnabled" => {157				limits.transfers_enabled = Some(value);158			}159			_ => {160				return Err(Error::Revert(format!(161					"Unknown boolean limit \"{}\"",162					limit163				)))164			}165		}166		self.limits = <Pallet<T>>::clamp_limits(self.mode.clone(), &self.limits, limits)167			.map_err(dispatch_to_evm::<T>)?;168		save(self)169	}170171	fn contract_address(&self, _caller: caller) -> Result<address> {172		Ok(crate::eth::collection_id_to_address(self.id))173	}174175	fn add_collection_admin_substrate(&self, caller: caller, new_admin: uint256) -> Result<void> {176		let caller = T::CrossAccountId::from_eth(caller);177		let mut new_admin_arr: [u8; 32] = Default::default();178		new_admin.to_big_endian(&mut new_admin_arr);179		let account_id = T::AccountId::from(new_admin_arr);180		let new_admin = T::CrossAccountId::from_sub(account_id);181		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;182		Ok(())183	}184185	fn remove_collection_admin_substrate(186		&self,187		caller: caller,188		new_admin: uint256,189	) -> Result<void> {190		let caller = T::CrossAccountId::from_eth(caller);191		let mut new_admin_arr: [u8; 32] = Default::default();192		new_admin.to_big_endian(&mut new_admin_arr);193		let account_id = T::AccountId::from(new_admin_arr);194		let new_admin = T::CrossAccountId::from_sub(account_id);195		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, false)196			.map_err(dispatch_to_evm::<T>)?;197		Ok(())198	}199200	fn add_collection_admin(&self, caller: caller, new_admin: address) -> Result<void> {201		let caller = T::CrossAccountId::from_eth(caller);202		let new_admin = T::CrossAccountId::from_eth(new_admin);203		<Pallet<T>>::toggle_admin(self, &caller, &new_admin, true).map_err(dispatch_to_evm::<T>)?;204		Ok(())205	}206207	fn remove_collection_admin(&self, caller: caller, admin: address) -> Result<void> {208		let caller = T::CrossAccountId::from_eth(caller);209		let admin = T::CrossAccountId::from_eth(admin);210		<Pallet<T>>::toggle_admin(self, &caller, &admin, false).map_err(dispatch_to_evm::<T>)?;211		Ok(())212	}213214	#[solidity(rename_selector = "setCollectionNesting")]215	fn set_nesting_bool(&mut self, caller: caller, enable: bool) -> Result<void> {216		check_is_owner_or_admin(caller, self)?;217		let permissions = CollectionPermissions {218			nesting: Some(match enable {219				false => NestingRule::Disabled,220				true => NestingRule::Owner,221			}),222			..Default::default()223		};224		self.collection.permissions = <Pallet<T>>::clamp_permissions(225			self.collection.mode.clone(),226			&self.collection.permissions,227			permissions,228		)229		.map_err(dispatch_to_evm::<T>)?;230231		save(self)232	}233234	#[solidity(rename_selector = "setCollectionNesting")]235	fn set_nesting(236		&mut self,237		caller: caller,238		enable: bool,239		collections: Vec<address>,240	) -> Result<void> {241		if collections.is_empty() {242			return Err("No addresses provided".into());243		}244		if collections.len() >= OwnerRestrictedSet::bound() {245			return Err(Error::Revert(format!(246				"Out of bound: {} >= {}",247				collections.len(),248				OwnerRestrictedSet::bound()249			)));250		}251		check_is_owner_or_admin(caller, self)?;252		let permissions = CollectionPermissions {253			nesting: Some(match enable {254				false => NestingRule::Disabled,255				true => {256					let mut bv = OwnerRestrictedSet::new();257					for i in collections {258						bv.try_insert(crate::eth::map_eth_to_id(&i).ok_or_else(|| {259							Error::Revert("Can't convert address into collection id".into())260						})?)261						.map_err(|e| Error::Revert(format!("{:?}", e)))?;262					}263					NestingRule::OwnerRestricted(bv)264				}265			}),266			..Default::default()267		};268		self.collection.permissions = <Pallet<T>>::clamp_permissions(269			self.collection.mode.clone(),270			&self.collection.permissions,271			permissions,272		)273		.map_err(dispatch_to_evm::<T>)?;274		275		save(self)276	}277278	fn set_collection_access(&mut self, caller: caller, mode: uint8) -> Result<void> {279		check_is_owner_or_admin(caller, self)?;280		let permissions = CollectionPermissions{281			access: Some(match mode {282				0 => AccessMode::Normal,283				1 => AccessMode::AllowList,284				_ => return Err("Not supported access mode".into()),285			}),286			.. Default::default()287		};288		self.collection.permissions = <Pallet<T>>::clamp_permissions(289			self.collection.mode.clone(),290			&self.collection.permissions,291			permissions,292		)293		.map_err(dispatch_to_evm::<T>)?;294295		save(self)296	}297298	fn add_to_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {299		let caller = T::CrossAccountId::from_eth(caller);300		let user = T::CrossAccountId::from_eth(user);301		<Pallet<T>>::toggle_allowlist(self, &caller, &user, true).map_err(dispatch_to_evm::<T>)?;302		Ok(())303	}304305	fn remove_from_collection_allow_list(&self, caller: caller, user: address) -> Result<void> {306		let caller = T::CrossAccountId::from_eth(caller);307		let user = T::CrossAccountId::from_eth(user);308		<Pallet<T>>::toggle_allowlist(self, &caller, &user, false).map_err(dispatch_to_evm::<T>)?;309		Ok(())310	}311312	fn set_collection_mint_mode(&mut self, caller: caller, mode: bool) -> Result<void> {313		check_is_owner_or_admin(caller, self)?;314		let permissions = CollectionPermissions { mint_mode: Some(mode), .. Default::default() };315		self.collection.permissions = <Pallet<T>>::clamp_permissions(316			self.collection.mode.clone(),317			&self.collection.permissions,318			permissions,319		)320		.map_err(dispatch_to_evm::<T>)?;321322		save(self)323	}324}325326fn check_is_owner_or_admin<T: Config>(327	caller: caller,328	collection: &CollectionHandle<T>,329) -> Result<T::CrossAccountId> {330	let caller = T::CrossAccountId::from_eth(caller);331	collection332		.check_is_owner_or_admin(&caller)333		.map_err(pallet_evm_coder_substrate::dispatch_to_evm::<T>)?;334	Ok(caller)335}336337fn save<T: Config>(collection: &CollectionHandle<T>) -> Result<void> {338	// TODO possibly delete for the lack of transaction339	collection340		.check_is_internal()341		.map_err(dispatch_to_evm::<T>)?;342	<crate::CollectionById<T>>::insert(collection.id, collection.collection.clone());343	Ok(())344}345346pub fn token_uri_key() -> up_data_structs::PropertyKey {347	b"tokenURI"348		.to_vec()349		.try_into()350		.expect("length < limit; qed")351}
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
@@ -330,7 +330,7 @@
 	}
 }
 
-// Selector: c0de6be0
+// Selector: 7d9262e6
 contract Collection is Dummy, ERC165 {
 	// Selector: setCollectionProperty(string,bytes) 2f073f66
 	function setCollectionProperty(string memory key, bytes memory value)
@@ -427,15 +427,17 @@
 		dummy;
 	}
 
-	// Selector: setNesting(bool) e8fc50dd
-	function setNesting(bool enable) public {
+	// Selector: setCollectionNesting(bool) 112d4586
+	function setCollectionNesting(bool enable) public {
 		require(false, stub_error);
 		enable;
 		dummy = 0;
 	}
 
-	// Selector: setNesting(bool,address[]) 7df12a9a
-	function setNesting(bool enable, address[] memory collections) public {
+	// Selector: setCollectionNesting(bool,address[]) 64872396
+	function setCollectionNesting(bool enable, address[] memory collections)
+		public
+	{
 		require(false, stub_error);
 		enable;
 		collections;
@@ -463,8 +465,8 @@
 		dummy;
 	}
 
-	// Selector: setMintMode(bool) 5dea9bd5
-	function setMintMode(bool mode) public {
+	// Selector: setCollectionMintMode(bool) 00018e84
+	function setCollectionMintMode(bool mode) public {
 		require(false, stub_error);
 		mode;
 		dummy = 0;
modifiedtests/src/eth/api/UniqueNFT.soldiffbeforeafterboth
--- a/tests/src/eth/api/UniqueNFT.sol
+++ b/tests/src/eth/api/UniqueNFT.sol
@@ -191,7 +191,7 @@
 	function totalSupply() external view returns (uint256);
 }
 
-// Selector: c0de6be0
+// Selector: 7d9262e6
 interface Collection is Dummy, ERC165 {
 	// Selector: setCollectionProperty(string,bytes) 2f073f66
 	function setCollectionProperty(string memory key, bytes memory value)
@@ -235,11 +235,12 @@
 	// Selector: removeCollectionAdmin(address) fafd7b42
 	function removeCollectionAdmin(address admin) external view;
 
-	// Selector: setNesting(bool) e8fc50dd
-	function setNesting(bool enable) external;
+	// Selector: setCollectionNesting(bool) 112d4586
+	function setCollectionNesting(bool enable) external;
 
-	// Selector: setNesting(bool,address[]) 7df12a9a
-	function setNesting(bool enable, address[] memory collections) external;
+	// Selector: setCollectionNesting(bool,address[]) 64872396
+	function setCollectionNesting(bool enable, address[] memory collections)
+		external;
 
 	// Selector: setCollectionAccess(uint8) 41835d4c
 	function setCollectionAccess(uint8 mode) external;
@@ -250,8 +251,8 @@
 	// Selector: removeFromCollectionAllowList(address) 85c51acb
 	function removeFromCollectionAllowList(address user) external view;
 
-	// Selector: setMintMode(bool) 5dea9bd5
-	function setMintMode(bool mode) external;
+	// Selector: setCollectionMintMode(bool) 00018e84
+	function setCollectionMintMode(bool mode) external;
 }
 
 // Selector: d74d154f
modifiedtests/src/eth/collectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/eth/collectionAdmin.test.ts
+++ b/tests/src/eth/collectionAdmin.test.ts
@@ -25,8 +25,8 @@
 } from './util/helpers';
 
 describe('Add collection admins', () => {
-  itWeb3('Add admin by owner', async ({api, web3}) => {
-    const owner = await createEthAccountWithBalance(api, web3);
+  itWeb3('Add admin by owner', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
         
     const result = await collectionHelper.methods
@@ -42,8 +42,8 @@
       .to.be.eq(newAdmin.toLocaleLowerCase());
   });
 
-  itWeb3('Add substrate admin by owner', async ({api, web3}) => {
-    const owner = await createEthAccountWithBalance(api, web3);
+  itWeb3('Add substrate admin by owner', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
         
     const result = await collectionHelper.methods
@@ -60,8 +60,8 @@
       .to.be.eq(newAdmin.address.toLocaleLowerCase());
   });
 
-  itWeb3('(!negative tests!) Add admin by ADMIN is not allowed', async ({api, web3}) => {
-    const owner = await createEthAccountWithBalance(api, web3);
+  itWeb3('(!negative tests!) Add admin by ADMIN is not allowed', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
         
     const result = await collectionHelper.methods
@@ -69,7 +69,7 @@
       .send();
     const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
 
-    const admin = await createEthAccountWithBalance(api, web3);
+    const admin = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
     await collectionEvm.methods.addCollectionAdmin(admin).send();
     
@@ -83,8 +83,8 @@
       .to.be.eq(admin.toLocaleLowerCase());
   });
 
-  itWeb3('(!negative tests!) Add admin by USER is not allowed', async ({api, web3}) => {
-    const owner = await createEthAccountWithBalance(api, web3);
+  itWeb3('(!negative tests!) Add admin by USER is not allowed', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
         
     const result = await collectionHelper.methods
@@ -92,7 +92,7 @@
       .send();
     const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
 
-    const notAdmin = await createEthAccountWithBalance(api, web3);
+    const notAdmin = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
     
     const user = await createEthAccount(web3);
@@ -103,8 +103,8 @@
     expect(adminList.length).to.be.eq(0);
   });
 
-  itWeb3('(!negative tests!) Add substrate admin by ADMIN is not allowed', async ({api, web3}) => {
-    const owner = await createEthAccountWithBalance(api, web3);
+  itWeb3('(!negative tests!) Add substrate admin by ADMIN is not allowed', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
         
     const result = await collectionHelper.methods
@@ -112,7 +112,7 @@
       .send();
     const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
 
-    const admin = await createEthAccountWithBalance(api, web3);
+    const admin = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
     await collectionEvm.methods.addCollectionAdmin(admin).send();
 
@@ -126,8 +126,8 @@
       .to.be.eq(admin.toLocaleLowerCase());
   });
   
-  itWeb3('(!negative tests!) Add substrate admin by USER is not allowed', async ({api, web3}) => {
-    const owner = await createEthAccountWithBalance(api, web3);
+  itWeb3('(!negative tests!) Add substrate admin by USER is not allowed', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
         
     const result = await collectionHelper.methods
@@ -135,7 +135,7 @@
       .send();
     const {collectionIdAddress, collectionId} = await getCollectionAddressFromResult(api, result);
 
-    const notAdmin0 = await createEthAccountWithBalance(api, web3);
+    const notAdmin0 = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
     const notAdmin1 = privateKey('//Alice');
     await expect(collectionEvm.methods.addCollectionAdminSubstrate(notAdmin1.addressRaw).call({from: notAdmin0}))
@@ -147,8 +147,8 @@
 });
 
 describe('Remove collection admins', () => {
-  itWeb3('Remove admin by owner', async ({api, web3}) => {
-    const owner = await createEthAccountWithBalance(api, web3);
+  itWeb3('Remove admin by owner', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
         
     const result = await collectionHelper.methods
@@ -171,8 +171,8 @@
     expect(adminList.length).to.be.eq(0);
   });
 
-  itWeb3('Remove substrate admin by owner', async ({api, web3}) => {
-    const owner = await createEthAccountWithBalance(api, web3);
+  itWeb3('Remove substrate admin by owner', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
         
     const result = await collectionHelper.methods
@@ -194,8 +194,8 @@
     expect(adminList.length).to.be.eq(0);
   });
 
-  itWeb3('(!negative tests!) Remove admin by ADMIN is not allowed', async ({api, web3}) => {
-    const owner = await createEthAccountWithBalance(api, web3);
+  itWeb3('(!negative tests!) Remove admin by ADMIN is not allowed', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
         
     const result = await collectionHelper.methods
@@ -205,7 +205,7 @@
 
     const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
 
-    const admin0 = await createEthAccountWithBalance(api, web3);
+    const admin0 = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     await collectionEvm.methods.addCollectionAdmin(admin0).send();
     const admin1 = await createEthAccount(web3);
     await collectionEvm.methods.addCollectionAdmin(admin1).send();
@@ -221,8 +221,8 @@
     }
   });
 
-  itWeb3('(!negative tests!) Remove admin by USER is not allowed', async ({api, web3}) => {
-    const owner = await createEthAccountWithBalance(api, web3);
+  itWeb3('(!negative tests!) Remove admin by USER is not allowed', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
         
     const result = await collectionHelper.methods
@@ -232,7 +232,7 @@
 
     const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
 
-    const admin = await createEthAccountWithBalance(api, web3);
+    const admin = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     await collectionEvm.methods.addCollectionAdmin(admin).send();
     const notAdmin = await createEthAccount(web3);
 
@@ -246,8 +246,8 @@
     }
   });
 
-  itWeb3('(!negative tests!) Remove substrate admin by ADMIN is not allowed', async ({api, web3}) => {
-    const owner = await createEthAccountWithBalance(api, web3);
+  itWeb3('(!negative tests!) Remove substrate admin by ADMIN is not allowed', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
         
     const result = await collectionHelper.methods
@@ -258,7 +258,7 @@
     const adminSub = privateKey('//Alice');
     const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
     await collectionEvm.methods.addCollectionAdminSubstrate(adminSub.addressRaw).send();
-    const adminEth = await createEthAccountWithBalance(api, web3);
+    const adminEth = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     await collectionEvm.methods.addCollectionAdmin(adminEth).send();
 
     await expect(collectionEvm.methods.removeCollectionAdminSubstrate(adminSub.addressRaw).call({from: adminEth}))
@@ -271,8 +271,8 @@
       .to.be.deep.contains(adminEth.toLocaleLowerCase());
   });
 
-  itWeb3('(!negative tests!) Remove substrate admin by USER is not allowed', async ({api, web3}) => {
-    const owner = await createEthAccountWithBalance(api, web3);
+  itWeb3('(!negative tests!) Remove substrate admin by USER is not allowed', async ({api, web3, privateKeyWrapper}) => {
+    const owner = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
     const collectionHelper = evmCollectionHelpers(web3, owner);
         
     const result = await collectionHelper.methods
@@ -283,7 +283,7 @@
     const adminSub = privateKey('//Alice');
     const collectionEvm = evmCollection(web3, owner, collectionIdAddress);
     await collectionEvm.methods.addCollectionAdminSubstrate(adminSub.addressRaw).send();
-    const notAdminEth = await createEthAccountWithBalance(api, web3);
+    const notAdminEth = await createEthAccountWithBalance(api, web3, privateKeyWrapper);
 
     await expect(collectionEvm.methods.removeCollectionAdminSubstrate(adminSub.addressRaw).call({from: notAdminEth}))
       .to.be.rejectedWith('NoPermission');
modifiedtests/src/eth/contractSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/contractSponsoring.test.ts
+++ b/tests/src/eth/contractSponsoring.test.ts
@@ -250,7 +250,7 @@
 
     await collectionEvm.methods.setCollectionAccess(1 /*'AllowList'*/).send({from: owner});
     await collectionEvm.methods.addToCollectionAllowList(user).send({from: owner});
-    await collectionEvm.methods.setMintMode(true).send({from: owner});
+    await collectionEvm.methods.setCollectionMintMode(true).send({from: owner});
 
     const newPermissions = (await getDetailedCollectionInfo(api, collectionId))!.permissions.toHuman();
     expect(newPermissions.mintMode).to.be.true;
modifiedtests/src/eth/nonFungibleAbi.jsondiffbeforeafterboth
--- a/tests/src/eth/nonFungibleAbi.json
+++ b/tests/src/eth/nonFungibleAbi.json
@@ -386,27 +386,15 @@
     "type": "function"
   },
   {
-    "inputs": [
-      { "internalType": "string", "name": "key", "type": "string" },
-      { "internalType": "bytes", "name": "value", "type": "bytes" }
-    ],
-    "name": "setCollectionProperty",
-    "outputs": [],
-    "stateMutability": "nonpayable",
-    "type": "function"
-  },
-  {
-    "inputs": [
-      { "internalType": "address", "name": "sponsor", "type": "address" }
-    ],
-    "name": "setCollectionSponsor",
+    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
+    "name": "setCollectionMintMode",
     "outputs": [],
     "stateMutability": "nonpayable",
     "type": "function"
   },
   {
-    "inputs": [{ "internalType": "bool", "name": "mode", "type": "bool" }],
-    "name": "setMintMode",
+    "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
+    "name": "setCollectionNesting",
     "outputs": [],
     "stateMutability": "nonpayable",
     "type": "function"
@@ -420,14 +408,26 @@
         "type": "address[]"
       }
     ],
-    "name": "setNesting",
+    "name": "setCollectionNesting",
     "outputs": [],
     "stateMutability": "nonpayable",
     "type": "function"
   },
   {
-    "inputs": [{ "internalType": "bool", "name": "enable", "type": "bool" }],
-    "name": "setNesting",
+    "inputs": [
+      { "internalType": "string", "name": "key", "type": "string" },
+      { "internalType": "bytes", "name": "value", "type": "bytes" }
+    ],
+    "name": "setCollectionProperty",
+    "outputs": [],
+    "stateMutability": "nonpayable",
+    "type": "function"
+  },
+  {
+    "inputs": [
+      { "internalType": "address", "name": "sponsor", "type": "address" }
+    ],
+    "name": "setCollectionSponsor",
     "outputs": [],
     "stateMutability": "nonpayable",
     "type": "function"
modifiedtests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/removeCollectionAdmin.test.ts
+++ b/tests/src/removeCollectionAdmin.test.ts
@@ -111,18 +111,24 @@
     });
   });
 
-  it('Admin can\'t remove collection admin.', async () => {
+  it.only('Admin can\'t remove collection admin.', async () => {
     await usingApi(async (api, privateKeyWrapper) => {
       const collectionId = await createCollectionExpectSuccess();
       const alice = privateKeyWrapper('//Alice');
       const bob = privateKeyWrapper('//Bob');
       const charlie = privateKeyWrapper('//Charlie');
 
+      const addBobAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(bob.address));
+      await submitTransactionAsync(alice, addBobAdminTx);
+      const addCharlieAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(charlie.address));
+      await submitTransactionAsync(alice, addCharlieAdminTx);
+
       const adminListAfterAddAdmin = await getAdminList(api, collectionId);
       expect(adminListAfterAddAdmin).to.be.deep.contains(normalizeAccountId(bob.address));
+      expect(adminListAfterAddAdmin).to.be.deep.contains(normalizeAccountId(charlie.address));
 
       const removeAdminTx = api.tx.unique.removeCollectionAdmin(collectionId, normalizeAccountId(bob.address));
-      await expect(submitTransactionAsync(charlie, removeAdminTx)).to.be.rejected;
+      await expect(submitTransactionExpectFailAsync(charlie, removeAdminTx)).to.be.rejected;
 
       const adminListAfterRemoveAdmin = await getAdminList(api, collectionId);
       expect(adminListAfterRemoveAdmin).to.be.deep.contains(normalizeAccountId(bob.address));