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

difftreelog

fix merge test changes

Yaroslav Bolyukin2021-06-25parent: #928aa03.patch.diff
in: master

7 files changed

modifiedpallets/inflation/src/tests.rsdiffbeforeafterboth
--- a/pallets/inflation/src/tests.rs
+++ b/pallets/inflation/src/tests.rs
@@ -34,9 +34,9 @@
 			NodeBlock = Block,
 			UncheckedExtrinsic = UncheckedExtrinsic,
 		{
-			Balances: pallet_balances::{Module, Call, Storage},
-			System: frame_system::{Module, Call, Config, Storage, Event<T>},
-			Inflation: pallet_inflation::{Module, Call, Storage},
+			Balances: pallet_balances::{Pallet, Call, Storage},
+			System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
+			Inflation: pallet_inflation::{Pallet, Call, Storage},
 		}
 	);
 
@@ -70,6 +70,7 @@
 		type OnKilledAccount = ();
 		type SystemWeightInfo = ();
 		type SS58Prefix = SS58Prefix;
+        type OnSetCode = ();
 	}
 
 	parameter_types! {
modifiedpallets/nft/src/eth/sponsoring.rsdiffbeforeafterboth
--- a/pallets/nft/src/eth/sponsoring.rs
+++ b/pallets/nft/src/eth/sponsoring.rs
@@ -32,7 +32,7 @@
             match call {
                 UniqueNFTCall::ERC721UniqueExtensions(ERC721UniqueExtensionsCall::Transfer {token_id, ..}) | UniqueNFTCall::ERC721(ERC721Call::TransferFrom {token_id, ..})  => {
                     let token_id: u32 = token_id.try_into().map_err(|_| AnyError)?;
-                    let block_number = <frame_system::Module<T>>::block_number() as T::BlockNumber;
+                    let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
                     let collection_limits = &collection.limits;
                     let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {
                         collection_limits.sponsor_transfer_timeout
@@ -68,7 +68,7 @@
                         ChainLimit::get().fungible_sponsor_transfer_timeout
                     };
 
-                    let block_number = <frame_system::Module<T>>::block_number() as T::BlockNumber;
+                    let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
                     let mut sponsored = true;
                     if <FungibleTransferBasket<T>>::contains_key(collection_id, who.as_sub()) {
                         let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who.as_sub());
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
before · pallets/nft/src/lib.rs
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56#![recursion_limit = "1024"]78#![cfg_attr(not(feature = "std"), no_std)]910extern crate alloc;1112pub use serde::{Serialize, Deserialize};1314pub use frame_support::{15    construct_runtime, decl_event, decl_module, decl_storage, decl_error,16    dispatch::DispatchResult,17    ensure, fail, parameter_types,18    traits::{19        Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,20        Randomness, IsSubType, WithdrawReasons,21    },22    weights::{23        constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},24        DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,25        WeightToFeePolynomial, DispatchClass,26    },27    StorageValue,28    transactional,29};3031use frame_system::{self as system, ensure_signed, ensure_root};32use sp_core::H160;33use sp_runtime::sp_std::prelude::Vec;34use core::ops::{Deref, DerefMut};35use core::cell::RefCell;36use nft_data_structs::{37    MAX_DECIMAL_POINTS, MAX_SPONSOR_TIMEOUT, MAX_TOKEN_OWNERSHIP, MAX_REFUNGIBLE_PIECES,38	AccessMode, ChainLimits, Collection, CreateItemData, CollectionLimits,39    CollectionId, CollectionMode, TokenId, 40    SchemaVersion, SponsorshipState, Ownership,41    NftItemType, FungibleItemType, ReFungibleItemType42};43use pallet_ethereum::EthereumTransactionSender;4445#[cfg(test)]46mod mock;4748#[cfg(test)]49mod tests;5051mod default_weights;52mod eth;53mod sponsorship;54pub use sponsorship::NftSponsorshipHandler;5556pub use eth::NftErcSupport;57pub use eth::account::*;58use eth::erc::{ERC20Events, ERC721Events};5960#[cfg(feature = "runtime-benchmarks")]61mod benchmarking;6263pub trait WeightInfo {64	fn create_collection() -> Weight;65	fn destroy_collection() -> Weight;66	fn add_to_white_list() -> Weight;67	fn remove_from_white_list() -> Weight;68    fn set_public_access_mode() -> Weight;69    fn set_mint_permission() -> Weight;70    fn change_collection_owner() -> Weight;71    fn add_collection_admin() -> Weight;72    fn remove_collection_admin() -> Weight;73    fn set_collection_sponsor() -> Weight;74    fn confirm_sponsorship() -> Weight;75    fn remove_collection_sponsor() -> Weight;76    fn create_item(s: usize) -> Weight;77    fn burn_item() -> Weight;78    fn transfer() -> Weight;79    fn approve() -> Weight;80    fn transfer_from() -> Weight;81    fn set_offchain_schema() -> Weight;82    fn set_const_on_chain_schema() -> Weight;83    fn set_variable_on_chain_schema() -> Weight;84    fn set_variable_meta_data() -> Weight;85    fn enable_contract_sponsoring() -> Weight;86    fn set_schema_version() -> Weight;87    fn set_chain_limits() -> Weight;88    fn set_contract_sponsoring_rate_limit() -> Weight;89    fn set_variable_meta_data_sponsoring_rate_limit() -> Weight;90    fn toggle_contract_white_list() -> Weight;91    fn add_to_contract_white_list() -> Weight;92    fn remove_from_contract_white_list() -> Weight;93    fn set_collection_limits() -> Weight;94}9596decl_error! {97	/// Error for non-fungible-token module.98	pub enum Error for Module<T: Config> {99        /// Total collections bound exceeded.100        TotalCollectionsLimitExceeded,101		/// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.102        CollectionDecimalPointLimitExceeded, 103        /// Collection name can not be longer than 63 char.104        CollectionNameLimitExceeded, 105        /// Collection description can not be longer than 255 char.106        CollectionDescriptionLimitExceeded, 107        /// Token prefix can not be longer than 15 char.108        CollectionTokenPrefixLimitExceeded,109        /// This collection does not exist.110        CollectionNotFound,111        /// Item not exists.112        TokenNotFound,113        /// Admin not found114        AdminNotFound,115        /// Arithmetic calculation overflow.116        NumOverflow,       117        /// Account already has admin role.118        AlreadyAdmin,  119        /// You do not own this collection.120        NoPermission,121        /// This address is not set as sponsor, use setCollectionSponsor first.122        ConfirmUnsetSponsorFail,123        /// Collection is not in mint mode.124        PublicMintingNotAllowed,125        /// Sender parameter and item owner must be equal.126        MustBeTokenOwner,127        /// Item balance not enough.128        TokenValueTooLow,129        /// Size of item is too large.130        NftSizeLimitExceeded,131        /// No approve found132        ApproveNotFound,133        /// Requested value more than approved.134        TokenValueNotEnough,135        /// Only approved addresses can call this method.136        ApproveRequired,137        /// Address is not in white list.138        AddresNotInWhiteList,139        /// Number of collection admins bound exceeded.140        CollectionAdminsLimitExceeded,141        /// Owned tokens by a single address bound exceeded.142        AddressOwnershipLimitExceeded,143        /// Length of items properties must be greater than 0.144        EmptyArgument,145        /// const_data exceeded data limit.146        TokenConstDataLimitExceeded,147        /// variable_data exceeded data limit.148        TokenVariableDataLimitExceeded,149        /// Not NFT item data used to mint in NFT collection.150        NotNftDataUsedToMintNftCollectionToken,151        /// Not Fungible item data used to mint in Fungible collection.152        NotFungibleDataUsedToMintFungibleCollectionToken,153        /// Not Re Fungible item data used to mint in Re Fungible collection.154        NotReFungibleDataUsedToMintReFungibleCollectionToken,155        /// Unexpected collection type.156        UnexpectedCollectionType,157        /// Can't store metadata in fungible tokens.158        CantStoreMetadataInFungibleTokens,159        /// Collection token limit exceeded160        CollectionTokenLimitExceeded,161        /// Account token limit exceeded per collection162        AccountTokenLimitExceeded,163        /// Collection limit bounds per collection exceeded164        CollectionLimitBoundsExceeded,165        /// Tried to enable permissions which are only permitted to be disabled166        OwnerPermissionsCantBeReverted,167        /// Schema data size limit bound exceeded168        SchemaDataLimitExceeded,169        /// Maximum refungibility exceeded170        WrongRefungiblePieces,171        /// createRefungible should be called with one owner172        BadCreateRefungibleCall,173        /// Gas limit exceeded174        OutOfGas,175	}176}177178pub struct CollectionHandle<T: Config> {179    pub id: CollectionId,180    collection: Collection<T>,181    logs: eth::log::LogRecorder,182    evm_address: H160,183    gas_limit: RefCell<u64>,184}185impl<T: Config> CollectionHandle<T> {186	pub fn get_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {187		<CollectionById<T>>::get(id)188			.map(|collection| Self {189				id,190				collection,191                logs: eth::log::LogRecorder::default(),192                evm_address: eth::collection_id_to_address(id),193                gas_limit: RefCell::new(gas_limit),194			})195	}196    pub fn get(id: CollectionId) -> Option<Self> {197        Self::get_with_gas_limit(id, u64::MAX)198    }199    pub fn gas_left(&self) -> u64 {200        *self.gas_limit.borrow()201    }202    pub fn consume_gas(&self, gas: u64) -> DispatchResult {203        let mut gas_limit = self.gas_limit.borrow_mut();204        if *gas_limit < gas {205            fail!(Error::<T>::OutOfGas);206        }207        *gas_limit -= gas;208        Ok(())209    }210    pub fn log(&self, log: impl evm_coder::ToLog) {211        self.logs.log(log.to_log(self.evm_address))212    }213    pub fn into_inner(self) -> Collection<T> {214        self.collection.clone()215    }216}217impl<T: Config> Deref for CollectionHandle<T> {218    type Target = Collection<T>;219220    fn deref(&self) -> &Self::Target {221        &self.collection222    }223}224225impl<T: Config> DerefMut for CollectionHandle<T> {226    fn deref_mut(&mut self) -> &mut Self::Target {227        &mut self.collection228    }229}230231pub trait Config: system::Config + Sized {232    type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;233234    /// Weight information for extrinsics in this pallet.235	type WeightInfo: WeightInfo;236237    type EvmAddressMapping: pallet_evm::AddressMapping<Self::AccountId>;238    type EvmBackwardsAddressMapping: EvmBackwardsAddressMapping<Self::AccountId>;239    type EvmWithdrawOrigin: pallet_evm::EnsureAddressOrigin<Self::Origin, Success = Self::AccountId>;240241	type CrossAccountId: CrossAccountId<Self::AccountId>;242    type Currency: Currency<Self::AccountId>;243    type CollectionCreationPrice: Get<<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance>;244    type TreasuryAccountId: Get<Self::AccountId>;245246    type EthereumChainId: Get<u64>;247    type EthereumTransactionSender: pallet_ethereum::EthereumTransactionSender;248}249250// # Used definitions251//252// ## User control levels253//254// chain-controlled - key is uncontrolled by user255//                    i.e autoincrementing index256//                    can use non-cryptographic hash257// real - key is controlled by user258//        but it is hard to generate enough colliding values, i.e owner of signed txs259//        can use non-cryptographic hash260// controlled - key is completly controlled by users261//              i.e maps with mutable keys262//              should use cryptographic hash263//264// ## User control level downgrade reasons265//266// ?1 - chain-controlled -> controlled267//      collections/tokens can be destroyed, resulting in massive holes268// ?2 - chain-controlled -> controlled269//      same as ?1, but can be only added, resulting in easier exploitation270// ?3 - real -> controlled271//      no confirmation required, so addresses can be easily generated272decl_storage! {273    trait Store for Module<T: Config> as Nft {274275        //#region Private members276        /// Id of next collection277        CreatedCollectionCount: u32;278        /// Used for migrations279        ChainVersion: u64;280        /// Id of last collection token281        /// Collection id (controlled?1)282        ItemListIndex: map hasher(blake2_128_concat) CollectionId => TokenId;283        //#endregion284285        //#region Chain limits struct286        pub ChainLimit get(fn chain_limit) config(): ChainLimits;287        //#endregion288289        //#region Bound counters290        /// Amount of collections destroyed, used for total amount tracking with291        /// CreatedCollectionCount292        DestroyedCollectionCount: u32;293        /// Total amount of account owned tokens (NFTs + RFTs + unique fungibles)294        /// Account id (real)295        pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;296        //#endregion297298        //#region Basic collections299        /// Collection info300        /// Collection id (controlled?1)301        pub CollectionById get(fn collection_id) config(): map hasher(blake2_128_concat) CollectionId => Option<Collection<T>> = None;302        /// List of collection admins303        /// Collection id (controlled?2)304        pub AdminList get(fn admin_list_collection): map hasher(blake2_128_concat) CollectionId => Vec<T::CrossAccountId>;305        /// Whitelisted collection users306        /// Collection id (controlled?2), user id (controlled?3)307        pub WhiteList get(fn white_list): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => bool;308        //#endregion309310        /// How many of collection items user have311        /// Collection id (controlled?2), account id (real)312        pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => u128;313314        /// Amount of items which spender can transfer out of owners account (via transferFrom)315        /// Collection id (controlled?2), (token id (controlled ?2) + owner account id (real) + spender account id (controlled?3))316        /// TODO: Off chain worker should remove from this map when token gets removed317        pub Allowances get(fn approved): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) (TokenId, T::AccountId, T::AccountId) => u128;318319        //#region Item collections320        /// Collection id (controlled?2), token id (controlled?1)321        pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<NftItemType<T::CrossAccountId>>;322        /// Collection id (controlled?2), owner (controlled?2)323        pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => FungibleItemType;324        /// Collection id (controlled?2), token id (controlled?1)325        pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<ReFungibleItemType<T::CrossAccountId>>;326        //#endregion327328        //#region Index list329        /// Collection id (controlled?2), tokens owner (controlled?2)330        pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => Vec<TokenId>;331        //#endregion332333        //#region Tokens transfer rate limit baskets334        /// (Collection id (controlled?2), who created (real))335        /// TODO: Off chain worker should remove from this map when collection gets removed336        pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => T::BlockNumber;337        /// Collection id (controlled?2), token id (controlled?2)338        pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;339        /// Collection id (controlled?2), owning user (real)340        pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;341        /// Collection id (controlled?2), token id (controlled?2)342        pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;343        //#endregion344345        /// Variable metadata sponsoring346        /// Collection id (controlled?2), token id (controlled?2)347        pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber> = None;348    }349    add_extra_genesis {350        build(|config: &GenesisConfig<T>| {351            // Modification of storage352            for (_num, _c) in &config.collection_id {353                <Module<T>>::init_collection(_c);354            }355356            for (_num, _c, _i) in &config.nft_item_id {357                <Module<T>>::init_nft_token(*_c, _i);358            }359360            for (collection_id, account_id, fungible_item) in &config.fungible_item_id {361                <Module<T>>::init_fungible_token(*collection_id, &T::CrossAccountId::from_sub(account_id.clone()), fungible_item);362            }363364            for (_num, _c, _i) in &config.refungible_item_id {365                <Module<T>>::init_refungible_token(*_c, _i);366            }367        })368    }369}370371decl_event!(372    pub enum Event<T>373    where374        AccountId = <T as frame_system::Config>::AccountId,375        CrossAccountId = <T as Config>::CrossAccountId,376    {377        /// New collection was created378        /// 379        /// # Arguments380        /// 381        /// * collection_id: Globally unique identifier of newly created collection.382        /// 383        /// * mode: [CollectionMode] converted into u8.384        /// 385        /// * account_id: Collection owner.386        CollectionCreated(CollectionId, u8, AccountId),387388        /// New item was created.389        /// 390        /// # Arguments391        /// 392        /// * collection_id: Id of the collection where item was created.393        /// 394        /// * item_id: Id of an item. Unique within the collection.395        ///396        /// * recipient: Owner of newly created item 397        ItemCreated(CollectionId, TokenId, CrossAccountId),398399        /// Collection item was burned.400        /// 401        /// # Arguments402        /// 403        /// collection_id.404        /// 405        /// item_id: Identifier of burned NFT.406        ItemDestroyed(CollectionId, TokenId),407408        /// Item was transferred409        ///410        /// * collection_id: Id of collection to which item is belong411        ///412        /// * item_id: Id of an item413        ///414        /// * sender: Original owner of item415        ///416        /// * recipient: New owner of item417        ///418        /// * amount: Always 1 for NFT419        Transfer(CollectionId, TokenId, CrossAccountId, CrossAccountId, u128),420421        /// * collection_id422        ///423        /// * item_id424        ///425        /// * sender426        ///427        /// * spender428        ///429        /// * amount430        Approved(CollectionId, TokenId, CrossAccountId, CrossAccountId, u128),431    }432);433434decl_module! {435    pub struct Module<T: Config> for enum Call 436    where 437        origin: T::Origin438    {439        fn deposit_event() = default;440        type Error = Error<T>;441442        fn on_initialize(_now: T::BlockNumber) -> Weight {443            0444        }445446        /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner and admin of the collection are set to the address that signed the transaction. Both addresses can be changed later.447        /// 448        /// # Permissions449        /// 450        /// * Anyone.451        /// 452        /// # Arguments453        /// 454        /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.455        /// 456        /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.457        /// 458        /// * token_prefix: UTF-8 string with token prefix.459        /// 460        /// * mode: [CollectionMode] collection type and type dependent data.461        // returns collection ID462        #[weight = <T as Config>::WeightInfo::create_collection()]463        #[transactional]464        pub fn create_collection(origin,465                                 collection_name: Vec<u16>,466                                 collection_description: Vec<u16>,467                                 token_prefix: Vec<u8>,468                                 mode: CollectionMode) -> DispatchResult {469470            // Anyone can create a collection471            let who = ensure_signed(origin)?;472473            // Take a (non-refundable) deposit of collection creation474            let mut imbalance = <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();475            imbalance.subsume(<<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(476                &T::TreasuryAccountId::get(),477                T::CollectionCreationPrice::get(),478            ));479            <T as Config>::Currency::settle(480                &who,481                imbalance,482                WithdrawReasons::TRANSFER,483                ExistenceRequirement::KeepAlive,484            ).map_err(|_| Error::<T>::NoPermission)?;485486            let decimal_points = match mode {487                CollectionMode::Fungible(points) => points,488                _ => 0489            };490491            let chain_limit = ChainLimit::get();492493            let created_count = CreatedCollectionCount::get();494            let destroyed_count = DestroyedCollectionCount::get();495496            // bound Total number of collections497            ensure!(created_count - destroyed_count < chain_limit.collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);498499            // check params500            ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);501            ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);502            ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);503            ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);504505            // Generate next collection ID506            let next_id = created_count507                .checked_add(1)508                .ok_or(Error::<T>::NumOverflow)?;509510            CreatedCollectionCount::put(next_id);511512            let limits = CollectionLimits {513                sponsored_data_size: chain_limit.custom_data_limit,514                ..Default::default()515            };516517            // Create new collection518            let new_collection = Collection {519                owner: who.clone(),520                name: collection_name,521                mode: mode.clone(),522                mint_mode: false,523                access: AccessMode::Normal,524                description: collection_description,525                decimal_points: decimal_points,526                token_prefix: token_prefix,527                offchain_schema: Vec::new(),528                schema_version: SchemaVersion::ImageURL,529                sponsorship: SponsorshipState::Disabled,530                variable_on_chain_schema: Vec::new(),531                const_on_chain_schema: Vec::new(),532                limits,533            };534535            // Add new collection to map536            <CollectionById<T>>::insert(next_id, new_collection);537538            // call event539            Self::deposit_event(RawEvent::CollectionCreated(next_id, mode.into(), who));540541            Ok(())542        }543544        /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.545        /// 546        /// # Permissions547        /// 548        /// * Collection Owner.549        /// 550        /// # Arguments551        /// 552        /// * collection_id: collection to destroy.553        #[weight = <T as Config>::WeightInfo::destroy_collection()]554        #[transactional]555        pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {556557            let sender = ensure_signed(origin)?;558            let collection = Self::get_collection(collection_id)?;559            Self::check_owner_permissions(&collection, &sender)?;560            if !collection.limits.owner_can_destroy {561                fail!(Error::<T>::NoPermission);562            }563564            <AddressTokens<T>>::remove_prefix(collection_id);565            <Allowances<T>>::remove_prefix(collection_id);566            <Balance<T>>::remove_prefix(collection_id);567            <ItemListIndex>::remove(collection_id);568            <AdminList<T>>::remove(collection_id);569            <CollectionById<T>>::remove(collection_id);570            <WhiteList<T>>::remove_prefix(collection_id);571572            <NftItemList<T>>::remove_prefix(collection_id);573            <FungibleItemList<T>>::remove_prefix(collection_id);574            <ReFungibleItemList<T>>::remove_prefix(collection_id);575576            <NftTransferBasket<T>>::remove_prefix(collection_id);577            <FungibleTransferBasket<T>>::remove_prefix(collection_id);578            <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);579580            <VariableMetaDataBasket<T>>::remove_prefix(collection_id);581582            DestroyedCollectionCount::put(DestroyedCollectionCount::get()583                .checked_add(1)584                .ok_or(Error::<T>::NumOverflow)?);585586            Ok(())587        }588589        /// Add an address to white list.590        /// 591        /// # Permissions592        /// 593        /// * Collection Owner594        /// * Collection Admin595        /// 596        /// # Arguments597        /// 598        /// * collection_id.599        /// 600        /// * address.601        #[weight = <T as Config>::WeightInfo::add_to_white_list()]602        #[transactional]603        pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{604605            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);606            let collection = Self::get_collection(collection_id)?;607608            Self::toggle_white_list_internal(609                &sender,610                &collection,611                &address,612                true,613            )?;614615            Ok(())616        }617618        /// Remove an address from white list.619        /// 620        /// # Permissions621        /// 622        /// * Collection Owner623        /// * Collection Admin624        /// 625        /// # Arguments626        /// 627        /// * collection_id.628        /// 629        /// * address.630        #[weight = <T as Config>::WeightInfo::remove_from_white_list()]631        #[transactional]632        pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{633634            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);635            let collection = Self::get_collection(collection_id)?;636637            Self::toggle_white_list_internal(638                &sender,639                &collection,640                &address,641                false,642            )?;643644            Ok(())645        }646647        /// Toggle between normal and white list access for the methods with access for `Anyone`.648        /// 649        /// # Permissions650        /// 651        /// * Collection Owner.652        /// 653        /// # Arguments654        /// 655        /// * collection_id.656        /// 657        /// * mode: [AccessMode]658        #[weight = <T as Config>::WeightInfo::set_public_access_mode()]659        #[transactional]660        pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult661        {662            let sender = ensure_signed(origin)?;663664            let mut target_collection = Self::get_collection(collection_id)?;665            Self::check_owner_permissions(&target_collection, &sender)?;666            target_collection.access = mode;667            Self::save_collection(target_collection);668669            Ok(())670        }671672        /// Allows Anyone to create tokens if:673        /// * White List is enabled, and674        /// * Address is added to white list, and675        /// * This method was called with True parameter676        /// 677        /// # Permissions678        /// * Collection Owner679        ///680        /// # Arguments681        /// 682        /// * collection_id.683        /// 684        /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.685        #[weight = <T as Config>::WeightInfo::set_mint_permission()]686        #[transactional]687        pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult688        {689            let sender = ensure_signed(origin)?;690691            let mut target_collection = Self::get_collection(collection_id)?;692            Self::check_owner_permissions(&target_collection, &sender)?;693            target_collection.mint_mode = mint_permission;694            Self::save_collection(target_collection);695696            Ok(())697        }698699        /// Change the owner of the collection.700        /// 701        /// # Permissions702        /// 703        /// * Collection Owner.704        /// 705        /// # Arguments706        /// 707        /// * collection_id.708        /// 709        /// * new_owner.710        #[weight = <T as Config>::WeightInfo::change_collection_owner()]711        #[transactional]712        pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {713714            let sender = ensure_signed(origin)?;715            let mut target_collection = Self::get_collection(collection_id)?;716            Self::check_owner_permissions(&target_collection, &sender)?;717            target_collection.owner = new_owner;718            Self::save_collection(target_collection);719720            Ok(())721        }722723        /// Adds an admin of the Collection.724        /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership. 725        /// 726        /// # Permissions727        /// 728        /// * Collection Owner.729        /// * Collection Admin.730        /// 731        /// # Arguments732        /// 733        /// * collection_id: ID of the Collection to add admin for.734        /// 735        /// * new_admin_id: Address of new admin to add.736        #[weight = <T as Config>::WeightInfo::add_collection_admin()]737        #[transactional]738        pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {739            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);740            let collection = Self::get_collection(collection_id)?;741            Self::check_owner_or_admin_permissions(&collection, &sender)?;742            let mut admin_arr = <AdminList<T>>::get(collection_id);743744            match admin_arr.binary_search(&new_admin_id) {745                Ok(_) => {},746                Err(idx) => {747                    let limits = ChainLimit::get();748                    ensure!(admin_arr.len() < limits.collections_admins_limit as usize, Error::<T>::CollectionAdminsLimitExceeded);749                    admin_arr.insert(idx, new_admin_id);750                    <AdminList<T>>::insert(collection_id, admin_arr);751                }752            }753            Ok(())754        }755756        /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.757        ///758        /// # Permissions759        /// 760        /// * Collection Owner.761        /// * Collection Admin.762        /// 763        /// # Arguments764        /// 765        /// * collection_id: ID of the Collection to remove admin for.766        /// 767        /// * account_id: Address of admin to remove.768        #[weight = <T as Config>::WeightInfo::remove_collection_admin()]769        #[transactional]770        pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {771            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);772            let collection = Self::get_collection(collection_id)?;773            Self::check_owner_or_admin_permissions(&collection, &sender)?;774            let mut admin_arr = <AdminList<T>>::get(collection_id);775776            match admin_arr.binary_search(&account_id) {777                Ok(idx) => {778                    admin_arr.remove(idx);779                    <AdminList<T>>::insert(collection_id, admin_arr);780                },781                Err(_) => {}782            }783            Ok(())784        }785786        /// # Permissions787        /// 788        /// * Collection Owner789        /// 790        /// # Arguments791        /// 792        /// * collection_id.793        /// 794        /// * new_sponsor.795        #[weight = <T as Config>::WeightInfo::set_collection_sponsor()]796        #[transactional]797        pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {798            let sender = ensure_signed(origin)?;799            let mut target_collection = Self::get_collection(collection_id)?;800            Self::check_owner_permissions(&target_collection, &sender)?;801802            target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor);803            Self::save_collection(target_collection);804805            Ok(())806        }807808        /// # Permissions809        /// 810        /// * Sponsor.811        /// 812        /// # Arguments813        /// 814        /// * collection_id.815        #[weight = <T as Config>::WeightInfo::confirm_sponsorship()]816        #[transactional]817        pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {818            let sender = ensure_signed(origin)?;819820            let mut target_collection = Self::get_collection(collection_id)?;821            ensure!(822                target_collection.sponsorship.pending_sponsor() == Some(&sender),823                Error::<T>::ConfirmUnsetSponsorFail824            );825826            target_collection.sponsorship = SponsorshipState::Confirmed(sender);827            Self::save_collection(target_collection);828829            Ok(())830        }831832        /// Switch back to pay-per-own-transaction model.833        ///834        /// # Permissions835        ///836        /// * Collection owner.837        /// 838        /// # Arguments839        /// 840        /// * collection_id.841        #[weight = <T as Config>::WeightInfo::remove_collection_sponsor()]842        #[transactional]843        pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {844            let sender = ensure_signed(origin)?;845846            let mut target_collection = Self::get_collection(collection_id)?;847            Self::check_owner_permissions(&target_collection, &sender)?;848849            target_collection.sponsorship = SponsorshipState::Disabled;850            Self::save_collection(target_collection);851852            Ok(())853        }854855        /// This method creates a concrete instance of NFT Collection created with CreateCollection method.856        /// 857        /// # Permissions858        /// 859        /// * Collection Owner.860        /// * Collection Admin.861        /// * Anyone if862        ///     * White List is enabled, and863        ///     * Address is added to white list, and864        ///     * MintPermission is enabled (see SetMintPermission method)865        /// 866        /// # Arguments867        /// 868        /// * collection_id: ID of the collection.869        /// 870        /// * owner: Address, initial owner of the NFT.871        ///872        /// * data: Token data to store on chain.873        // #[weight =874        // (130_000_000 as Weight)875        // .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))876        // .saturating_add(RocksDbWeight::get().reads(10 as Weight))877        // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]878879        #[weight = <T as Config>::WeightInfo::create_item(data.len())]880        #[transactional]881        pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResult {882            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);883            let collection = Self::get_collection(collection_id)?;884885            Self::create_item_internal(&sender, &collection, &owner, data)?;886887            Self::submit_logs(collection)?;888            Ok(())889        }890891        /// This method creates multiple items in a collection created with CreateCollection method.892        /// 893        /// # Permissions894        /// 895        /// * Collection Owner.896        /// * Collection Admin.897        /// * Anyone if898        ///     * White List is enabled, and899        ///     * Address is added to white list, and900        ///     * MintPermission is enabled (see SetMintPermission method)901        /// 902        /// # Arguments903        /// 904        /// * collection_id: ID of the collection.905        /// 906        /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].907        /// 908        /// * owner: Address, initial owner of the NFT.909        #[weight = <T as Config>::WeightInfo::create_item(items_data.into_iter()910                               .map(|data| { data.len() })911                               .sum())]912        #[transactional]913        pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResult {914915            ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);916            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);917            let collection = Self::get_collection(collection_id)?;918919            Self::create_multiple_items_internal(&sender, &collection, &owner, items_data)?;920921            Self::submit_logs(collection)?;922            Ok(())923        }924925        /// Destroys a concrete instance of NFT.926        /// 927        /// # Permissions928        /// 929        /// * Collection Owner.930        /// * Collection Admin.931        /// * Current NFT Owner.932        /// 933        /// # Arguments934        /// 935        /// * collection_id: ID of the collection.936        /// 937        /// * item_id: ID of NFT to burn.938        #[weight = <T as Config>::WeightInfo::burn_item()]939        #[transactional]940        pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {941942            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);943            let target_collection = Self::get_collection(collection_id)?;944945            Self::burn_item_internal(&sender, &target_collection, item_id, value)?;946947            Self::submit_logs(target_collection)?;948            Ok(())949        }950951        /// Change ownership of the token.952        /// 953        /// # Permissions954        /// 955        /// * Collection Owner956        /// * Collection Admin957        /// * Current NFT owner958        ///959        /// # Arguments960        /// 961        /// * recipient: Address of token recipient.962        /// 963        /// * collection_id.964        /// 965        /// * item_id: ID of the item966        ///     * Non-Fungible Mode: Required.967        ///     * Fungible Mode: Ignored.968        ///     * Re-Fungible Mode: Required.969        /// 970        /// * value: Amount to transfer.971        ///     * Non-Fungible Mode: Ignored972        ///     * Fungible Mode: Must specify transferred amount973        ///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)974        #[weight = <T as Config>::WeightInfo::transfer()]975        #[transactional]976        pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {977            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);978            let collection = Self::get_collection(collection_id)?;979980            Self::transfer_internal(&sender, &recipient, &collection, item_id, value)?;981982            Self::submit_logs(collection)?;983            Ok(())984        }985986        /// Set, change, or remove approved address to transfer the ownership of the NFT.987        /// 988        /// # Permissions989        /// 990        /// * Collection Owner991        /// * Collection Admin992        /// * Current NFT owner993        /// 994        /// # Arguments995        /// 996        /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).997        /// 998        /// * collection_id.999        /// 1000        /// * item_id: ID of the item.1001        #[weight = <T as Config>::WeightInfo::approve()]1002        #[transactional]1003        pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {1004            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1005            let collection = Self::get_collection(collection_id)?;10061007            Self::approve_internal(&sender, &spender, &collection, item_id, amount)?;10081009            Self::submit_logs(collection)?;1010            Ok(())1011        }1012        1013        /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.1014        /// 1015        /// # Permissions1016        /// * Collection Owner1017        /// * Collection Admin1018        /// * Current NFT owner1019        /// * Address approved by current NFT owner1020        /// 1021        /// # Arguments1022        /// 1023        /// * from: Address that owns token.1024        /// 1025        /// * recipient: Address of token recipient.1026        /// 1027        /// * collection_id.1028        /// 1029        /// * item_id: ID of the item.1030        /// 1031        /// * value: Amount to transfer.1032        #[weight = <T as Config>::WeightInfo::transfer_from()]1033        #[transactional]1034        pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {1035            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1036            let collection = Self::get_collection(collection_id)?;10371038            Self::transfer_from_internal(&sender, &from, &recipient, &collection, item_id, value)?;10391040            Self::submit_logs(collection)?;1041            Ok(())1042        }1043        // #[weight = 0]1044        //     // let no_perm_mes = "You do not have permissions to modify this collection";1045        //     // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1046        //     // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1047        //     // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);10481049        //     // // on_nft_received  call10501051        //     // Self::transfer(origin, collection_id, item_id, new_owner)?;10521053        //     Ok(())1054        // }10551056        /// Set off-chain data schema.1057        /// 1058        /// # Permissions1059        /// 1060        /// * Collection Owner1061        /// * Collection Admin1062        /// 1063        /// # Arguments1064        /// 1065        /// * collection_id.1066        /// 1067        /// * schema: String representing the offchain data schema.1068        #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1069        #[transactional]1070        pub fn set_variable_meta_data (1071            origin,1072            collection_id: CollectionId,1073            item_id: TokenId,1074            data: Vec<u8>1075        ) -> DispatchResult {1076            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1077            1078            let collection = Self::get_collection(collection_id)?;10791080            Self::set_variable_meta_data_internal(&sender, &collection, item_id, data)?;10811082            Ok(())1083        }1084 1085        /// Set schema standard1086        /// ImageURL1087        /// Unique1088        /// 1089        /// # Permissions1090        /// 1091        /// * Collection Owner1092        /// * Collection Admin1093        /// 1094        /// # Arguments1095        /// 1096        /// * collection_id.1097        /// 1098        /// * schema: SchemaVersion: enum1099        #[weight = <T as Config>::WeightInfo::set_schema_version()]1100        #[transactional]1101        pub fn set_schema_version(1102            origin,1103            collection_id: CollectionId,1104            version: SchemaVersion1105        ) -> DispatchResult {1106            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1107            let mut target_collection = Self::get_collection(collection_id)?;1108            Self::check_owner_or_admin_permissions(&target_collection, &sender)?;1109            target_collection.schema_version = version;1110            Self::save_collection(target_collection);11111112            Ok(())1113        }11141115        /// Set off-chain data schema.1116        /// 1117        /// # Permissions1118        /// 1119        /// * Collection Owner1120        /// * Collection Admin1121        /// 1122        /// # Arguments1123        /// 1124        /// * collection_id.1125        /// 1126        /// * schema: String representing the offchain data schema.1127        #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1128        #[transactional]1129        pub fn set_offchain_schema(1130            origin,1131            collection_id: CollectionId,1132            schema: Vec<u8>1133        ) -> DispatchResult {1134            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1135            let mut target_collection = Self::get_collection(collection_id)?;1136            Self::check_owner_or_admin_permissions(&target_collection, &sender)?;11371138            // check schema limit1139            ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");11401141            target_collection.offchain_schema = schema;1142            Self::save_collection(target_collection);11431144            Ok(())1145        }11461147        /// Set const on-chain data schema.1148        /// 1149        /// # Permissions1150        /// 1151        /// * Collection Owner1152        /// * Collection Admin1153        /// 1154        /// # Arguments1155        /// 1156        /// * collection_id.1157        /// 1158        /// * schema: String representing the const on-chain data schema.1159        #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1160        #[transactional]1161        pub fn set_const_on_chain_schema (1162            origin,1163            collection_id: CollectionId,1164            schema: Vec<u8>1165        ) -> DispatchResult {1166            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1167            let mut target_collection = Self::get_collection(collection_id)?;1168            Self::check_owner_or_admin_permissions(&target_collection, &sender)?;11691170            // check schema limit1171            ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");11721173            target_collection.const_on_chain_schema = schema;1174            Self::save_collection(target_collection);11751176            Ok(())1177        }11781179        /// Set variable on-chain data schema.1180        /// 1181        /// # Permissions1182        /// 1183        /// * Collection Owner1184        /// * Collection Admin1185        /// 1186        /// # Arguments1187        /// 1188        /// * collection_id.1189        /// 1190        /// * schema: String representing the variable on-chain data schema.1191        #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1192        #[transactional]1193        pub fn set_variable_on_chain_schema (1194            origin,1195            collection_id: CollectionId,1196            schema: Vec<u8>1197        ) -> DispatchResult {1198            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1199            let mut target_collection = Self::get_collection(collection_id)?;1200            Self::check_owner_or_admin_permissions(&target_collection, &sender)?;12011202            // check schema limit1203            ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");12041205            target_collection.variable_on_chain_schema = schema;1206            Self::save_collection(target_collection);12071208            Ok(())1209        }12101211        // Sudo permissions function1212        #[weight = <T as Config>::WeightInfo::set_chain_limits()]1213        #[transactional]1214        pub fn set_chain_limits(1215            origin,1216            limits: ChainLimits1217        ) -> DispatchResult {12181219            #[cfg(not(feature = "runtime-benchmarks"))]1220            ensure_root(origin)?;12211222            <ChainLimit>::put(limits);1223            Ok(())1224        }12251226        #[weight = <T as Config>::WeightInfo::set_collection_limits()]1227        #[transactional]1228        pub fn set_collection_limits(1229            origin,1230            collection_id: u32,1231            new_limits: CollectionLimits<T::BlockNumber>,1232        ) -> DispatchResult {1233            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1234            let mut target_collection = Self::get_collection(collection_id)?;1235            Self::check_owner_permissions(&target_collection, &sender.as_sub())?;1236            let old_limits = &target_collection.limits;1237            let chain_limits = ChainLimit::get();12381239            // collection bounds1240            ensure!(new_limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1241                new_limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP && 1242                new_limits.sponsored_data_size <= chain_limits.custom_data_limit,1243                Error::<T>::CollectionLimitBoundsExceeded);12441245            // token_limit   check  prev1246            ensure!(old_limits.token_limit >= new_limits.token_limit, Error::<T>::CollectionTokenLimitExceeded);1247            ensure!(new_limits.token_limit > 0, Error::<T>::CollectionTokenLimitExceeded);12481249            ensure!(1250                (old_limits.owner_can_transfer || !new_limits.owner_can_transfer) &&1251                (old_limits.owner_can_destroy || !new_limits.owner_can_destroy),1252                Error::<T>::OwnerPermissionsCantBeReverted,1253            );12541255            target_collection.limits = new_limits;1256            Self::save_collection(target_collection);12571258            Ok(())1259        } 1260    }1261}12621263impl<T: Config> Module<T> {1264    pub fn create_item_internal(sender: &T::CrossAccountId, collection: &CollectionHandle<T>, owner: &T::CrossAccountId, data: CreateItemData) -> DispatchResult {1265        Self::can_create_items_in_collection(&collection, &sender, &owner, 1)?;1266        Self::validate_create_item_args(&collection, &data)?;1267        Self::create_item_no_validation(&collection, owner, data)?;12681269        Ok(())1270    }12711272    pub fn transfer_internal(sender: &T::CrossAccountId, recipient: &T::CrossAccountId, target_collection: &CollectionHandle<T>, item_id: TokenId, value: u128) -> DispatchResult {1273        target_collection.consume_gas(2000000)?;1274        // Limits check1275        Self::is_correct_transfer(target_collection, &recipient)?;12761277        // Transfer permissions check1278        ensure!(Self::is_item_owner(&sender, target_collection, item_id) ||1279            Self::is_owner_or_admin_permissions(target_collection, &sender),1280            Error::<T>::NoPermission);12811282        if target_collection.access == AccessMode::WhiteList {1283            Self::check_white_list(target_collection, &sender)?;1284            Self::check_white_list(target_collection, &recipient)?;1285        }12861287        match target_collection.mode1288        {1289            CollectionMode::NFT => Self::transfer_nft(target_collection, item_id, sender.clone(), recipient.clone())?,1290            CollectionMode::Fungible(_)  => Self::transfer_fungible(target_collection, value, &sender, &recipient)?,1291            CollectionMode::ReFungible  => Self::transfer_refungible(target_collection, item_id, value, sender.clone(), recipient.clone())?,1292            _ => ()1293        };12941295        Self::deposit_event(RawEvent::Transfer(target_collection.id, item_id, sender.clone(), recipient.clone(), value));12961297        Ok(())1298    }12991300	pub fn approve_internal(1301		sender: &T::CrossAccountId,1302		spender: &T::CrossAccountId,1303		collection: &CollectionHandle<T>,1304		item_id: TokenId,1305		amount: u1281306	) -> DispatchResult {1307        collection.consume_gas(2000000)?;1308		Self::token_exists(&collection, item_id)?;13091310		// Transfer permissions check1311		let bypasses_limits = collection.limits.owner_can_transfer &&1312			Self::is_owner_or_admin_permissions(1313				&collection,1314				&sender,1315			);13161317		let allowance_limit = if bypasses_limits {1318			None1319		} else if let Some(amount) = Self::owned_amount(1320			&sender,1321			&collection,1322			item_id,1323		) {1324			Some(amount)1325		} else {1326			fail!(Error::<T>::NoPermission);1327		};13281329		if collection.access == AccessMode::WhiteList {1330			Self::check_white_list(&collection, &sender)?;1331			Self::check_white_list(&collection, &spender)?;1332		}13331334		let allowance: u128 = amount1335			.checked_add(<Allowances<T>>::get(collection.id, (item_id, sender.as_sub(), spender.as_sub())))1336			.ok_or(Error::<T>::NumOverflow)?;1337		if let Some(limit) = allowance_limit {1338			ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);1339		}1340		<Allowances<T>>::insert(collection.id, (item_id, sender.as_sub(), spender.as_sub()), allowance);13411342		if matches!(collection.mode, CollectionMode::NFT) {1343			// TODO: NFT: only one owner may exist for token in ERC7211344			collection.log(ERC721Events::Approval {1345                owner: *sender.as_eth(),1346                approved: *spender.as_eth(),1347                token_id: item_id.into(),1348            });1349		}13501351		if matches!(collection.mode, CollectionMode::Fungible(_)) {1352			// TODO: NFT: only one owner may exist for token in ERC201353			collection.log(ERC20Events::Approval {1354                owner: *sender.as_eth(),1355                spender: *spender.as_eth(),1356                value: allowance.into()1357            });1358		}13591360		Self::deposit_event(RawEvent::Approved(collection.id, item_id, sender.clone(), spender.clone(), allowance));1361		Ok(())1362	}13631364	pub fn transfer_from_internal(1365		sender: &T::CrossAccountId,1366		from: &T::CrossAccountId,1367		recipient: &T::CrossAccountId,1368		collection: &CollectionHandle<T>,1369		item_id: TokenId,1370		amount: u128,1371	) -> DispatchResult {1372        collection.consume_gas(2000000)?;1373		// Check approval1374		let approval: u128 = <Allowances<T>>::get(collection.id, (item_id, from.as_sub(), sender.as_sub()));13751376		// Limits check1377		Self::is_correct_transfer(&collection, &recipient)?;13781379		// Transfer permissions check1380		ensure!(1381			approval >= amount || 1382			(1383				collection.limits.owner_can_transfer &&1384				Self::is_owner_or_admin_permissions(&collection, &sender)1385			),1386			Error::<T>::NoPermission1387		);13881389		if collection.access == AccessMode::WhiteList {1390			Self::check_white_list(&collection, &sender)?;1391			Self::check_white_list(&collection, &recipient)?;1392		}13931394		// Reduce approval by transferred amount or remove if remaining approval drops to 01395		let allowance = approval.saturating_sub(amount);1396		if allowance > 0 {1397			<Allowances<T>>::insert(collection.id, (item_id, from.as_sub(), sender.as_sub()), allowance);1398		} else {1399			<Allowances<T>>::remove(collection.id, (item_id, from.as_sub(), sender.as_sub()));1400		}14011402		match collection.mode {1403			CollectionMode::NFT => {1404				Self::transfer_nft(&collection, item_id, from.clone(), recipient.clone())?1405			}1406			CollectionMode::Fungible(_) => {1407				Self::transfer_fungible(&collection, amount, &from, &recipient)?1408			}1409			CollectionMode::ReFungible => {1410				Self::transfer_refungible(&collection, item_id, amount, from.clone(), recipient.clone())?1411			}1412			_ => ()1413		};14141415		if matches!(collection.mode, CollectionMode::Fungible(_)) {1416			collection.log(ERC20Events::Approval {1417                owner: *from.as_eth(),1418                spender: *sender.as_eth(),1419                value: allowance.into()1420            });1421		}14221423		Ok(())1424	}14251426    pub fn set_variable_meta_data_internal(1427        sender: &T::CrossAccountId,1428        collection: &CollectionHandle<T>, 1429        item_id: TokenId,1430        data: Vec<u8>,1431    ) -> DispatchResult {1432        Self::token_exists(&collection, item_id)?;14331434        ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);14351436        // Modify permissions check1437        ensure!(Self::is_item_owner(&sender, &collection, item_id) ||1438            Self::is_owner_or_admin_permissions(&collection, &sender),1439            Error::<T>::NoPermission);14401441        match collection.mode1442        {1443            CollectionMode::NFT => Self::set_nft_variable_data(&collection, item_id, data)?,1444            CollectionMode::ReFungible  => Self::set_re_fungible_variable_data(&collection, item_id, data)?,1445            CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1446            _ => fail!(Error::<T>::UnexpectedCollectionType)1447        };14481449        Ok(())1450    }14511452    pub fn create_multiple_items_internal(1453        sender: &T::CrossAccountId,1454        collection: &CollectionHandle<T>,1455        owner: &T::CrossAccountId,1456        items_data: Vec<CreateItemData>,1457    ) -> DispatchResult {1458        Self::can_create_items_in_collection(&collection, &sender, &owner, items_data.len() as u32)?;14591460        for data in &items_data {1461            Self::validate_create_item_args(&collection, data)?;1462        }1463        for data in &items_data {1464            Self::create_item_no_validation(&collection, owner, data.clone())?;1465        }14661467        Ok(())1468    }14691470    pub fn burn_item_internal(1471        sender: &T::CrossAccountId,1472        collection: &CollectionHandle<T>,1473        item_id: TokenId,1474        value: u128,1475    ) -> DispatchResult {1476        ensure!(1477            Self::is_item_owner(&sender, &collection, item_id) ||1478            (1479                collection.limits.owner_can_transfer &&1480                Self::is_owner_or_admin_permissions(&collection, &sender)1481            ),1482            Error::<T>::NoPermission1483        );14841485        if collection.access == AccessMode::WhiteList {1486            Self::check_white_list(&collection, &sender)?;1487        }14881489        match collection.mode1490        {1491            CollectionMode::NFT => Self::burn_nft_item(&collection, item_id)?,1492            CollectionMode::Fungible(_)  => Self::burn_fungible_item(&sender, &collection, value)?,1493            CollectionMode::ReFungible  => Self::burn_refungible_item(&collection, item_id, &sender)?,1494            _ => ()1495        };14961497        Ok(())1498    }14991500    pub fn toggle_white_list_internal(1501        sender: &T::CrossAccountId,1502        collection: &CollectionHandle<T>,1503        address: &T::CrossAccountId,1504        whitelisted: bool,1505    ) -> DispatchResult {1506        Self::check_owner_or_admin_permissions(&collection, &sender)?;15071508        if whitelisted {1509            <WhiteList<T>>::insert(collection.id, address.as_sub(), true);1510        } else {1511            <WhiteList<T>>::remove(collection.id, address.as_sub());1512        }15131514        Ok(())1515    }15161517    fn is_correct_transfer(collection: &CollectionHandle<T>, recipient: &T::CrossAccountId) -> DispatchResult {1518        let collection_id = collection.id;15191520        // check token limit and account token limit1521        let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient.as_sub()).len() as u32;1522        ensure!(collection.limits.account_token_ownership_limit > account_items,  Error::<T>::AccountTokenLimitExceeded);1523        1524        Ok(())1525    }15261527    fn can_create_items_in_collection(collection: &CollectionHandle<T>, sender: &T::CrossAccountId, owner: &T::CrossAccountId, amount: u32) -> DispatchResult {1528        let collection_id = collection.id;15291530        // check token limit and account token limit1531        let total_items: u32 = ItemListIndex::get(collection_id)1532            .checked_add(amount)1533            .ok_or(Error::<T>::CollectionTokenLimitExceeded)?;1534        let account_items: u32 = (<AddressTokens<T>>::get(collection_id, owner.as_sub()).len() as u32)1535            .checked_add(amount)1536            .ok_or(Error::<T>::AccountTokenLimitExceeded)?;1537        ensure!(collection.limits.token_limit >= total_items,  Error::<T>::CollectionTokenLimitExceeded);1538        ensure!(collection.limits.account_token_ownership_limit >= account_items,  Error::<T>::AccountTokenLimitExceeded);15391540        if !Self::is_owner_or_admin_permissions(collection, &sender) {1541            ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1542            Self::check_white_list(collection, owner)?;1543            Self::check_white_list(collection, sender)?;1544        }15451546        Ok(())1547    }15481549    fn validate_create_item_args(target_collection: &CollectionHandle<T>, data: &CreateItemData) -> DispatchResult {1550        match target_collection.mode1551        {1552            CollectionMode::NFT => {1553                if let CreateItemData::NFT(data) = data {1554                    // check sizes1555                    ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1556                    ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1557                } else {1558                    fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1559                }1560            },1561            CollectionMode::Fungible(_) => {1562                if let CreateItemData::Fungible(_) = data {1563                } else {1564                    fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1565                }1566            },1567            CollectionMode::ReFungible => {1568                if let CreateItemData::ReFungible(data) = data {15691570                    // check sizes1571                    ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1572                    ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);15731574                    // Check refungibility limits1575                    ensure!(data.pieces <= MAX_REFUNGIBLE_PIECES, Error::<T>::WrongRefungiblePieces);1576                    ensure!(data.pieces > 0, Error::<T>::WrongRefungiblePieces);1577                } else {1578                    fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1579                }1580            },1581            _ => { fail!(Error::<T>::UnexpectedCollectionType); }1582        };15831584        Ok(())1585    }15861587    fn create_item_no_validation(collection: &CollectionHandle<T>, owner: &T::CrossAccountId, data: CreateItemData) -> DispatchResult {1588        match data1589        {1590            CreateItemData::NFT(data) => {1591                let item = NftItemType {1592                    owner: owner.clone(),1593                    const_data: data.const_data,1594                    variable_data: data.variable_data1595                };15961597                Self::add_nft_item(collection, item)?;1598            },1599            CreateItemData::Fungible(data) => {1600                Self::add_fungible_item(collection, &owner, data.value)?;1601            },1602            CreateItemData::ReFungible(data) => {1603                let mut owner_list = Vec::new();1604                owner_list.push(Ownership {owner: owner.clone(), fraction: data.pieces});16051606                let item = ReFungibleItemType {1607                    owner: owner_list,1608                    const_data: data.const_data,1609                    variable_data: data.variable_data1610                };16111612                Self::add_refungible_item(collection, item)?;1613            }1614        };16151616        Ok(())1617    }16181619    fn add_fungible_item(collection: &CollectionHandle<T>, owner: &T::CrossAccountId, value: u128) -> DispatchResult {1620        let collection_id = collection.id;16211622        // Does new owner already have an account?1623        let balance: u128 = <FungibleItemList<T>>::get(collection_id, owner.as_sub()).value;16241625        // Mint 1626        let item = FungibleItemType {1627            value: balance.checked_add(value).ok_or(Error::<T>::NumOverflow)?,1628        };1629        <FungibleItemList<T>>::insert(collection_id, owner.as_sub(), item);16301631        // Update balance1632        let new_balance = <Balance<T>>::get(collection_id, owner.as_sub())1633            .checked_add(value)1634            .ok_or(Error::<T>::NumOverflow)?;1635        <Balance<T>>::insert(collection_id, owner.as_sub(), new_balance);16361637        Self::deposit_event(RawEvent::ItemCreated(collection_id, 0, owner.clone()));1638        Ok(())1639    }16401641    fn add_refungible_item(collection: &CollectionHandle<T>, item: ReFungibleItemType<T::CrossAccountId>) -> DispatchResult {1642        let collection_id = collection.id;16431644        let current_index = <ItemListIndex>::get(collection_id)1645            .checked_add(1)1646            .ok_or(Error::<T>::NumOverflow)?;1647        let itemcopy = item.clone();16481649        ensure!(1650            item.owner.len() == 1,1651            Error::<T>::BadCreateRefungibleCall,1652        );1653        let item_owner = item.owner.first().expect("only one owner is defined");16541655        let value = item_owner.fraction;1656        let owner = item_owner.owner.clone();16571658        Self::add_token_index(collection_id, current_index, &owner)?;16591660        <ItemListIndex>::insert(collection_id, current_index);1661        <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16621663        // Update balance1664        let new_balance = <Balance<T>>::get(collection_id, owner.as_sub())1665            .checked_add(value)1666            .ok_or(Error::<T>::NumOverflow)?;1667        <Balance<T>>::insert(collection_id, owner.as_sub(), new_balance);16681669        Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index, owner));1670        Ok(())1671    }16721673    fn add_nft_item(collection: &CollectionHandle<T>, item: NftItemType<T::CrossAccountId>) -> DispatchResult {1674        let collection_id = collection.id;16751676        let current_index = <ItemListIndex>::get(collection_id)1677            .checked_add(1)1678            .ok_or(Error::<T>::NumOverflow)?;16791680        let item_owner = item.owner.clone();1681        Self::add_token_index(collection_id, current_index, &item.owner)?;16821683        <ItemListIndex>::insert(collection_id, current_index);1684        <NftItemList<T>>::insert(collection_id, current_index, item);16851686        // Update balance1687        let new_balance = <Balance<T>>::get(collection_id, item_owner.as_sub())1688            .checked_add(1)1689            .ok_or(Error::<T>::NumOverflow)?;1690        <Balance<T>>::insert(collection_id, item_owner.as_sub(), new_balance);16911692        collection.log(ERC721Events::Transfer {1693            from: H160::default(),1694            to: *item_owner.as_eth(),1695            token_id: current_index.into(),1696        });1697        Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index, item_owner));1698        Ok(())1699    }17001701    fn burn_refungible_item(1702        collection: &CollectionHandle<T>,1703        item_id: TokenId,1704        owner: &T::CrossAccountId,1705    ) -> DispatchResult {1706        let collection_id = collection.id;17071708        let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id)1709            .ok_or(Error::<T>::TokenNotFound)?;1710        let rft_balance = token1711            .owner1712            .iter()1713            .find(|&i| i.owner == *owner)1714            .ok_or(Error::<T>::TokenNotFound)?;1715        Self::remove_token_index(collection_id, item_id, owner)?;17161717        // update balance1718        let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.as_sub())1719            .checked_sub(rft_balance.fraction)1720            .ok_or(Error::<T>::NumOverflow)?;1721        <Balance<T>>::insert(collection_id, rft_balance.owner.as_sub(), new_balance);17221723        // Re-create owners list with sender removed1724        let index = token1725            .owner1726            .iter()1727            .position(|i| i.owner == *owner)1728            .expect("owned item is exists");1729        token.owner.remove(index);1730        let owner_count = token.owner.len();17311732        // Burn the token completely if this was the last (only) owner1733        if owner_count == 0 {1734            <ReFungibleItemList<T>>::remove(collection_id, item_id);1735            <VariableMetaDataBasket<T>>::remove(collection_id, item_id);1736        }1737        else {1738            <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1739        }17401741        Ok(())1742    }17431744    fn burn_nft_item(collection: &CollectionHandle<T>, item_id: TokenId) -> DispatchResult {1745        let collection_id = collection.id;17461747        let item = <NftItemList<T>>::get(collection_id, item_id)1748            .ok_or(Error::<T>::TokenNotFound)?;1749        Self::remove_token_index(collection_id, item_id, &item.owner)?;17501751        // update balance1752        let new_balance = <Balance<T>>::get(collection_id, item.owner.as_sub())1753            .checked_sub(1)1754            .ok_or(Error::<T>::NumOverflow)?;1755        <Balance<T>>::insert(collection_id, item.owner.as_sub(), new_balance);1756        <NftItemList<T>>::remove(collection_id, item_id);1757        <VariableMetaDataBasket<T>>::remove(collection_id, item_id);17581759        Self::deposit_event(RawEvent::ItemDestroyed(collection.id, item_id));1760        Ok(())1761    }17621763    fn burn_fungible_item(owner: &T::CrossAccountId, collection: &CollectionHandle<T>, value: u128) -> DispatchResult {1764        let collection_id = collection.id;17651766        let mut balance = <FungibleItemList<T>>::get(collection_id, owner.as_sub());1767        ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);17681769        // update balance1770        let new_balance = <Balance<T>>::get(collection_id, owner.as_sub())1771            .checked_sub(value)1772            .ok_or(Error::<T>::NumOverflow)?;1773        <Balance<T>>::insert(collection_id, owner.as_sub(), new_balance);17741775        if balance.value - value > 0 {1776            balance.value -= value;1777            <FungibleItemList<T>>::insert(collection_id, owner.as_sub(), balance);1778        }1779        else {1780            <FungibleItemList<T>>::remove(collection_id, owner.as_sub());1781        }17821783        collection.log(ERC20Events::Transfer {1784            from: *owner.as_eth(),1785            to: H160::default(),1786            value: value.into(),1787        });1788        Ok(())1789    }17901791    pub fn get_collection(collection_id: CollectionId) -> Result<CollectionHandle<T>, sp_runtime::DispatchError> {1792        Ok(<CollectionHandle<T>>::get(collection_id)1793            .ok_or(Error::<T>::CollectionNotFound)?)1794    }17951796    fn save_collection(collection: CollectionHandle<T>) {1797        <CollectionById<T>>::insert(collection.id, collection.into_inner());1798    }17991800    pub fn submit_logs(collection: CollectionHandle<T>) -> DispatchResult {1801        if collection.logs.is_empty() {1802            return Ok(())1803        }1804        T::EthereumTransactionSender::submit_logs_transaction(1805            eth::generate_transaction(collection.id, T::EthereumChainId::get()),1806            collection.logs.retrieve_logs(),1807        )1808    }18091810    fn check_owner_permissions(target_collection: &CollectionHandle<T>, subject: &T::AccountId) -> DispatchResult {1811        ensure!(1812            *subject == target_collection.owner,1813            Error::<T>::NoPermission1814        );18151816        Ok(())1817    }18181819    fn is_owner_or_admin_permissions(collection: &CollectionHandle<T>, subject: &T::CrossAccountId) -> bool {1820        *subject.as_sub() == collection.owner || <AdminList<T>>::get(collection.id).contains(&subject)1821    }18221823    fn check_owner_or_admin_permissions(1824        collection: &CollectionHandle<T>,1825        subject: &T::CrossAccountId,1826    ) -> DispatchResult {1827        ensure!(Self::is_owner_or_admin_permissions(collection, subject), Error::<T>::NoPermission);18281829        Ok(())1830    }18311832    fn owned_amount(1833        subject: &T::CrossAccountId,1834        target_collection: &CollectionHandle<T>,1835        item_id: TokenId,1836    ) -> Option<u128> {1837        let collection_id = target_collection.id;18381839        match target_collection.mode {1840            CollectionMode::NFT => (<NftItemList<T>>::get(collection_id, item_id)?.owner == *subject)1841                .then(|| 1),1842            CollectionMode::Fungible(_) => Some(<FungibleItemList<T>>::get(collection_id, &subject.as_sub())1843                .value),1844            CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection_id, item_id)?1845                .owner1846                .iter()1847                .find(|i| i.owner == *subject)1848                .map(|i| i.fraction),1849            CollectionMode::Invalid => None,1850        }1851    }18521853    fn is_item_owner(subject: &T::CrossAccountId, target_collection: &CollectionHandle<T>, item_id: TokenId) -> bool {1854        match target_collection.mode {1855            CollectionMode::Fungible(_) => true,1856            _ => Self::owned_amount(&subject, target_collection, item_id).is_some(),1857        }1858    }18591860    fn check_white_list(collection: &CollectionHandle<T>, address: &T::CrossAccountId) -> DispatchResult {1861        let collection_id = collection.id;18621863        let mes = Error::<T>::AddresNotInWhiteList;1864        ensure!(<WhiteList<T>>::contains_key(collection_id, address.as_sub()), mes);18651866        Ok(())1867    }18681869    /// Check if token exists. In case of Fungible, check if there is an entry for 1870    /// the owner in fungible balances double map1871    fn token_exists(1872        target_collection: &CollectionHandle<T>,1873        item_id: TokenId,1874    ) -> DispatchResult {1875        let collection_id = target_collection.id;1876        let exists = match target_collection.mode1877        {1878            CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),1879            CollectionMode::Fungible(_)  => true,1880            CollectionMode::ReFungible  => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1881            _ => false1882        };18831884        ensure!(exists == true, Error::<T>::TokenNotFound);1885        Ok(())1886    }18871888    fn transfer_fungible(1889        collection: &CollectionHandle<T>,1890        value: u128,1891        owner: &T::CrossAccountId,1892        recipient: &T::CrossAccountId,1893    ) -> DispatchResult {1894        let collection_id = collection.id;18951896        let mut balance = <FungibleItemList<T>>::get(collection_id, owner.as_sub());1897        ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);18981899        // Send balance to recipient (updates balanceOf of recipient)1900        Self::add_fungible_item(collection, recipient, value)?;19011902        // update balanceOf of sender1903        <Balance<T>>::insert(collection_id, owner.as_sub(), balance.value - value);19041905        // Reduce or remove sender1906        if balance.value == value {1907            <FungibleItemList<T>>::remove(collection_id, owner.as_sub());1908        }1909        else {1910            balance.value -= value;1911            <FungibleItemList<T>>::insert(collection_id, owner.as_sub(), balance);1912        }19131914        collection.log(ERC20Events::Transfer {1915            from: *owner.as_eth(),1916            to: *recipient.as_eth(),1917            value: value.into(),1918        });1919        Self::deposit_event(RawEvent::Transfer(collection.id, 1, owner.clone(), recipient.clone(), value));19201921        Ok(())1922    }19231924    fn transfer_refungible(1925        collection: &CollectionHandle<T>,1926        item_id: TokenId,1927        value: u128,1928        owner: T::CrossAccountId,1929        new_owner: T::CrossAccountId,1930    ) -> DispatchResult {1931        let collection_id = collection.id;1932        let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id)1933            .ok_or(Error::<T>::TokenNotFound)?;19341935        let item = full_item1936            .owner1937            .iter()1938            .filter(|i| i.owner == owner)1939            .next()1940            .ok_or(Error::<T>::TokenNotFound)?;1941        let amount = item.fraction;19421943        ensure!(amount >= value, Error::<T>::TokenValueTooLow);19441945        // update balance1946        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.as_sub())1947            .checked_sub(value)1948            .ok_or(Error::<T>::NumOverflow)?;1949        <Balance<T>>::insert(collection_id, item.owner.as_sub(), balance_old_owner);19501951        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.as_sub())1952            .checked_add(value)1953            .ok_or(Error::<T>::NumOverflow)?;1954        <Balance<T>>::insert(collection_id, new_owner.as_sub(), balance_new_owner);19551956        let old_owner = item.owner.clone();1957        let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19581959        // transfer1960        if amount == value && !new_owner_has_account {1961            // change owner1962            // new owner do not have account1963            let mut new_full_item = full_item.clone();1964            new_full_item1965                .owner1966                .iter_mut()1967                .find(|i| i.owner == owner)1968                .expect("old owner does present in refungible")1969                .owner = new_owner.clone();1970            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19711972            // update index collection1973            Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;1974        } else {1975            let mut new_full_item = full_item.clone();1976            new_full_item1977                .owner1978                .iter_mut()1979                .find(|i| i.owner == owner)1980                .expect("old owner does present in refungible")1981                .fraction -= value;19821983            // separate amount1984            if new_owner_has_account {1985                // new owner has account1986                new_full_item1987                    .owner1988                    .iter_mut()1989                    .find(|i| i.owner == new_owner)1990                    .expect("new owner has account")1991                    .fraction += value;1992            } else {1993                // new owner do not have account1994                new_full_item.owner.push(Ownership {1995                    owner: new_owner.clone(),1996                    fraction: value,1997                });1998                Self::add_token_index(collection_id, item_id, &new_owner)?;1999            }20002001            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2002        }20032004        Self::deposit_event(RawEvent::Transfer(collection.id, item_id, owner, new_owner, amount));20052006        Ok(())2007    }20082009    fn transfer_nft(2010        collection: &CollectionHandle<T>,2011        item_id: TokenId,2012        sender: T::CrossAccountId,2013        new_owner: T::CrossAccountId,2014    ) -> DispatchResult {2015        let collection_id = collection.id;2016        let mut item = <NftItemList<T>>::get(collection_id, item_id)2017            .ok_or(Error::<T>::TokenNotFound)?;20182019        ensure!(2020            sender == item.owner,2021            Error::<T>::MustBeTokenOwner2022        );20232024        // update balance2025        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.as_sub())2026            .checked_sub(1)2027            .ok_or(Error::<T>::NumOverflow)?;2028        <Balance<T>>::insert(collection_id, item.owner.as_sub(), balance_old_owner);20292030        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.as_sub())2031            .checked_add(1)2032            .ok_or(Error::<T>::NumOverflow)?;2033        <Balance<T>>::insert(collection_id, new_owner.as_sub(), balance_new_owner);20342035        // change owner2036        let old_owner = item.owner.clone();2037        item.owner = new_owner.clone();2038        <NftItemList<T>>::insert(collection_id, item_id, item);20392040        // update index collection2041        Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;20422043        collection.log(ERC721Events::Transfer {2044            from: *sender.as_eth(),2045            to: *new_owner.as_eth(),2046            token_id: item_id.into(),2047        });2048        Self::deposit_event(RawEvent::Transfer(collection.id, item_id, sender, new_owner, 1));20492050        Ok(())2051    }2052    2053    fn set_re_fungible_variable_data(2054        collection: &CollectionHandle<T>,2055        item_id: TokenId,2056        data: Vec<u8>2057    ) -> DispatchResult {2058        let collection_id = collection.id;2059        let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id)2060            .ok_or(Error::<T>::TokenNotFound)?;20612062        item.variable_data = data;20632064        <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20652066        Ok(())2067    }20682069    fn set_nft_variable_data(2070        collection: &CollectionHandle<T>,2071        item_id: TokenId,2072        data: Vec<u8>2073    ) -> DispatchResult {2074        let collection_id = collection.id;2075        let mut item = <NftItemList<T>>::get(collection_id, item_id)2076            .ok_or(Error::<T>::TokenNotFound)?;2077        2078        item.variable_data = data;20792080        <NftItemList<T>>::insert(collection_id, item_id, item);2081        2082        Ok(())2083    }20842085    #[allow(dead_code)]2086    fn init_collection(item: &Collection<T>) {2087        // check params2088        assert!(2089            item.decimal_points <= MAX_DECIMAL_POINTS,2090            "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2091        );2092        assert!(2093            item.name.len() <= 64,2094            "Collection name can not be longer than 63 char"2095        );2096        assert!(2097            item.name.len() <= 256,2098            "Collection description can not be longer than 255 char"2099        );2100        assert!(2101            item.token_prefix.len() <= 16,2102            "Token prefix can not be longer than 15 char"2103        );21042105        // Generate next collection ID2106        let next_id = CreatedCollectionCount::get()2107            .checked_add(1)2108            .unwrap();21092110        CreatedCollectionCount::put(next_id);2111    }21122113    #[allow(dead_code)]2114    fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::CrossAccountId>) {2115        let current_index = <ItemListIndex>::get(collection_id)2116            .checked_add(1)2117            .unwrap();21182119        Self::add_token_index(collection_id, current_index, &item.owner).unwrap();21202121        <ItemListIndex>::insert(collection_id, current_index);21222123        // Update balance2124        let new_balance = <Balance<T>>::get(collection_id, item.owner.as_sub())2125            .checked_add(1)2126            .unwrap();2127        <Balance<T>>::insert(collection_id, item.owner.as_sub(), new_balance);2128    }21292130    #[allow(dead_code)]2131    fn init_fungible_token(collection_id: CollectionId, owner: &T::CrossAccountId, item: &FungibleItemType) {2132        let current_index = <ItemListIndex>::get(collection_id)2133            .checked_add(1)2134            .unwrap();21352136        Self::add_token_index(collection_id, current_index, owner).unwrap();21372138        <ItemListIndex>::insert(collection_id, current_index);21392140        // Update balance2141        let new_balance = <Balance<T>>::get(collection_id, owner.as_sub())2142            .checked_add(item.value)2143            .unwrap();2144        <Balance<T>>::insert(collection_id, owner.as_sub(), new_balance);2145    }21462147    #[allow(dead_code)]2148    fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::CrossAccountId>) {2149        let current_index = <ItemListIndex>::get(collection_id)2150            .checked_add(1)2151            .unwrap();21522153        let value = item.owner.first().unwrap().fraction;2154        let owner = item.owner.first().unwrap().owner.clone();21552156        Self::add_token_index(collection_id, current_index, &owner).unwrap();21572158        <ItemListIndex>::insert(collection_id, current_index);21592160        // Update balance2161        let new_balance = <Balance<T>>::get(collection_id, &owner.as_sub())2162            .checked_add(value)2163            .unwrap();2164        <Balance<T>>::insert(collection_id, owner.as_sub(), new_balance);2165    }21662167    fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::CrossAccountId) -> DispatchResult {2168        // add to account limit2169        if <AccountItemCount<T>>::contains_key(owner.as_sub()) {21702171            // bound Owned tokens by a single address2172            let count = <AccountItemCount<T>>::get(owner.as_sub());2173            ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21742175            <AccountItemCount<T>>::insert(owner.as_sub(), count2176                .checked_add(1)2177                .ok_or(Error::<T>::NumOverflow)?);2178        }2179        else {2180            <AccountItemCount<T>>::insert(owner.as_sub(), 1);2181        }21822183        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.as_sub());2184        if list_exists {2185            let mut list = <AddressTokens<T>>::get(collection_id, owner.as_sub());2186            let item_contains = list.contains(&item_index.clone());21872188            if !item_contains {2189                list.push(item_index.clone());2190            }21912192            <AddressTokens<T>>::insert(collection_id, owner.as_sub(), list);2193        } else {2194            let mut itm = Vec::new();2195            itm.push(item_index.clone());2196            <AddressTokens<T>>::insert(collection_id, owner.as_sub(), itm);2197        }21982199        Ok(())2200    }22012202    fn remove_token_index(2203        collection_id: CollectionId,2204        item_index: TokenId,2205        owner: &T::CrossAccountId,2206    ) -> DispatchResult {22072208        // update counter2209        <AccountItemCount<T>>::insert(owner.as_sub(), 2210            <AccountItemCount<T>>::get(owner.as_sub())2211            .checked_sub(1)2212            .ok_or(Error::<T>::NumOverflow)?);221322142215        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.as_sub());2216        if list_exists {2217            let mut list = <AddressTokens<T>>::get(collection_id, owner.as_sub());2218            let item_contains = list.contains(&item_index.clone());22192220            if item_contains {2221                list.retain(|&item| item != item_index);2222                <AddressTokens<T>>::insert(collection_id, owner.as_sub(), list);2223            }2224        }22252226        Ok(())2227    }22282229    fn move_token_index(2230        collection_id: CollectionId,2231        item_index: TokenId,2232        old_owner: &T::CrossAccountId,2233        new_owner: &T::CrossAccountId,2234    ) -> DispatchResult {2235        Self::remove_token_index(collection_id, item_index, old_owner)?;2236        Self::add_token_index(collection_id, item_index, new_owner)?;22372238        Ok(())2239    }2240}22412242sp_api::decl_runtime_apis! {2243    pub trait NftApi {2244        /// Used for ethereum integration2245        fn eth_contract_code(account: H160) -> Option<Vec<u8>>;2246    }2247}
after · pallets/nft/src/lib.rs
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56#![recursion_limit = "1024"]78#![cfg_attr(not(feature = "std"), no_std)]910extern crate alloc;1112pub use serde::{Serialize, Deserialize};1314pub use frame_support::{15    construct_runtime, decl_event, decl_module, decl_storage, decl_error,16    dispatch::DispatchResult,17    ensure, fail, parameter_types,18    traits::{19        Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,20        Randomness, IsSubType, WithdrawReasons,21    },22    weights::{23        constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},24        DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,25        WeightToFeePolynomial, DispatchClass,26    },27    StorageValue,28    transactional,29};3031use frame_system::{self as system, ensure_signed, ensure_root};32use sp_core::H160;33use sp_runtime::sp_std::prelude::Vec;34use core::ops::{Deref, DerefMut};35use core::cell::RefCell;36use nft_data_structs::{37    MAX_DECIMAL_POINTS, MAX_SPONSOR_TIMEOUT, MAX_TOKEN_OWNERSHIP, MAX_REFUNGIBLE_PIECES,38	AccessMode, ChainLimits, Collection, CreateItemData, CollectionLimits,39    CollectionId, CollectionMode, TokenId, 40    SchemaVersion, SponsorshipState, Ownership,41    NftItemType, FungibleItemType, ReFungibleItemType42};43use pallet_ethereum::EthereumTransactionSender;4445#[cfg(test)]46mod mock;4748#[cfg(test)]49mod tests;5051mod default_weights;52mod eth;53mod sponsorship;54pub use sponsorship::NftSponsorshipHandler;5556pub use eth::NftErcSupport;57pub use eth::account::*;58use eth::erc::{ERC20Events, ERC721Events};5960#[cfg(feature = "runtime-benchmarks")]61mod benchmarking;6263pub trait WeightInfo {64	fn create_collection() -> Weight;65	fn destroy_collection() -> Weight;66	fn add_to_white_list() -> Weight;67	fn remove_from_white_list() -> Weight;68    fn set_public_access_mode() -> Weight;69    fn set_mint_permission() -> Weight;70    fn change_collection_owner() -> Weight;71    fn add_collection_admin() -> Weight;72    fn remove_collection_admin() -> Weight;73    fn set_collection_sponsor() -> Weight;74    fn confirm_sponsorship() -> Weight;75    fn remove_collection_sponsor() -> Weight;76    fn create_item(s: usize) -> Weight;77    fn burn_item() -> Weight;78    fn transfer() -> Weight;79    fn approve() -> Weight;80    fn transfer_from() -> Weight;81    fn set_offchain_schema() -> Weight;82    fn set_const_on_chain_schema() -> Weight;83    fn set_variable_on_chain_schema() -> Weight;84    fn set_variable_meta_data() -> Weight;85    fn enable_contract_sponsoring() -> Weight;86    fn set_schema_version() -> Weight;87    fn set_chain_limits() -> Weight;88    fn set_contract_sponsoring_rate_limit() -> Weight;89    fn set_variable_meta_data_sponsoring_rate_limit() -> Weight;90    fn toggle_contract_white_list() -> Weight;91    fn add_to_contract_white_list() -> Weight;92    fn remove_from_contract_white_list() -> Weight;93    fn set_collection_limits() -> Weight;94}9596decl_error! {97	/// Error for non-fungible-token module.98	pub enum Error for Module<T: Config> {99        /// Total collections bound exceeded.100        TotalCollectionsLimitExceeded,101		/// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.102        CollectionDecimalPointLimitExceeded, 103        /// Collection name can not be longer than 63 char.104        CollectionNameLimitExceeded, 105        /// Collection description can not be longer than 255 char.106        CollectionDescriptionLimitExceeded, 107        /// Token prefix can not be longer than 15 char.108        CollectionTokenPrefixLimitExceeded,109        /// This collection does not exist.110        CollectionNotFound,111        /// Item not exists.112        TokenNotFound,113        /// Admin not found114        AdminNotFound,115        /// Arithmetic calculation overflow.116        NumOverflow,       117        /// Account already has admin role.118        AlreadyAdmin,  119        /// You do not own this collection.120        NoPermission,121        /// This address is not set as sponsor, use setCollectionSponsor first.122        ConfirmUnsetSponsorFail,123        /// Collection is not in mint mode.124        PublicMintingNotAllowed,125        /// Sender parameter and item owner must be equal.126        MustBeTokenOwner,127        /// Item balance not enough.128        TokenValueTooLow,129        /// Size of item is too large.130        NftSizeLimitExceeded,131        /// No approve found132        ApproveNotFound,133        /// Requested value more than approved.134        TokenValueNotEnough,135        /// Only approved addresses can call this method.136        ApproveRequired,137        /// Address is not in white list.138        AddresNotInWhiteList,139        /// Number of collection admins bound exceeded.140        CollectionAdminsLimitExceeded,141        /// Owned tokens by a single address bound exceeded.142        AddressOwnershipLimitExceeded,143        /// Length of items properties must be greater than 0.144        EmptyArgument,145        /// const_data exceeded data limit.146        TokenConstDataLimitExceeded,147        /// variable_data exceeded data limit.148        TokenVariableDataLimitExceeded,149        /// Not NFT item data used to mint in NFT collection.150        NotNftDataUsedToMintNftCollectionToken,151        /// Not Fungible item data used to mint in Fungible collection.152        NotFungibleDataUsedToMintFungibleCollectionToken,153        /// Not Re Fungible item data used to mint in Re Fungible collection.154        NotReFungibleDataUsedToMintReFungibleCollectionToken,155        /// Unexpected collection type.156        UnexpectedCollectionType,157        /// Can't store metadata in fungible tokens.158        CantStoreMetadataInFungibleTokens,159        /// Collection token limit exceeded160        CollectionTokenLimitExceeded,161        /// Account token limit exceeded per collection162        AccountTokenLimitExceeded,163        /// Collection limit bounds per collection exceeded164        CollectionLimitBoundsExceeded,165        /// Tried to enable permissions which are only permitted to be disabled166        OwnerPermissionsCantBeReverted,167        /// Schema data size limit bound exceeded168        SchemaDataLimitExceeded,169        /// Maximum refungibility exceeded170        WrongRefungiblePieces,171        /// createRefungible should be called with one owner172        BadCreateRefungibleCall,173        /// Gas limit exceeded174        OutOfGas,175	}176}177178pub struct CollectionHandle<T: Config> {179    pub id: CollectionId,180    collection: Collection<T>,181    logs: eth::log::LogRecorder,182    evm_address: H160,183    gas_limit: RefCell<u64>,184}185impl<T: Config> CollectionHandle<T> {186	pub fn get_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {187		<CollectionById<T>>::get(id)188			.map(|collection| Self {189				id,190				collection,191                logs: eth::log::LogRecorder::default(),192                evm_address: eth::collection_id_to_address(id),193                gas_limit: RefCell::new(gas_limit),194			})195	}196    pub fn get(id: CollectionId) -> Option<Self> {197        Self::get_with_gas_limit(id, u64::MAX)198    }199    pub fn gas_left(&self) -> u64 {200        *self.gas_limit.borrow()201    }202    pub fn consume_gas(&self, gas: u64) -> DispatchResult {203        let mut gas_limit = self.gas_limit.borrow_mut();204        if *gas_limit < gas {205            fail!(Error::<T>::OutOfGas);206        }207        *gas_limit -= gas;208        Ok(())209    }210    pub fn log(&self, log: impl evm_coder::ToLog) {211        self.logs.log(log.to_log(self.evm_address))212    }213    pub fn into_inner(self) -> Collection<T> {214        self.collection.clone()215    }216}217impl<T: Config> Deref for CollectionHandle<T> {218    type Target = Collection<T>;219220    fn deref(&self) -> &Self::Target {221        &self.collection222    }223}224225impl<T: Config> DerefMut for CollectionHandle<T> {226    fn deref_mut(&mut self) -> &mut Self::Target {227        &mut self.collection228    }229}230231pub trait Config: system::Config + Sized {232    type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;233234    /// Weight information for extrinsics in this pallet.235	type WeightInfo: WeightInfo;236237    type EvmAddressMapping: pallet_evm::AddressMapping<Self::AccountId>;238    type EvmBackwardsAddressMapping: EvmBackwardsAddressMapping<Self::AccountId>;239240	type CrossAccountId: CrossAccountId<Self::AccountId>;241    type Currency: Currency<Self::AccountId>;242    type CollectionCreationPrice: Get<<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance>;243    type TreasuryAccountId: Get<Self::AccountId>;244245    type EthereumChainId: Get<u64>;246    type EthereumTransactionSender: pallet_ethereum::EthereumTransactionSender;247}248249// # Used definitions250//251// ## User control levels252//253// chain-controlled - key is uncontrolled by user254//                    i.e autoincrementing index255//                    can use non-cryptographic hash256// real - key is controlled by user257//        but it is hard to generate enough colliding values, i.e owner of signed txs258//        can use non-cryptographic hash259// controlled - key is completly controlled by users260//              i.e maps with mutable keys261//              should use cryptographic hash262//263// ## User control level downgrade reasons264//265// ?1 - chain-controlled -> controlled266//      collections/tokens can be destroyed, resulting in massive holes267// ?2 - chain-controlled -> controlled268//      same as ?1, but can be only added, resulting in easier exploitation269// ?3 - real -> controlled270//      no confirmation required, so addresses can be easily generated271decl_storage! {272    trait Store for Module<T: Config> as Nft {273274        //#region Private members275        /// Id of next collection276        CreatedCollectionCount: u32;277        /// Used for migrations278        ChainVersion: u64;279        /// Id of last collection token280        /// Collection id (controlled?1)281        ItemListIndex: map hasher(blake2_128_concat) CollectionId => TokenId;282        //#endregion283284        //#region Chain limits struct285        pub ChainLimit get(fn chain_limit) config(): ChainLimits;286        //#endregion287288        //#region Bound counters289        /// Amount of collections destroyed, used for total amount tracking with290        /// CreatedCollectionCount291        DestroyedCollectionCount: u32;292        /// Total amount of account owned tokens (NFTs + RFTs + unique fungibles)293        /// Account id (real)294        pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;295        //#endregion296297        //#region Basic collections298        /// Collection info299        /// Collection id (controlled?1)300        pub CollectionById get(fn collection_id) config(): map hasher(blake2_128_concat) CollectionId => Option<Collection<T>> = None;301        /// List of collection admins302        /// Collection id (controlled?2)303        pub AdminList get(fn admin_list_collection): map hasher(blake2_128_concat) CollectionId => Vec<T::CrossAccountId>;304        /// Whitelisted collection users305        /// Collection id (controlled?2), user id (controlled?3)306        pub WhiteList get(fn white_list): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => bool;307        //#endregion308309        /// How many of collection items user have310        /// Collection id (controlled?2), account id (real)311        pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => u128;312313        /// Amount of items which spender can transfer out of owners account (via transferFrom)314        /// Collection id (controlled?2), (token id (controlled ?2) + owner account id (real) + spender account id (controlled?3))315        /// TODO: Off chain worker should remove from this map when token gets removed316        pub Allowances get(fn approved): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) (TokenId, T::AccountId, T::AccountId) => u128;317318        //#region Item collections319        /// Collection id (controlled?2), token id (controlled?1)320        pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<NftItemType<T::CrossAccountId>>;321        /// Collection id (controlled?2), owner (controlled?2)322        pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => FungibleItemType;323        /// Collection id (controlled?2), token id (controlled?1)324        pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<ReFungibleItemType<T::CrossAccountId>>;325        //#endregion326327        //#region Index list328        /// Collection id (controlled?2), tokens owner (controlled?2)329        pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => Vec<TokenId>;330        //#endregion331332        //#region Tokens transfer rate limit baskets333        /// (Collection id (controlled?2), who created (real))334        /// TODO: Off chain worker should remove from this map when collection gets removed335        pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => T::BlockNumber;336        /// Collection id (controlled?2), token id (controlled?2)337        pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;338        /// Collection id (controlled?2), owning user (real)339        pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;340        /// Collection id (controlled?2), token id (controlled?2)341        pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;342        //#endregion343344        /// Variable metadata sponsoring345        /// Collection id (controlled?2), token id (controlled?2)346        pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber> = None;347    }348    add_extra_genesis {349        build(|config: &GenesisConfig<T>| {350            // Modification of storage351            for (_num, _c) in &config.collection_id {352                <Module<T>>::init_collection(_c);353            }354355            for (_num, _c, _i) in &config.nft_item_id {356                <Module<T>>::init_nft_token(*_c, _i);357            }358359            for (collection_id, account_id, fungible_item) in &config.fungible_item_id {360                <Module<T>>::init_fungible_token(*collection_id, &T::CrossAccountId::from_sub(account_id.clone()), fungible_item);361            }362363            for (_num, _c, _i) in &config.refungible_item_id {364                <Module<T>>::init_refungible_token(*_c, _i);365            }366        })367    }368}369370decl_event!(371    pub enum Event<T>372    where373        AccountId = <T as frame_system::Config>::AccountId,374        CrossAccountId = <T as Config>::CrossAccountId,375    {376        /// New collection was created377        /// 378        /// # Arguments379        /// 380        /// * collection_id: Globally unique identifier of newly created collection.381        /// 382        /// * mode: [CollectionMode] converted into u8.383        /// 384        /// * account_id: Collection owner.385        CollectionCreated(CollectionId, u8, AccountId),386387        /// New item was created.388        /// 389        /// # Arguments390        /// 391        /// * collection_id: Id of the collection where item was created.392        /// 393        /// * item_id: Id of an item. Unique within the collection.394        ///395        /// * recipient: Owner of newly created item 396        ItemCreated(CollectionId, TokenId, CrossAccountId),397398        /// Collection item was burned.399        /// 400        /// # Arguments401        /// 402        /// collection_id.403        /// 404        /// item_id: Identifier of burned NFT.405        ItemDestroyed(CollectionId, TokenId),406407        /// Item was transferred408        ///409        /// * collection_id: Id of collection to which item is belong410        ///411        /// * item_id: Id of an item412        ///413        /// * sender: Original owner of item414        ///415        /// * recipient: New owner of item416        ///417        /// * amount: Always 1 for NFT418        Transfer(CollectionId, TokenId, CrossAccountId, CrossAccountId, u128),419420        /// * collection_id421        ///422        /// * item_id423        ///424        /// * sender425        ///426        /// * spender427        ///428        /// * amount429        Approved(CollectionId, TokenId, CrossAccountId, CrossAccountId, u128),430    }431);432433decl_module! {434    pub struct Module<T: Config> for enum Call 435    where 436        origin: T::Origin437    {438        fn deposit_event() = default;439        type Error = Error<T>;440441        fn on_initialize(_now: T::BlockNumber) -> Weight {442            0443        }444445        /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner and admin of the collection are set to the address that signed the transaction. Both addresses can be changed later.446        /// 447        /// # Permissions448        /// 449        /// * Anyone.450        /// 451        /// # Arguments452        /// 453        /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.454        /// 455        /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.456        /// 457        /// * token_prefix: UTF-8 string with token prefix.458        /// 459        /// * mode: [CollectionMode] collection type and type dependent data.460        // returns collection ID461        #[weight = <T as Config>::WeightInfo::create_collection()]462        #[transactional]463        pub fn create_collection(origin,464                                 collection_name: Vec<u16>,465                                 collection_description: Vec<u16>,466                                 token_prefix: Vec<u8>,467                                 mode: CollectionMode) -> DispatchResult {468469            // Anyone can create a collection470            let who = ensure_signed(origin)?;471472            // Take a (non-refundable) deposit of collection creation473            let mut imbalance = <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();474            imbalance.subsume(<<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(475                &T::TreasuryAccountId::get(),476                T::CollectionCreationPrice::get(),477            ));478            <T as Config>::Currency::settle(479                &who,480                imbalance,481                WithdrawReasons::TRANSFER,482                ExistenceRequirement::KeepAlive,483            ).map_err(|_| Error::<T>::NoPermission)?;484485            let decimal_points = match mode {486                CollectionMode::Fungible(points) => points,487                _ => 0488            };489490            let chain_limit = ChainLimit::get();491492            let created_count = CreatedCollectionCount::get();493            let destroyed_count = DestroyedCollectionCount::get();494495            // bound Total number of collections496            ensure!(created_count - destroyed_count < chain_limit.collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);497498            // check params499            ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);500            ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);501            ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);502            ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);503504            // Generate next collection ID505            let next_id = created_count506                .checked_add(1)507                .ok_or(Error::<T>::NumOverflow)?;508509            CreatedCollectionCount::put(next_id);510511            let limits = CollectionLimits {512                sponsored_data_size: chain_limit.custom_data_limit,513                ..Default::default()514            };515516            // Create new collection517            let new_collection = Collection {518                owner: who.clone(),519                name: collection_name,520                mode: mode.clone(),521                mint_mode: false,522                access: AccessMode::Normal,523                description: collection_description,524                decimal_points: decimal_points,525                token_prefix: token_prefix,526                offchain_schema: Vec::new(),527                schema_version: SchemaVersion::ImageURL,528                sponsorship: SponsorshipState::Disabled,529                variable_on_chain_schema: Vec::new(),530                const_on_chain_schema: Vec::new(),531                limits,532            };533534            // Add new collection to map535            <CollectionById<T>>::insert(next_id, new_collection);536537            // call event538            Self::deposit_event(RawEvent::CollectionCreated(next_id, mode.into(), who));539540            Ok(())541        }542543        /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.544        /// 545        /// # Permissions546        /// 547        /// * Collection Owner.548        /// 549        /// # Arguments550        /// 551        /// * collection_id: collection to destroy.552        #[weight = <T as Config>::WeightInfo::destroy_collection()]553        #[transactional]554        pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {555556            let sender = ensure_signed(origin)?;557            let collection = Self::get_collection(collection_id)?;558            Self::check_owner_permissions(&collection, &sender)?;559            if !collection.limits.owner_can_destroy {560                fail!(Error::<T>::NoPermission);561            }562563            <AddressTokens<T>>::remove_prefix(collection_id);564            <Allowances<T>>::remove_prefix(collection_id);565            <Balance<T>>::remove_prefix(collection_id);566            <ItemListIndex>::remove(collection_id);567            <AdminList<T>>::remove(collection_id);568            <CollectionById<T>>::remove(collection_id);569            <WhiteList<T>>::remove_prefix(collection_id);570571            <NftItemList<T>>::remove_prefix(collection_id);572            <FungibleItemList<T>>::remove_prefix(collection_id);573            <ReFungibleItemList<T>>::remove_prefix(collection_id);574575            <NftTransferBasket<T>>::remove_prefix(collection_id);576            <FungibleTransferBasket<T>>::remove_prefix(collection_id);577            <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);578579            <VariableMetaDataBasket<T>>::remove_prefix(collection_id);580581            DestroyedCollectionCount::put(DestroyedCollectionCount::get()582                .checked_add(1)583                .ok_or(Error::<T>::NumOverflow)?);584585            Ok(())586        }587588        /// Add an address to white list.589        /// 590        /// # Permissions591        /// 592        /// * Collection Owner593        /// * Collection Admin594        /// 595        /// # Arguments596        /// 597        /// * collection_id.598        /// 599        /// * address.600        #[weight = <T as Config>::WeightInfo::add_to_white_list()]601        #[transactional]602        pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{603604            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);605            let collection = Self::get_collection(collection_id)?;606607            Self::toggle_white_list_internal(608                &sender,609                &collection,610                &address,611                true,612            )?;613614            Ok(())615        }616617        /// Remove an address from white list.618        /// 619        /// # Permissions620        /// 621        /// * Collection Owner622        /// * Collection Admin623        /// 624        /// # Arguments625        /// 626        /// * collection_id.627        /// 628        /// * address.629        #[weight = <T as Config>::WeightInfo::remove_from_white_list()]630        #[transactional]631        pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{632633            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);634            let collection = Self::get_collection(collection_id)?;635636            Self::toggle_white_list_internal(637                &sender,638                &collection,639                &address,640                false,641            )?;642643            Ok(())644        }645646        /// Toggle between normal and white list access for the methods with access for `Anyone`.647        /// 648        /// # Permissions649        /// 650        /// * Collection Owner.651        /// 652        /// # Arguments653        /// 654        /// * collection_id.655        /// 656        /// * mode: [AccessMode]657        #[weight = <T as Config>::WeightInfo::set_public_access_mode()]658        #[transactional]659        pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult660        {661            let sender = ensure_signed(origin)?;662663            let mut target_collection = Self::get_collection(collection_id)?;664            Self::check_owner_permissions(&target_collection, &sender)?;665            target_collection.access = mode;666            Self::save_collection(target_collection);667668            Ok(())669        }670671        /// Allows Anyone to create tokens if:672        /// * White List is enabled, and673        /// * Address is added to white list, and674        /// * This method was called with True parameter675        /// 676        /// # Permissions677        /// * Collection Owner678        ///679        /// # Arguments680        /// 681        /// * collection_id.682        /// 683        /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.684        #[weight = <T as Config>::WeightInfo::set_mint_permission()]685        #[transactional]686        pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult687        {688            let sender = ensure_signed(origin)?;689690            let mut target_collection = Self::get_collection(collection_id)?;691            Self::check_owner_permissions(&target_collection, &sender)?;692            target_collection.mint_mode = mint_permission;693            Self::save_collection(target_collection);694695            Ok(())696        }697698        /// Change the owner of the collection.699        /// 700        /// # Permissions701        /// 702        /// * Collection Owner.703        /// 704        /// # Arguments705        /// 706        /// * collection_id.707        /// 708        /// * new_owner.709        #[weight = <T as Config>::WeightInfo::change_collection_owner()]710        #[transactional]711        pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {712713            let sender = ensure_signed(origin)?;714            let mut target_collection = Self::get_collection(collection_id)?;715            Self::check_owner_permissions(&target_collection, &sender)?;716            target_collection.owner = new_owner;717            Self::save_collection(target_collection);718719            Ok(())720        }721722        /// Adds an admin of the Collection.723        /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership. 724        /// 725        /// # Permissions726        /// 727        /// * Collection Owner.728        /// * Collection Admin.729        /// 730        /// # Arguments731        /// 732        /// * collection_id: ID of the Collection to add admin for.733        /// 734        /// * new_admin_id: Address of new admin to add.735        #[weight = <T as Config>::WeightInfo::add_collection_admin()]736        #[transactional]737        pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {738            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);739            let collection = Self::get_collection(collection_id)?;740            Self::check_owner_or_admin_permissions(&collection, &sender)?;741            let mut admin_arr = <AdminList<T>>::get(collection_id);742743            match admin_arr.binary_search(&new_admin_id) {744                Ok(_) => {},745                Err(idx) => {746                    let limits = ChainLimit::get();747                    ensure!(admin_arr.len() < limits.collections_admins_limit as usize, Error::<T>::CollectionAdminsLimitExceeded);748                    admin_arr.insert(idx, new_admin_id);749                    <AdminList<T>>::insert(collection_id, admin_arr);750                }751            }752            Ok(())753        }754755        /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.756        ///757        /// # Permissions758        /// 759        /// * Collection Owner.760        /// * Collection Admin.761        /// 762        /// # Arguments763        /// 764        /// * collection_id: ID of the Collection to remove admin for.765        /// 766        /// * account_id: Address of admin to remove.767        #[weight = <T as Config>::WeightInfo::remove_collection_admin()]768        #[transactional]769        pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {770            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);771            let collection = Self::get_collection(collection_id)?;772            Self::check_owner_or_admin_permissions(&collection, &sender)?;773            let mut admin_arr = <AdminList<T>>::get(collection_id);774775            match admin_arr.binary_search(&account_id) {776                Ok(idx) => {777                    admin_arr.remove(idx);778                    <AdminList<T>>::insert(collection_id, admin_arr);779                },780                Err(_) => {}781            }782            Ok(())783        }784785        /// # Permissions786        /// 787        /// * Collection Owner788        /// 789        /// # Arguments790        /// 791        /// * collection_id.792        /// 793        /// * new_sponsor.794        #[weight = <T as Config>::WeightInfo::set_collection_sponsor()]795        #[transactional]796        pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {797            let sender = ensure_signed(origin)?;798            let mut target_collection = Self::get_collection(collection_id)?;799            Self::check_owner_permissions(&target_collection, &sender)?;800801            target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor);802            Self::save_collection(target_collection);803804            Ok(())805        }806807        /// # Permissions808        /// 809        /// * Sponsor.810        /// 811        /// # Arguments812        /// 813        /// * collection_id.814        #[weight = <T as Config>::WeightInfo::confirm_sponsorship()]815        #[transactional]816        pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {817            let sender = ensure_signed(origin)?;818819            let mut target_collection = Self::get_collection(collection_id)?;820            ensure!(821                target_collection.sponsorship.pending_sponsor() == Some(&sender),822                Error::<T>::ConfirmUnsetSponsorFail823            );824825            target_collection.sponsorship = SponsorshipState::Confirmed(sender);826            Self::save_collection(target_collection);827828            Ok(())829        }830831        /// Switch back to pay-per-own-transaction model.832        ///833        /// # Permissions834        ///835        /// * Collection owner.836        /// 837        /// # Arguments838        /// 839        /// * collection_id.840        #[weight = <T as Config>::WeightInfo::remove_collection_sponsor()]841        #[transactional]842        pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {843            let sender = ensure_signed(origin)?;844845            let mut target_collection = Self::get_collection(collection_id)?;846            Self::check_owner_permissions(&target_collection, &sender)?;847848            target_collection.sponsorship = SponsorshipState::Disabled;849            Self::save_collection(target_collection);850851            Ok(())852        }853854        /// This method creates a concrete instance of NFT Collection created with CreateCollection method.855        /// 856        /// # Permissions857        /// 858        /// * Collection Owner.859        /// * Collection Admin.860        /// * Anyone if861        ///     * White List is enabled, and862        ///     * Address is added to white list, and863        ///     * MintPermission is enabled (see SetMintPermission method)864        /// 865        /// # Arguments866        /// 867        /// * collection_id: ID of the collection.868        /// 869        /// * owner: Address, initial owner of the NFT.870        ///871        /// * data: Token data to store on chain.872        // #[weight =873        // (130_000_000 as Weight)874        // .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))875        // .saturating_add(RocksDbWeight::get().reads(10 as Weight))876        // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]877878        #[weight = <T as Config>::WeightInfo::create_item(data.len())]879        #[transactional]880        pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResult {881            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);882            let collection = Self::get_collection(collection_id)?;883884            Self::create_item_internal(&sender, &collection, &owner, data)?;885886            Self::submit_logs(collection)?;887            Ok(())888        }889890        /// This method creates multiple items in a collection created with CreateCollection method.891        /// 892        /// # Permissions893        /// 894        /// * Collection Owner.895        /// * Collection Admin.896        /// * Anyone if897        ///     * White List is enabled, and898        ///     * Address is added to white list, and899        ///     * MintPermission is enabled (see SetMintPermission method)900        /// 901        /// # Arguments902        /// 903        /// * collection_id: ID of the collection.904        /// 905        /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].906        /// 907        /// * owner: Address, initial owner of the NFT.908        #[weight = <T as Config>::WeightInfo::create_item(items_data.into_iter()909                               .map(|data| { data.len() })910                               .sum())]911        #[transactional]912        pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResult {913914            ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);915            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);916            let collection = Self::get_collection(collection_id)?;917918            Self::create_multiple_items_internal(&sender, &collection, &owner, items_data)?;919920            Self::submit_logs(collection)?;921            Ok(())922        }923924        /// Destroys a concrete instance of NFT.925        /// 926        /// # Permissions927        /// 928        /// * Collection Owner.929        /// * Collection Admin.930        /// * Current NFT Owner.931        /// 932        /// # Arguments933        /// 934        /// * collection_id: ID of the collection.935        /// 936        /// * item_id: ID of NFT to burn.937        #[weight = <T as Config>::WeightInfo::burn_item()]938        #[transactional]939        pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {940941            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);942            let target_collection = Self::get_collection(collection_id)?;943944            Self::burn_item_internal(&sender, &target_collection, item_id, value)?;945946            Self::submit_logs(target_collection)?;947            Ok(())948        }949950        /// Change ownership of the token.951        /// 952        /// # Permissions953        /// 954        /// * Collection Owner955        /// * Collection Admin956        /// * Current NFT owner957        ///958        /// # Arguments959        /// 960        /// * recipient: Address of token recipient.961        /// 962        /// * collection_id.963        /// 964        /// * item_id: ID of the item965        ///     * Non-Fungible Mode: Required.966        ///     * Fungible Mode: Ignored.967        ///     * Re-Fungible Mode: Required.968        /// 969        /// * value: Amount to transfer.970        ///     * Non-Fungible Mode: Ignored971        ///     * Fungible Mode: Must specify transferred amount972        ///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)973        #[weight = <T as Config>::WeightInfo::transfer()]974        #[transactional]975        pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {976            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);977            let collection = Self::get_collection(collection_id)?;978979            Self::transfer_internal(&sender, &recipient, &collection, item_id, value)?;980981            Self::submit_logs(collection)?;982            Ok(())983        }984985        /// Set, change, or remove approved address to transfer the ownership of the NFT.986        /// 987        /// # Permissions988        /// 989        /// * Collection Owner990        /// * Collection Admin991        /// * Current NFT owner992        /// 993        /// # Arguments994        /// 995        /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).996        /// 997        /// * collection_id.998        /// 999        /// * item_id: ID of the item.1000        #[weight = <T as Config>::WeightInfo::approve()]1001        #[transactional]1002        pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {1003            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1004            let collection = Self::get_collection(collection_id)?;10051006            Self::approve_internal(&sender, &spender, &collection, item_id, amount)?;10071008            Self::submit_logs(collection)?;1009            Ok(())1010        }1011        1012        /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.1013        /// 1014        /// # Permissions1015        /// * Collection Owner1016        /// * Collection Admin1017        /// * Current NFT owner1018        /// * Address approved by current NFT owner1019        /// 1020        /// # Arguments1021        /// 1022        /// * from: Address that owns token.1023        /// 1024        /// * recipient: Address of token recipient.1025        /// 1026        /// * collection_id.1027        /// 1028        /// * item_id: ID of the item.1029        /// 1030        /// * value: Amount to transfer.1031        #[weight = <T as Config>::WeightInfo::transfer_from()]1032        #[transactional]1033        pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {1034            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1035            let collection = Self::get_collection(collection_id)?;10361037            Self::transfer_from_internal(&sender, &from, &recipient, &collection, item_id, value)?;10381039            Self::submit_logs(collection)?;1040            Ok(())1041        }1042        // #[weight = 0]1043        //     // let no_perm_mes = "You do not have permissions to modify this collection";1044        //     // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1045        //     // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1046        //     // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);10471048        //     // // on_nft_received  call10491050        //     // Self::transfer(origin, collection_id, item_id, new_owner)?;10511052        //     Ok(())1053        // }10541055        /// Set off-chain data schema.1056        /// 1057        /// # Permissions1058        /// 1059        /// * Collection Owner1060        /// * Collection Admin1061        /// 1062        /// # Arguments1063        /// 1064        /// * collection_id.1065        /// 1066        /// * schema: String representing the offchain data schema.1067        #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1068        #[transactional]1069        pub fn set_variable_meta_data (1070            origin,1071            collection_id: CollectionId,1072            item_id: TokenId,1073            data: Vec<u8>1074        ) -> DispatchResult {1075            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1076            1077            let collection = Self::get_collection(collection_id)?;10781079            Self::set_variable_meta_data_internal(&sender, &collection, item_id, data)?;10801081            Ok(())1082        }1083 1084        /// Set schema standard1085        /// ImageURL1086        /// Unique1087        /// 1088        /// # Permissions1089        /// 1090        /// * Collection Owner1091        /// * Collection Admin1092        /// 1093        /// # Arguments1094        /// 1095        /// * collection_id.1096        /// 1097        /// * schema: SchemaVersion: enum1098        #[weight = <T as Config>::WeightInfo::set_schema_version()]1099        #[transactional]1100        pub fn set_schema_version(1101            origin,1102            collection_id: CollectionId,1103            version: SchemaVersion1104        ) -> DispatchResult {1105            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1106            let mut target_collection = Self::get_collection(collection_id)?;1107            Self::check_owner_or_admin_permissions(&target_collection, &sender)?;1108            target_collection.schema_version = version;1109            Self::save_collection(target_collection);11101111            Ok(())1112        }11131114        /// Set off-chain data schema.1115        /// 1116        /// # Permissions1117        /// 1118        /// * Collection Owner1119        /// * Collection Admin1120        /// 1121        /// # Arguments1122        /// 1123        /// * collection_id.1124        /// 1125        /// * schema: String representing the offchain data schema.1126        #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1127        #[transactional]1128        pub fn set_offchain_schema(1129            origin,1130            collection_id: CollectionId,1131            schema: Vec<u8>1132        ) -> DispatchResult {1133            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1134            let mut target_collection = Self::get_collection(collection_id)?;1135            Self::check_owner_or_admin_permissions(&target_collection, &sender)?;11361137            // check schema limit1138            ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");11391140            target_collection.offchain_schema = schema;1141            Self::save_collection(target_collection);11421143            Ok(())1144        }11451146        /// Set const on-chain data schema.1147        /// 1148        /// # Permissions1149        /// 1150        /// * Collection Owner1151        /// * Collection Admin1152        /// 1153        /// # Arguments1154        /// 1155        /// * collection_id.1156        /// 1157        /// * schema: String representing the const on-chain data schema.1158        #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1159        #[transactional]1160        pub fn set_const_on_chain_schema (1161            origin,1162            collection_id: CollectionId,1163            schema: Vec<u8>1164        ) -> DispatchResult {1165            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1166            let mut target_collection = Self::get_collection(collection_id)?;1167            Self::check_owner_or_admin_permissions(&target_collection, &sender)?;11681169            // check schema limit1170            ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");11711172            target_collection.const_on_chain_schema = schema;1173            Self::save_collection(target_collection);11741175            Ok(())1176        }11771178        /// Set variable on-chain data schema.1179        /// 1180        /// # Permissions1181        /// 1182        /// * Collection Owner1183        /// * Collection Admin1184        /// 1185        /// # Arguments1186        /// 1187        /// * collection_id.1188        /// 1189        /// * schema: String representing the variable on-chain data schema.1190        #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1191        #[transactional]1192        pub fn set_variable_on_chain_schema (1193            origin,1194            collection_id: CollectionId,1195            schema: Vec<u8>1196        ) -> DispatchResult {1197            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1198            let mut target_collection = Self::get_collection(collection_id)?;1199            Self::check_owner_or_admin_permissions(&target_collection, &sender)?;12001201            // check schema limit1202            ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");12031204            target_collection.variable_on_chain_schema = schema;1205            Self::save_collection(target_collection);12061207            Ok(())1208        }12091210        // Sudo permissions function1211        #[weight = <T as Config>::WeightInfo::set_chain_limits()]1212        #[transactional]1213        pub fn set_chain_limits(1214            origin,1215            limits: ChainLimits1216        ) -> DispatchResult {12171218            #[cfg(not(feature = "runtime-benchmarks"))]1219            ensure_root(origin)?;12201221            <ChainLimit>::put(limits);1222            Ok(())1223        }12241225        #[weight = <T as Config>::WeightInfo::set_collection_limits()]1226        #[transactional]1227        pub fn set_collection_limits(1228            origin,1229            collection_id: u32,1230            new_limits: CollectionLimits<T::BlockNumber>,1231        ) -> DispatchResult {1232            let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1233            let mut target_collection = Self::get_collection(collection_id)?;1234            Self::check_owner_permissions(&target_collection, &sender.as_sub())?;1235            let old_limits = &target_collection.limits;1236            let chain_limits = ChainLimit::get();12371238            // collection bounds1239            ensure!(new_limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1240                new_limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP && 1241                new_limits.sponsored_data_size <= chain_limits.custom_data_limit,1242                Error::<T>::CollectionLimitBoundsExceeded);12431244            // token_limit   check  prev1245            ensure!(old_limits.token_limit >= new_limits.token_limit, Error::<T>::CollectionTokenLimitExceeded);1246            ensure!(new_limits.token_limit > 0, Error::<T>::CollectionTokenLimitExceeded);12471248            ensure!(1249                (old_limits.owner_can_transfer || !new_limits.owner_can_transfer) &&1250                (old_limits.owner_can_destroy || !new_limits.owner_can_destroy),1251                Error::<T>::OwnerPermissionsCantBeReverted,1252            );12531254            target_collection.limits = new_limits;1255            Self::save_collection(target_collection);12561257            Ok(())1258        } 1259    }1260}12611262impl<T: Config> Module<T> {1263    pub fn create_item_internal(sender: &T::CrossAccountId, collection: &CollectionHandle<T>, owner: &T::CrossAccountId, data: CreateItemData) -> DispatchResult {1264        Self::can_create_items_in_collection(&collection, &sender, &owner, 1)?;1265        Self::validate_create_item_args(&collection, &data)?;1266        Self::create_item_no_validation(&collection, owner, data)?;12671268        Ok(())1269    }12701271    pub fn transfer_internal(sender: &T::CrossAccountId, recipient: &T::CrossAccountId, target_collection: &CollectionHandle<T>, item_id: TokenId, value: u128) -> DispatchResult {1272        target_collection.consume_gas(2000000)?;1273        // Limits check1274        Self::is_correct_transfer(target_collection, &recipient)?;12751276        // Transfer permissions check1277        ensure!(Self::is_item_owner(&sender, target_collection, item_id) ||1278            Self::is_owner_or_admin_permissions(target_collection, &sender),1279            Error::<T>::NoPermission);12801281        if target_collection.access == AccessMode::WhiteList {1282            Self::check_white_list(target_collection, &sender)?;1283            Self::check_white_list(target_collection, &recipient)?;1284        }12851286        match target_collection.mode1287        {1288            CollectionMode::NFT => Self::transfer_nft(target_collection, item_id, sender.clone(), recipient.clone())?,1289            CollectionMode::Fungible(_)  => Self::transfer_fungible(target_collection, value, &sender, &recipient)?,1290            CollectionMode::ReFungible  => Self::transfer_refungible(target_collection, item_id, value, sender.clone(), recipient.clone())?,1291            _ => ()1292        };12931294        Self::deposit_event(RawEvent::Transfer(target_collection.id, item_id, sender.clone(), recipient.clone(), value));12951296        Ok(())1297    }12981299	pub fn approve_internal(1300		sender: &T::CrossAccountId,1301		spender: &T::CrossAccountId,1302		collection: &CollectionHandle<T>,1303		item_id: TokenId,1304		amount: u1281305	) -> DispatchResult {1306        collection.consume_gas(2000000)?;1307		Self::token_exists(&collection, item_id)?;13081309		// Transfer permissions check1310		let bypasses_limits = collection.limits.owner_can_transfer &&1311			Self::is_owner_or_admin_permissions(1312				&collection,1313				&sender,1314			);13151316		let allowance_limit = if bypasses_limits {1317			None1318		} else if let Some(amount) = Self::owned_amount(1319			&sender,1320			&collection,1321			item_id,1322		) {1323			Some(amount)1324		} else {1325			fail!(Error::<T>::NoPermission);1326		};13271328		if collection.access == AccessMode::WhiteList {1329			Self::check_white_list(&collection, &sender)?;1330			Self::check_white_list(&collection, &spender)?;1331		}13321333		let allowance: u128 = amount1334			.checked_add(<Allowances<T>>::get(collection.id, (item_id, sender.as_sub(), spender.as_sub())))1335			.ok_or(Error::<T>::NumOverflow)?;1336		if let Some(limit) = allowance_limit {1337			ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);1338		}1339		<Allowances<T>>::insert(collection.id, (item_id, sender.as_sub(), spender.as_sub()), allowance);13401341		if matches!(collection.mode, CollectionMode::NFT) {1342			// TODO: NFT: only one owner may exist for token in ERC7211343			collection.log(ERC721Events::Approval {1344                owner: *sender.as_eth(),1345                approved: *spender.as_eth(),1346                token_id: item_id.into(),1347            });1348		}13491350		if matches!(collection.mode, CollectionMode::Fungible(_)) {1351			// TODO: NFT: only one owner may exist for token in ERC201352			collection.log(ERC20Events::Approval {1353                owner: *sender.as_eth(),1354                spender: *spender.as_eth(),1355                value: allowance.into()1356            });1357		}13581359		Self::deposit_event(RawEvent::Approved(collection.id, item_id, sender.clone(), spender.clone(), allowance));1360		Ok(())1361	}13621363	pub fn transfer_from_internal(1364		sender: &T::CrossAccountId,1365		from: &T::CrossAccountId,1366		recipient: &T::CrossAccountId,1367		collection: &CollectionHandle<T>,1368		item_id: TokenId,1369		amount: u128,1370	) -> DispatchResult {1371        collection.consume_gas(2000000)?;1372		// Check approval1373		let approval: u128 = <Allowances<T>>::get(collection.id, (item_id, from.as_sub(), sender.as_sub()));13741375		// Limits check1376		Self::is_correct_transfer(&collection, &recipient)?;13771378		// Transfer permissions check1379		ensure!(1380			approval >= amount || 1381			(1382				collection.limits.owner_can_transfer &&1383				Self::is_owner_or_admin_permissions(&collection, &sender)1384			),1385			Error::<T>::NoPermission1386		);13871388		if collection.access == AccessMode::WhiteList {1389			Self::check_white_list(&collection, &sender)?;1390			Self::check_white_list(&collection, &recipient)?;1391		}13921393		// Reduce approval by transferred amount or remove if remaining approval drops to 01394		let allowance = approval.saturating_sub(amount);1395		if allowance > 0 {1396			<Allowances<T>>::insert(collection.id, (item_id, from.as_sub(), sender.as_sub()), allowance);1397		} else {1398			<Allowances<T>>::remove(collection.id, (item_id, from.as_sub(), sender.as_sub()));1399		}14001401		match collection.mode {1402			CollectionMode::NFT => {1403				Self::transfer_nft(&collection, item_id, from.clone(), recipient.clone())?1404			}1405			CollectionMode::Fungible(_) => {1406				Self::transfer_fungible(&collection, amount, &from, &recipient)?1407			}1408			CollectionMode::ReFungible => {1409				Self::transfer_refungible(&collection, item_id, amount, from.clone(), recipient.clone())?1410			}1411			_ => ()1412		};14131414		if matches!(collection.mode, CollectionMode::Fungible(_)) {1415			collection.log(ERC20Events::Approval {1416                owner: *from.as_eth(),1417                spender: *sender.as_eth(),1418                value: allowance.into()1419            });1420		}14211422		Ok(())1423	}14241425    pub fn set_variable_meta_data_internal(1426        sender: &T::CrossAccountId,1427        collection: &CollectionHandle<T>, 1428        item_id: TokenId,1429        data: Vec<u8>,1430    ) -> DispatchResult {1431        Self::token_exists(&collection, item_id)?;14321433        ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);14341435        // Modify permissions check1436        ensure!(Self::is_item_owner(&sender, &collection, item_id) ||1437            Self::is_owner_or_admin_permissions(&collection, &sender),1438            Error::<T>::NoPermission);14391440        match collection.mode1441        {1442            CollectionMode::NFT => Self::set_nft_variable_data(&collection, item_id, data)?,1443            CollectionMode::ReFungible  => Self::set_re_fungible_variable_data(&collection, item_id, data)?,1444            CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1445            _ => fail!(Error::<T>::UnexpectedCollectionType)1446        };14471448        Ok(())1449    }14501451    pub fn create_multiple_items_internal(1452        sender: &T::CrossAccountId,1453        collection: &CollectionHandle<T>,1454        owner: &T::CrossAccountId,1455        items_data: Vec<CreateItemData>,1456    ) -> DispatchResult {1457        Self::can_create_items_in_collection(&collection, &sender, &owner, items_data.len() as u32)?;14581459        for data in &items_data {1460            Self::validate_create_item_args(&collection, data)?;1461        }1462        for data in &items_data {1463            Self::create_item_no_validation(&collection, owner, data.clone())?;1464        }14651466        Ok(())1467    }14681469    pub fn burn_item_internal(1470        sender: &T::CrossAccountId,1471        collection: &CollectionHandle<T>,1472        item_id: TokenId,1473        value: u128,1474    ) -> DispatchResult {1475        ensure!(1476            Self::is_item_owner(&sender, &collection, item_id) ||1477            (1478                collection.limits.owner_can_transfer &&1479                Self::is_owner_or_admin_permissions(&collection, &sender)1480            ),1481            Error::<T>::NoPermission1482        );14831484        if collection.access == AccessMode::WhiteList {1485            Self::check_white_list(&collection, &sender)?;1486        }14871488        match collection.mode1489        {1490            CollectionMode::NFT => Self::burn_nft_item(&collection, item_id)?,1491            CollectionMode::Fungible(_)  => Self::burn_fungible_item(&sender, &collection, value)?,1492            CollectionMode::ReFungible  => Self::burn_refungible_item(&collection, item_id, &sender)?,1493            _ => ()1494        };14951496        Ok(())1497    }14981499    pub fn toggle_white_list_internal(1500        sender: &T::CrossAccountId,1501        collection: &CollectionHandle<T>,1502        address: &T::CrossAccountId,1503        whitelisted: bool,1504    ) -> DispatchResult {1505        Self::check_owner_or_admin_permissions(&collection, &sender)?;15061507        if whitelisted {1508            <WhiteList<T>>::insert(collection.id, address.as_sub(), true);1509        } else {1510            <WhiteList<T>>::remove(collection.id, address.as_sub());1511        }15121513        Ok(())1514    }15151516    fn is_correct_transfer(collection: &CollectionHandle<T>, recipient: &T::CrossAccountId) -> DispatchResult {1517        let collection_id = collection.id;15181519        // check token limit and account token limit1520        let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient.as_sub()).len() as u32;1521        ensure!(collection.limits.account_token_ownership_limit > account_items,  Error::<T>::AccountTokenLimitExceeded);1522        1523        Ok(())1524    }15251526    fn can_create_items_in_collection(collection: &CollectionHandle<T>, sender: &T::CrossAccountId, owner: &T::CrossAccountId, amount: u32) -> DispatchResult {1527        let collection_id = collection.id;15281529        // check token limit and account token limit1530        let total_items: u32 = ItemListIndex::get(collection_id)1531            .checked_add(amount)1532            .ok_or(Error::<T>::CollectionTokenLimitExceeded)?;1533        let account_items: u32 = (<AddressTokens<T>>::get(collection_id, owner.as_sub()).len() as u32)1534            .checked_add(amount)1535            .ok_or(Error::<T>::AccountTokenLimitExceeded)?;1536        ensure!(collection.limits.token_limit >= total_items,  Error::<T>::CollectionTokenLimitExceeded);1537        ensure!(collection.limits.account_token_ownership_limit >= account_items,  Error::<T>::AccountTokenLimitExceeded);15381539        if !Self::is_owner_or_admin_permissions(collection, &sender) {1540            ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1541            Self::check_white_list(collection, owner)?;1542            Self::check_white_list(collection, sender)?;1543        }15441545        Ok(())1546    }15471548    fn validate_create_item_args(target_collection: &CollectionHandle<T>, data: &CreateItemData) -> DispatchResult {1549        match target_collection.mode1550        {1551            CollectionMode::NFT => {1552                if let CreateItemData::NFT(data) = data {1553                    // check sizes1554                    ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1555                    ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1556                } else {1557                    fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1558                }1559            },1560            CollectionMode::Fungible(_) => {1561                if let CreateItemData::Fungible(_) = data {1562                } else {1563                    fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1564                }1565            },1566            CollectionMode::ReFungible => {1567                if let CreateItemData::ReFungible(data) = data {15681569                    // check sizes1570                    ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1571                    ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);15721573                    // Check refungibility limits1574                    ensure!(data.pieces <= MAX_REFUNGIBLE_PIECES, Error::<T>::WrongRefungiblePieces);1575                    ensure!(data.pieces > 0, Error::<T>::WrongRefungiblePieces);1576                } else {1577                    fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1578                }1579            },1580            _ => { fail!(Error::<T>::UnexpectedCollectionType); }1581        };15821583        Ok(())1584    }15851586    fn create_item_no_validation(collection: &CollectionHandle<T>, owner: &T::CrossAccountId, data: CreateItemData) -> DispatchResult {1587        match data1588        {1589            CreateItemData::NFT(data) => {1590                let item = NftItemType {1591                    owner: owner.clone(),1592                    const_data: data.const_data,1593                    variable_data: data.variable_data1594                };15951596                Self::add_nft_item(collection, item)?;1597            },1598            CreateItemData::Fungible(data) => {1599                Self::add_fungible_item(collection, &owner, data.value)?;1600            },1601            CreateItemData::ReFungible(data) => {1602                let mut owner_list = Vec::new();1603                owner_list.push(Ownership {owner: owner.clone(), fraction: data.pieces});16041605                let item = ReFungibleItemType {1606                    owner: owner_list,1607                    const_data: data.const_data,1608                    variable_data: data.variable_data1609                };16101611                Self::add_refungible_item(collection, item)?;1612            }1613        };16141615        Ok(())1616    }16171618    fn add_fungible_item(collection: &CollectionHandle<T>, owner: &T::CrossAccountId, value: u128) -> DispatchResult {1619        let collection_id = collection.id;16201621        // Does new owner already have an account?1622        let balance: u128 = <FungibleItemList<T>>::get(collection_id, owner.as_sub()).value;16231624        // Mint 1625        let item = FungibleItemType {1626            value: balance.checked_add(value).ok_or(Error::<T>::NumOverflow)?,1627        };1628        <FungibleItemList<T>>::insert(collection_id, owner.as_sub(), item);16291630        // Update balance1631        let new_balance = <Balance<T>>::get(collection_id, owner.as_sub())1632            .checked_add(value)1633            .ok_or(Error::<T>::NumOverflow)?;1634        <Balance<T>>::insert(collection_id, owner.as_sub(), new_balance);16351636        Self::deposit_event(RawEvent::ItemCreated(collection_id, 0, owner.clone()));1637        Ok(())1638    }16391640    fn add_refungible_item(collection: &CollectionHandle<T>, item: ReFungibleItemType<T::CrossAccountId>) -> DispatchResult {1641        let collection_id = collection.id;16421643        let current_index = <ItemListIndex>::get(collection_id)1644            .checked_add(1)1645            .ok_or(Error::<T>::NumOverflow)?;1646        let itemcopy = item.clone();16471648        ensure!(1649            item.owner.len() == 1,1650            Error::<T>::BadCreateRefungibleCall,1651        );1652        let item_owner = item.owner.first().expect("only one owner is defined");16531654        let value = item_owner.fraction;1655        let owner = item_owner.owner.clone();16561657        Self::add_token_index(collection_id, current_index, &owner)?;16581659        <ItemListIndex>::insert(collection_id, current_index);1660        <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16611662        // Update balance1663        let new_balance = <Balance<T>>::get(collection_id, owner.as_sub())1664            .checked_add(value)1665            .ok_or(Error::<T>::NumOverflow)?;1666        <Balance<T>>::insert(collection_id, owner.as_sub(), new_balance);16671668        Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index, owner));1669        Ok(())1670    }16711672    fn add_nft_item(collection: &CollectionHandle<T>, item: NftItemType<T::CrossAccountId>) -> DispatchResult {1673        let collection_id = collection.id;16741675        let current_index = <ItemListIndex>::get(collection_id)1676            .checked_add(1)1677            .ok_or(Error::<T>::NumOverflow)?;16781679        let item_owner = item.owner.clone();1680        Self::add_token_index(collection_id, current_index, &item.owner)?;16811682        <ItemListIndex>::insert(collection_id, current_index);1683        <NftItemList<T>>::insert(collection_id, current_index, item);16841685        // Update balance1686        let new_balance = <Balance<T>>::get(collection_id, item_owner.as_sub())1687            .checked_add(1)1688            .ok_or(Error::<T>::NumOverflow)?;1689        <Balance<T>>::insert(collection_id, item_owner.as_sub(), new_balance);16901691        collection.log(ERC721Events::Transfer {1692            from: H160::default(),1693            to: *item_owner.as_eth(),1694            token_id: current_index.into(),1695        });1696        Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index, item_owner));1697        Ok(())1698    }16991700    fn burn_refungible_item(1701        collection: &CollectionHandle<T>,1702        item_id: TokenId,1703        owner: &T::CrossAccountId,1704    ) -> DispatchResult {1705        let collection_id = collection.id;17061707        let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id)1708            .ok_or(Error::<T>::TokenNotFound)?;1709        let rft_balance = token1710            .owner1711            .iter()1712            .find(|&i| i.owner == *owner)1713            .ok_or(Error::<T>::TokenNotFound)?;1714        Self::remove_token_index(collection_id, item_id, owner)?;17151716        // update balance1717        let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.as_sub())1718            .checked_sub(rft_balance.fraction)1719            .ok_or(Error::<T>::NumOverflow)?;1720        <Balance<T>>::insert(collection_id, rft_balance.owner.as_sub(), new_balance);17211722        // Re-create owners list with sender removed1723        let index = token1724            .owner1725            .iter()1726            .position(|i| i.owner == *owner)1727            .expect("owned item is exists");1728        token.owner.remove(index);1729        let owner_count = token.owner.len();17301731        // Burn the token completely if this was the last (only) owner1732        if owner_count == 0 {1733            <ReFungibleItemList<T>>::remove(collection_id, item_id);1734            <VariableMetaDataBasket<T>>::remove(collection_id, item_id);1735        }1736        else {1737            <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1738        }17391740        Ok(())1741    }17421743    fn burn_nft_item(collection: &CollectionHandle<T>, item_id: TokenId) -> DispatchResult {1744        let collection_id = collection.id;17451746        let item = <NftItemList<T>>::get(collection_id, item_id)1747            .ok_or(Error::<T>::TokenNotFound)?;1748        Self::remove_token_index(collection_id, item_id, &item.owner)?;17491750        // update balance1751        let new_balance = <Balance<T>>::get(collection_id, item.owner.as_sub())1752            .checked_sub(1)1753            .ok_or(Error::<T>::NumOverflow)?;1754        <Balance<T>>::insert(collection_id, item.owner.as_sub(), new_balance);1755        <NftItemList<T>>::remove(collection_id, item_id);1756        <VariableMetaDataBasket<T>>::remove(collection_id, item_id);17571758        Self::deposit_event(RawEvent::ItemDestroyed(collection.id, item_id));1759        Ok(())1760    }17611762    fn burn_fungible_item(owner: &T::CrossAccountId, collection: &CollectionHandle<T>, value: u128) -> DispatchResult {1763        let collection_id = collection.id;17641765        let mut balance = <FungibleItemList<T>>::get(collection_id, owner.as_sub());1766        ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);17671768        // update balance1769        let new_balance = <Balance<T>>::get(collection_id, owner.as_sub())1770            .checked_sub(value)1771            .ok_or(Error::<T>::NumOverflow)?;1772        <Balance<T>>::insert(collection_id, owner.as_sub(), new_balance);17731774        if balance.value - value > 0 {1775            balance.value -= value;1776            <FungibleItemList<T>>::insert(collection_id, owner.as_sub(), balance);1777        }1778        else {1779            <FungibleItemList<T>>::remove(collection_id, owner.as_sub());1780        }17811782        collection.log(ERC20Events::Transfer {1783            from: *owner.as_eth(),1784            to: H160::default(),1785            value: value.into(),1786        });1787        Ok(())1788    }17891790    pub fn get_collection(collection_id: CollectionId) -> Result<CollectionHandle<T>, sp_runtime::DispatchError> {1791        Ok(<CollectionHandle<T>>::get(collection_id)1792            .ok_or(Error::<T>::CollectionNotFound)?)1793    }17941795    fn save_collection(collection: CollectionHandle<T>) {1796        <CollectionById<T>>::insert(collection.id, collection.into_inner());1797    }17981799    pub fn submit_logs(collection: CollectionHandle<T>) -> DispatchResult {1800        if collection.logs.is_empty() {1801            return Ok(())1802        }1803        T::EthereumTransactionSender::submit_logs_transaction(1804            eth::generate_transaction(collection.id, T::EthereumChainId::get()),1805            collection.logs.retrieve_logs(),1806        )1807    }18081809    fn check_owner_permissions(target_collection: &CollectionHandle<T>, subject: &T::AccountId) -> DispatchResult {1810        ensure!(1811            *subject == target_collection.owner,1812            Error::<T>::NoPermission1813        );18141815        Ok(())1816    }18171818    fn is_owner_or_admin_permissions(collection: &CollectionHandle<T>, subject: &T::CrossAccountId) -> bool {1819        *subject.as_sub() == collection.owner || <AdminList<T>>::get(collection.id).contains(&subject)1820    }18211822    fn check_owner_or_admin_permissions(1823        collection: &CollectionHandle<T>,1824        subject: &T::CrossAccountId,1825    ) -> DispatchResult {1826        ensure!(Self::is_owner_or_admin_permissions(collection, subject), Error::<T>::NoPermission);18271828        Ok(())1829    }18301831    fn owned_amount(1832        subject: &T::CrossAccountId,1833        target_collection: &CollectionHandle<T>,1834        item_id: TokenId,1835    ) -> Option<u128> {1836        let collection_id = target_collection.id;18371838        match target_collection.mode {1839            CollectionMode::NFT => (<NftItemList<T>>::get(collection_id, item_id)?.owner == *subject)1840                .then(|| 1),1841            CollectionMode::Fungible(_) => Some(<FungibleItemList<T>>::get(collection_id, &subject.as_sub())1842                .value),1843            CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection_id, item_id)?1844                .owner1845                .iter()1846                .find(|i| i.owner == *subject)1847                .map(|i| i.fraction),1848            CollectionMode::Invalid => None,1849        }1850    }18511852    fn is_item_owner(subject: &T::CrossAccountId, target_collection: &CollectionHandle<T>, item_id: TokenId) -> bool {1853        match target_collection.mode {1854            CollectionMode::Fungible(_) => true,1855            _ => Self::owned_amount(&subject, target_collection, item_id).is_some(),1856        }1857    }18581859    fn check_white_list(collection: &CollectionHandle<T>, address: &T::CrossAccountId) -> DispatchResult {1860        let collection_id = collection.id;18611862        let mes = Error::<T>::AddresNotInWhiteList;1863        ensure!(<WhiteList<T>>::contains_key(collection_id, address.as_sub()), mes);18641865        Ok(())1866    }18671868    /// Check if token exists. In case of Fungible, check if there is an entry for 1869    /// the owner in fungible balances double map1870    fn token_exists(1871        target_collection: &CollectionHandle<T>,1872        item_id: TokenId,1873    ) -> DispatchResult {1874        let collection_id = target_collection.id;1875        let exists = match target_collection.mode1876        {1877            CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),1878            CollectionMode::Fungible(_)  => true,1879            CollectionMode::ReFungible  => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1880            _ => false1881        };18821883        ensure!(exists == true, Error::<T>::TokenNotFound);1884        Ok(())1885    }18861887    fn transfer_fungible(1888        collection: &CollectionHandle<T>,1889        value: u128,1890        owner: &T::CrossAccountId,1891        recipient: &T::CrossAccountId,1892    ) -> DispatchResult {1893        let collection_id = collection.id;18941895        let mut balance = <FungibleItemList<T>>::get(collection_id, owner.as_sub());1896        ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);18971898        // Send balance to recipient (updates balanceOf of recipient)1899        Self::add_fungible_item(collection, recipient, value)?;19001901        // update balanceOf of sender1902        <Balance<T>>::insert(collection_id, owner.as_sub(), balance.value - value);19031904        // Reduce or remove sender1905        if balance.value == value {1906            <FungibleItemList<T>>::remove(collection_id, owner.as_sub());1907        }1908        else {1909            balance.value -= value;1910            <FungibleItemList<T>>::insert(collection_id, owner.as_sub(), balance);1911        }19121913        collection.log(ERC20Events::Transfer {1914            from: *owner.as_eth(),1915            to: *recipient.as_eth(),1916            value: value.into(),1917        });1918        Self::deposit_event(RawEvent::Transfer(collection.id, 1, owner.clone(), recipient.clone(), value));19191920        Ok(())1921    }19221923    fn transfer_refungible(1924        collection: &CollectionHandle<T>,1925        item_id: TokenId,1926        value: u128,1927        owner: T::CrossAccountId,1928        new_owner: T::CrossAccountId,1929    ) -> DispatchResult {1930        let collection_id = collection.id;1931        let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id)1932            .ok_or(Error::<T>::TokenNotFound)?;19331934        let item = full_item1935            .owner1936            .iter()1937            .filter(|i| i.owner == owner)1938            .next()1939            .ok_or(Error::<T>::TokenNotFound)?;1940        let amount = item.fraction;19411942        ensure!(amount >= value, Error::<T>::TokenValueTooLow);19431944        // update balance1945        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.as_sub())1946            .checked_sub(value)1947            .ok_or(Error::<T>::NumOverflow)?;1948        <Balance<T>>::insert(collection_id, item.owner.as_sub(), balance_old_owner);19491950        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.as_sub())1951            .checked_add(value)1952            .ok_or(Error::<T>::NumOverflow)?;1953        <Balance<T>>::insert(collection_id, new_owner.as_sub(), balance_new_owner);19541955        let old_owner = item.owner.clone();1956        let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19571958        // transfer1959        if amount == value && !new_owner_has_account {1960            // change owner1961            // new owner do not have account1962            let mut new_full_item = full_item.clone();1963            new_full_item1964                .owner1965                .iter_mut()1966                .find(|i| i.owner == owner)1967                .expect("old owner does present in refungible")1968                .owner = new_owner.clone();1969            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19701971            // update index collection1972            Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;1973        } else {1974            let mut new_full_item = full_item.clone();1975            new_full_item1976                .owner1977                .iter_mut()1978                .find(|i| i.owner == owner)1979                .expect("old owner does present in refungible")1980                .fraction -= value;19811982            // separate amount1983            if new_owner_has_account {1984                // new owner has account1985                new_full_item1986                    .owner1987                    .iter_mut()1988                    .find(|i| i.owner == new_owner)1989                    .expect("new owner has account")1990                    .fraction += value;1991            } else {1992                // new owner do not have account1993                new_full_item.owner.push(Ownership {1994                    owner: new_owner.clone(),1995                    fraction: value,1996                });1997                Self::add_token_index(collection_id, item_id, &new_owner)?;1998            }19992000            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2001        }20022003        Self::deposit_event(RawEvent::Transfer(collection.id, item_id, owner, new_owner, amount));20042005        Ok(())2006    }20072008    fn transfer_nft(2009        collection: &CollectionHandle<T>,2010        item_id: TokenId,2011        sender: T::CrossAccountId,2012        new_owner: T::CrossAccountId,2013    ) -> DispatchResult {2014        let collection_id = collection.id;2015        let mut item = <NftItemList<T>>::get(collection_id, item_id)2016            .ok_or(Error::<T>::TokenNotFound)?;20172018        ensure!(2019            sender == item.owner,2020            Error::<T>::MustBeTokenOwner2021        );20222023        // update balance2024        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.as_sub())2025            .checked_sub(1)2026            .ok_or(Error::<T>::NumOverflow)?;2027        <Balance<T>>::insert(collection_id, item.owner.as_sub(), balance_old_owner);20282029        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.as_sub())2030            .checked_add(1)2031            .ok_or(Error::<T>::NumOverflow)?;2032        <Balance<T>>::insert(collection_id, new_owner.as_sub(), balance_new_owner);20332034        // change owner2035        let old_owner = item.owner.clone();2036        item.owner = new_owner.clone();2037        <NftItemList<T>>::insert(collection_id, item_id, item);20382039        // update index collection2040        Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;20412042        collection.log(ERC721Events::Transfer {2043            from: *sender.as_eth(),2044            to: *new_owner.as_eth(),2045            token_id: item_id.into(),2046        });2047        Self::deposit_event(RawEvent::Transfer(collection.id, item_id, sender, new_owner, 1));20482049        Ok(())2050    }2051    2052    fn set_re_fungible_variable_data(2053        collection: &CollectionHandle<T>,2054        item_id: TokenId,2055        data: Vec<u8>2056    ) -> DispatchResult {2057        let collection_id = collection.id;2058        let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id)2059            .ok_or(Error::<T>::TokenNotFound)?;20602061        item.variable_data = data;20622063        <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20642065        Ok(())2066    }20672068    fn set_nft_variable_data(2069        collection: &CollectionHandle<T>,2070        item_id: TokenId,2071        data: Vec<u8>2072    ) -> DispatchResult {2073        let collection_id = collection.id;2074        let mut item = <NftItemList<T>>::get(collection_id, item_id)2075            .ok_or(Error::<T>::TokenNotFound)?;2076        2077        item.variable_data = data;20782079        <NftItemList<T>>::insert(collection_id, item_id, item);2080        2081        Ok(())2082    }20832084    #[allow(dead_code)]2085    fn init_collection(item: &Collection<T>) {2086        // check params2087        assert!(2088            item.decimal_points <= MAX_DECIMAL_POINTS,2089            "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2090        );2091        assert!(2092            item.name.len() <= 64,2093            "Collection name can not be longer than 63 char"2094        );2095        assert!(2096            item.name.len() <= 256,2097            "Collection description can not be longer than 255 char"2098        );2099        assert!(2100            item.token_prefix.len() <= 16,2101            "Token prefix can not be longer than 15 char"2102        );21032104        // Generate next collection ID2105        let next_id = CreatedCollectionCount::get()2106            .checked_add(1)2107            .unwrap();21082109        CreatedCollectionCount::put(next_id);2110    }21112112    #[allow(dead_code)]2113    fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::CrossAccountId>) {2114        let current_index = <ItemListIndex>::get(collection_id)2115            .checked_add(1)2116            .unwrap();21172118        Self::add_token_index(collection_id, current_index, &item.owner).unwrap();21192120        <ItemListIndex>::insert(collection_id, current_index);21212122        // Update balance2123        let new_balance = <Balance<T>>::get(collection_id, item.owner.as_sub())2124            .checked_add(1)2125            .unwrap();2126        <Balance<T>>::insert(collection_id, item.owner.as_sub(), new_balance);2127    }21282129    #[allow(dead_code)]2130    fn init_fungible_token(collection_id: CollectionId, owner: &T::CrossAccountId, item: &FungibleItemType) {2131        let current_index = <ItemListIndex>::get(collection_id)2132            .checked_add(1)2133            .unwrap();21342135        Self::add_token_index(collection_id, current_index, owner).unwrap();21362137        <ItemListIndex>::insert(collection_id, current_index);21382139        // Update balance2140        let new_balance = <Balance<T>>::get(collection_id, owner.as_sub())2141            .checked_add(item.value)2142            .unwrap();2143        <Balance<T>>::insert(collection_id, owner.as_sub(), new_balance);2144    }21452146    #[allow(dead_code)]2147    fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::CrossAccountId>) {2148        let current_index = <ItemListIndex>::get(collection_id)2149            .checked_add(1)2150            .unwrap();21512152        let value = item.owner.first().unwrap().fraction;2153        let owner = item.owner.first().unwrap().owner.clone();21542155        Self::add_token_index(collection_id, current_index, &owner).unwrap();21562157        <ItemListIndex>::insert(collection_id, current_index);21582159        // Update balance2160        let new_balance = <Balance<T>>::get(collection_id, &owner.as_sub())2161            .checked_add(value)2162            .unwrap();2163        <Balance<T>>::insert(collection_id, owner.as_sub(), new_balance);2164    }21652166    fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::CrossAccountId) -> DispatchResult {2167        // add to account limit2168        if <AccountItemCount<T>>::contains_key(owner.as_sub()) {21692170            // bound Owned tokens by a single address2171            let count = <AccountItemCount<T>>::get(owner.as_sub());2172            ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21732174            <AccountItemCount<T>>::insert(owner.as_sub(), count2175                .checked_add(1)2176                .ok_or(Error::<T>::NumOverflow)?);2177        }2178        else {2179            <AccountItemCount<T>>::insert(owner.as_sub(), 1);2180        }21812182        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.as_sub());2183        if list_exists {2184            let mut list = <AddressTokens<T>>::get(collection_id, owner.as_sub());2185            let item_contains = list.contains(&item_index.clone());21862187            if !item_contains {2188                list.push(item_index.clone());2189            }21902191            <AddressTokens<T>>::insert(collection_id, owner.as_sub(), list);2192        } else {2193            let mut itm = Vec::new();2194            itm.push(item_index.clone());2195            <AddressTokens<T>>::insert(collection_id, owner.as_sub(), itm);2196        }21972198        Ok(())2199    }22002201    fn remove_token_index(2202        collection_id: CollectionId,2203        item_index: TokenId,2204        owner: &T::CrossAccountId,2205    ) -> DispatchResult {22062207        // update counter2208        <AccountItemCount<T>>::insert(owner.as_sub(), 2209            <AccountItemCount<T>>::get(owner.as_sub())2210            .checked_sub(1)2211            .ok_or(Error::<T>::NumOverflow)?);221222132214        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.as_sub());2215        if list_exists {2216            let mut list = <AddressTokens<T>>::get(collection_id, owner.as_sub());2217            let item_contains = list.contains(&item_index.clone());22182219            if item_contains {2220                list.retain(|&item| item != item_index);2221                <AddressTokens<T>>::insert(collection_id, owner.as_sub(), list);2222            }2223        }22242225        Ok(())2226    }22272228    fn move_token_index(2229        collection_id: CollectionId,2230        item_index: TokenId,2231        old_owner: &T::CrossAccountId,2232        new_owner: &T::CrossAccountId,2233    ) -> DispatchResult {2234        Self::remove_token_index(collection_id, item_index, old_owner)?;2235        Self::add_token_index(collection_id, item_index, new_owner)?;22362237        Ok(())2238    }2239}22402241sp_api::decl_runtime_apis! {2242    pub trait NftApi {2243        /// Used for ethereum integration2244        fn eth_contract_code(account: H160) -> Option<Vec<u8>>;2245    }2246}
modifiedpallets/nft/src/mock.rsdiffbeforeafterboth
--- a/pallets/nft/src/mock.rs
+++ b/pallets/nft/src/mock.rs
@@ -11,6 +11,9 @@
 };
 use pallet_transaction_payment::{ CurrencyAdapter};
 use frame_system as system;
+use pallet_evm::AddressMapping;
+use crate::{EvmBackwardsAddressMapping, CrossAccountId};
+use codec::{Encode, Decode};
 
 type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
 type Block = frame_system::mocking::MockBlock<Test>; 
@@ -22,9 +25,9 @@
 		NodeBlock = Block,
 		UncheckedExtrinsic = UncheckedExtrinsic,
 	{
-		System: frame_system::{Module, Call, Config, Storage, Event<T>},
-		TemplateModule: pallet_template::{Module, Call, Storage},
-		Balances: pallet_balances::{Module, Call, Storage},
+		System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
+		TemplateModule: pallet_template::{Pallet, Call, Storage},
+		Balances: pallet_balances::{Pallet, Call, Storage},
 	}
 );
 
@@ -56,6 +59,7 @@
 	type OnKilledAccount = ();
 	type SystemWeightInfo = ();
 	type SS58Prefix = SS58Prefix;
+    type OnSetCode = ();
 }
 
 parameter_types! {
@@ -78,7 +82,7 @@
 }
 
 impl pallet_transaction_payment::Config for Test {
-	type OnChargeTransaction = CurrencyAdapter<pallet_balances::Module<Test>, ()>;
+	type OnChargeTransaction = CurrencyAdapter<pallet_balances::Pallet<Test>, ()>;
 	type TransactionByteFee = TransactionByteFee;
 	type WeightToFee = IdentityFee<u64>;
 	type FeeMultiplierUpdate = ();
@@ -94,27 +98,26 @@
 	type WeightInfo = ();
 }
 
-type Timestamp = pallet_timestamp::Module<Test>;
-type Randomness = pallet_randomness_collective_flip::Module<Test>;
+type Timestamp = pallet_timestamp::Pallet<Test>;
+type Randomness = pallet_randomness_collective_flip::Pallet<Test>;
 
 parameter_types! {
 	pub const TombstoneDeposit: u64 = 1;
 	pub const DepositPerContract: u64 = 1;
 	pub const DepositPerStorageByte: u64 = 1;
 	pub const DepositPerStorageItem: u64 = 1;
-	pub RentFraction: Perbill = Perbill::from_rational_approximation(1u32, 30 * 24 * 60 * 10);
+	pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * 24 * 60 * 10);
 	pub const SurchargeReward: u64 = 1;
 	pub const SignedClaimHandicap: u32 = 2;
-	pub const MaxDepth: u32 = 32;
-	pub const MaxValueSize: u32 = 16 * 1024;
 	pub DeletionWeightLimit: u64 = u64::MAX;//Perbill::from_percent(10);
 	pub DeletionQueueDepth: u32 = 10;
+	pub Schedule: pallet_contracts::Schedule<Test> = Default::default();
 }
 
 impl pallet_contracts::Config for Test {
 	type Time = Timestamp;
 	type Randomness = Randomness;
-	type Currency = pallet_balances::Module<Test>;
+	type Currency = pallet_balances::Pallet<Test>;
 	type Event = ();
 	type RentPayment = ();
 	type SignedClaimHandicap = SignedClaimHandicap;
@@ -125,26 +128,71 @@
 	type RentFraction = RentFraction;
 	type SurchargeReward = SurchargeReward;
 	type DeletionWeightLimit = DeletionWeightLimit;
-	type MaxDepth = MaxDepth;
 	type DeletionQueueDepth = DeletionQueueDepth;
-	type MaxValueSize = MaxValueSize;
 	type ChainExtension = ();
-	type MaxCodeSize = ();
 	type WeightPrice = ();
 	type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;
+    type Schedule = Schedule;
+    type CallStack = [pallet_contracts::Frame<Self>; 31];
 }
 
 parameter_types! {
 	pub const CollectionCreationPrice: u32 = 0;
     pub TreasuryAccountId: u64 = 1234;
+    pub EthereumChainId: u32 = 1111;
+}
+
+pub struct TestEvmAddressMapping;
+impl AddressMapping<u64> for TestEvmAddressMapping {
+    fn into_account_id(addr: sp_core::H160) -> u64 {
+        unimplemented!()
+    }
+}
+
+pub struct TestEvmBackwardsAddressMapping;
+impl EvmBackwardsAddressMapping<u64> for TestEvmBackwardsAddressMapping {
+    fn from_account_id(account_id: u64) -> sp_core::H160 {
+        unimplemented!()
+    }
+}
+
+#[derive(Encode, Decode, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub struct TestCrossAccountId(u64, sp_core::H160);
+impl CrossAccountId<u64> for TestCrossAccountId {
+    fn from_sub(sub: u64) -> Self {
+        let mut eth = [0; 20];
+        eth[12..20].copy_from_slice(&sub.to_be_bytes());
+        Self(sub, sp_core::H160(eth))
+    }
+    fn as_sub(&self) -> &u64 {
+        &self.0
+    }
+    fn from_eth(eth: sp_core::H160) -> Self {
+        unimplemented!()
+    }
+    fn as_eth(&self) -> &sp_core::H160 {
+        &self.1
+    }
 }
 
+pub struct TestEtheremTransactionSender;
+impl pallet_ethereum::EthereumTransactionSender for TestEtheremTransactionSender {
+    fn submit_logs_transaction(tx: pallet_ethereum::Transaction, logs: Vec<pallet_ethereum::Log>) -> Result<(), sp_runtime::DispatchError> {
+        Ok(())
+    }
+}
+
 impl pallet_template::Config for Test {
 	type Event = ();
 	type WeightInfo = ();
 	type CollectionCreationPrice = CollectionCreationPrice;
-    type Currency = pallet_balances::Module<Test>;
+    type Currency = pallet_balances::Pallet<Test>;
     type TreasuryAccountId = TreasuryAccountId;
+    type EvmAddressMapping = TestEvmAddressMapping;
+    type EvmBackwardsAddressMapping = TestEvmBackwardsAddressMapping;
+    type CrossAccountId = TestCrossAccountId;
+    type EthereumChainId = EthereumChainId;
+    type EthereumTransactionSender = TestEtheremTransactionSender;
 }
 
 // Build genesis storage according to the mock runtime.
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -1,9 +1,14 @@
 // Tests to be written here
 use super::*;
 use crate::mock::*;
-use crate::{AccessMode, CollectionMode,
-    Ownership, ChainLimits, CreateItemData, CreateNftData, CreateFungibleData, CreateReFungibleData,
-    CollectionId, TokenId, MAX_DECIMAL_POINTS};
+use crate::{
+    AccessMode, CollectionMode,
+    Ownership, ChainLimits, CreateItemData,
+};
+use nft_data_structs::{
+    CreateNftData, CreateFungibleData, CreateReFungibleData,
+    CollectionId, TokenId, MAX_DECIMAL_POINTS,
+};
 use frame_support::{assert_noop, assert_ok};
 use frame_system::{ RawOrigin };
 
@@ -72,12 +77,16 @@
     assert_ok!(TemplateModule::create_item(
             origin1.clone(),
             collection_id,
-            1,
+            account(1),
             data.clone()
         ));
 
 }
 
+fn account(sub: u64) -> TestCrossAccountId {
+    TestCrossAccountId::from_sub(sub)
+}
+
 // Use cases tests region
 // #region
 
@@ -142,8 +151,8 @@
 
         assert_ok!(TemplateModule::create_multiple_items(
             origin1.clone(),
-            1,
             1,
+            account(1),
             items_data.clone().into_iter().map(|d| { d.into() }).collect()
         ));
         for (index, data) in items_data.iter().enumerate() {
@@ -174,7 +183,7 @@
         assert_eq!(
             item.owner[0],
             Ownership {
-                owner: 1,
+                owner: account(1),
                 fraction: 1023
             }
         );
@@ -195,7 +204,7 @@
         assert_ok!(TemplateModule::create_multiple_items(
             origin1.clone(),
             1,
-            1,
+            account(1),
             items_data.clone().into_iter().map(|d| { d.into() }).collect()
         ));
         for (index, data) in items_data.iter().enumerate() {
@@ -206,7 +215,7 @@
             assert_eq!(
                 item.owner[0],
                 Ownership {
-                    owner: 1,
+                    owner: account(1),
                     fraction: 1023
                 }
             );
@@ -271,18 +280,18 @@
         assert_eq!(TemplateModule::balance_count(1, 1), 5);
 
         // change owner scenario
-        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 5));
+        assert_ok!(TemplateModule::transfer(origin1.clone(), account(2), 1, 1, 5));
         assert_eq!(TemplateModule::fungible_item_id(1, 1).value, 0);
         assert_eq!(TemplateModule::balance_count(1, 1), 0);
         assert_eq!(TemplateModule::balance_count(1, 2), 5);
 
         // split item scenario
-        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 3));
+        assert_ok!(TemplateModule::transfer(origin2.clone(), account(3), 1, 1, 3));
         assert_eq!(TemplateModule::balance_count(1, 2), 2);
         assert_eq!(TemplateModule::balance_count(1, 3), 3);
 
         // split item and new owner has account scenario
-        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 1));
+        assert_ok!(TemplateModule::transfer(origin2.clone(), account(3), 1, 1, 1));
         assert_eq!(TemplateModule::fungible_item_id(1, 2).value, 1);
         assert_eq!(TemplateModule::fungible_item_id(1, 3).value, 4);
         assert_eq!(TemplateModule::balance_count(1, 2), 1);
@@ -315,7 +324,7 @@
             assert_eq!(
                 item.owner[0],
                 Ownership {
-                    owner: 1,
+                    owner: account(1),
                     fraction: 1023
                 }
             );
@@ -324,11 +333,11 @@
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
 
         // change owner scenario
-        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1023));
+        assert_ok!(TemplateModule::transfer(origin1.clone(), account(2), 1, 1, 1023));
         assert_eq!(
             TemplateModule::refungible_item_id(1, 1).unwrap().owner[0],
             Ownership {
-                owner: 2,
+                owner: account(2),
                 fraction: 1023
             }
         );
@@ -338,20 +347,20 @@
         assert_eq!(TemplateModule::address_tokens(1, 2), [1]);
 
         // split item scenario
-        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 500));
+        assert_ok!(TemplateModule::transfer(origin2.clone(), account(3), 1, 1, 500));
         {
             let item = TemplateModule::refungible_item_id(1, 1).unwrap();
             assert_eq!(
                 item.owner[0],
                 Ownership {
-                    owner: 2,
+                    owner: account(2),
                     fraction: 523
                 }
             );
             assert_eq!(
                 item.owner[1],
                 Ownership {
-                    owner: 3,
+                    owner: account(3),
                     fraction: 500
                 }
             );
@@ -362,20 +371,20 @@
         assert_eq!(TemplateModule::address_tokens(1, 3), [1]);
 
         // split item and new owner has account scenario
-        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 200));
+        assert_ok!(TemplateModule::transfer(origin2.clone(), account(3), 1, 1, 200));
         {
             let item = TemplateModule::refungible_item_id(1, 1).unwrap();
             assert_eq!(
                 item.owner[0],
                 Ownership {
-                    owner: 2,
+                    owner: account(2),
                     fraction: 323
                 }
             );
             assert_eq!(
                 item.owner[1],
                 Ownership {
-                    owner: 3,
+                    owner: account(3),
                     fraction: 700
                 }
             );
@@ -401,8 +410,8 @@
 
         let origin1 = Origin::signed(1);
         // default scenario
-        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));
-        assert_eq!(TemplateModule::nft_item_id(1, 1).unwrap().owner, 2);
+        assert_ok!(TemplateModule::transfer(origin1.clone(), account(2), 1, 1, 1000));
+        assert_eq!(TemplateModule::nft_item_id(1, 1).unwrap().owner, account(2));
         assert_eq!(TemplateModule::balance_count(1, 1), 0);
         assert_eq!(TemplateModule::balance_count(1, 2), 1);
         // assert_eq!(TemplateModule::address_tokens(1, 1), []);
@@ -429,14 +438,14 @@
         // neg transfer
         assert_noop!(TemplateModule::transfer_from(
             origin2.clone(),
-            1,
-            2,
+            account(1),
+            account(2),
             1,
             1,
             1), Error::<Test>::NoPermission);
 
         // do approve
-        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));
+        assert_ok!(TemplateModule::approve(origin1.clone(), account(2), 1, 1, 5));
         assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);
         assert_eq!(
             TemplateModule::approved(1, (1, 1, 2)),
@@ -445,8 +454,8 @@
 
         assert_ok!(TemplateModule::transfer_from(
             origin2.clone(),
-            1,
-            3,
+            account(1),
+            account(3),
             1,
             1,
             1
@@ -482,20 +491,20 @@
             1,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(1)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(2)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(3)));
 
         // do approve
-        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));
+        assert_ok!(TemplateModule::approve(origin1.clone(), account(2), 1, 1, 5));
         assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);
-        assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1, 5));
+        assert_ok!(TemplateModule::approve(origin1.clone(), account(3), 1, 1, 5));
         assert_eq!(TemplateModule::approved(1, (1, 1, 3)), 5);
 
         assert_ok!(TemplateModule::transfer_from(
             origin2.clone(),
-            1,
-            3,
+            account(1),
+            account(3),
             1,
             1,
             1
@@ -530,18 +539,18 @@
             1,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(1)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(2)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(3)));
 
         // do approve
-        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1023));
+        assert_ok!(TemplateModule::approve(origin1.clone(), account(2), 1, 1, 1023));
         assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1023);
 
         assert_ok!(TemplateModule::transfer_from(
             origin2.clone(),
-            1,
-            3,
+            account(1),
+            account(3),
             1,
             1,
             100
@@ -583,14 +592,14 @@
             1,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(1)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(2)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(3)));
 
         // do approve
-        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));
+        assert_ok!(TemplateModule::approve(origin1.clone(), account(2), 1, 1, 5));
         assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);
-        assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1, 5));
+        assert_ok!(TemplateModule::approve(origin1.clone(), account(3), 1, 1, 5));
         assert_eq!(TemplateModule::approved(1, (1, 1, 3)), 5);
         assert_eq!(
             TemplateModule::approved(1, (1, 1, 2)),
@@ -599,9 +608,9 @@
 
         assert_ok!(TemplateModule::transfer_from(
             origin2.clone(),
+            account(1),
+            account(3),
             1,
-            3,
-            1,
             1,
             4
         ));
@@ -612,9 +621,9 @@
 
         assert_noop!(TemplateModule::transfer_from(
             origin2.clone(),
+            account(1),
+            account(3),
             1,
-            3,
-            1,
             1,
             4
         ), Error::<Test>::NoPermission);
@@ -658,7 +667,7 @@
         let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, account(2)));
         
         let data = default_nft_data();
         create_test_item(collection_id, &data.into());
@@ -685,7 +694,7 @@
         let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);
         
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, account(2)));
         
         let data = default_fungible_data();
         create_test_item(collection_id, &data.into());
@@ -722,9 +731,9 @@
             collection_id,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(1)));
 
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, account(2)));
         
         let data = default_re_fungible_data();
         create_test_item(collection_id, &data.into());
@@ -755,11 +764,11 @@
         let origin1 = Origin::signed(1);
 
         // collection admin
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 2));
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 3));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, account(2)));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, account(3)));
 
-        assert_eq!(TemplateModule::admin_list_collection(collection1_id).contains(&2), true);
-        assert_eq!(TemplateModule::admin_list_collection(collection1_id).contains(&3), true);
+        assert_eq!(TemplateModule::admin_list_collection(collection1_id).contains(&account(2)), true);
+        assert_eq!(TemplateModule::admin_list_collection(collection1_id).contains(&account(3)), true);
     });
 }
 
@@ -776,19 +785,19 @@
         let origin2 = Origin::signed(2);
 
         // collection admin
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 2));
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 3));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, account(2)));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, account(3)));
 
-        assert_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);
-        assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);
+        assert_eq!(TemplateModule::admin_list_collection(1).contains(&account(2)), true);
+        assert_eq!(TemplateModule::admin_list_collection(1).contains(&account(3)), true);
 
         // remove admin
         assert_ok!(TemplateModule::remove_collection_admin(
             origin2.clone(),
             1,
-            3
+            account(3)
         ));
-        assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), false);
+        assert_eq!(TemplateModule::admin_list_collection(1).contains(&account(3)), false);
     });
 }
 
@@ -819,9 +828,9 @@
         assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 1);
         assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 5);
         assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 1023);
-        assert_eq!(TemplateModule::nft_item_id(nft_collection_id, 1).unwrap().owner, 1);
+        assert_eq!(TemplateModule::nft_item_id(nft_collection_id, 1).unwrap().owner, account(1));
         assert_eq!(TemplateModule::fungible_item_id(fungible_collection_id, 1).value, 5);
-        assert_eq!(TemplateModule::refungible_item_id(re_fungible_collection_id, 1).unwrap().owner[0].owner, 1);
+        assert_eq!(TemplateModule::refungible_item_id(re_fungible_collection_id, 1).unwrap().owner[0].owner, account(1));
     });
 }
 
@@ -838,7 +847,7 @@
         let origin1 = Origin::signed(1);
         
         // approve
-        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1));
+        assert_ok!(TemplateModule::approve(origin1.clone(), account(2), 1, 1, 1));
         assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1);
     });
 }
@@ -856,7 +865,7 @@
         create_test_item(collection_id, &data.into());
 
         // approve
-        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1));
+        assert_ok!(TemplateModule::approve(origin1.clone(), account(2), 1, 1, 1));
         assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1);
 
         assert_ok!(TemplateModule::set_mint_permission(
@@ -869,14 +878,14 @@
             1,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(1)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(2)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(3)));
 
         assert_ok!(TemplateModule::transfer_from(
             origin2.clone(),
-            1,
-            2,
+            account(1),
+            account(2),
             1,
             1,
             1
@@ -901,7 +910,7 @@
         let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
         assert_eq!(TemplateModule::white_list(collection_id, 2), true);
     });
 }
@@ -915,8 +924,8 @@
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
 
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
-        assert_ok!(TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, account(2)));
+        assert_ok!(TemplateModule::add_to_white_list(origin2.clone(), collection_id, account(3)));
         assert_eq!(TemplateModule::white_list(collection_id, 3), true);
     });
 }
@@ -930,7 +939,7 @@
 
         let origin2 = Origin::signed(2);
         assert_noop!(
-            TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3),
+            TemplateModule::add_to_white_list(origin2.clone(), collection_id, account(3)),
             Error::<Test>::NoPermission
         );
     });
@@ -944,7 +953,7 @@
         let origin1 = Origin::signed(1);
 
         assert_noop!(
-            TemplateModule::add_to_white_list(origin1.clone(), 1, 2),
+            TemplateModule::add_to_white_list(origin1.clone(), 1, account(2)),
             Error::<Test>::CollectionNotFound
         );
     });
@@ -960,7 +969,7 @@
         let origin1 = Origin::signed(1);
         assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));
         assert_noop!(
-            TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2),
+            TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)),
             Error::<Test>::CollectionNotFound
         );
     });
@@ -975,8 +984,8 @@
         let collection_id = create_test_collection(&CollectionMode::NFT, 1);
         let origin1 = Origin::signed(1);
         
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
         assert_eq!(TemplateModule::white_list(collection_id, 2), true);
     });
 }
@@ -989,11 +998,11 @@
         let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
         assert_ok!(TemplateModule::remove_from_white_list(
             origin1.clone(),
             collection_id,
-            2
+            account(2)
         ));
         assert_eq!(TemplateModule::white_list(collection_id, 2), false);
     });
@@ -1008,13 +1017,13 @@
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
 
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, account(2)));
 
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 3));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(3)));
         assert_ok!(TemplateModule::remove_from_white_list(
             origin2.clone(),
             collection_id,
-            3
+            account(3)
         ));
         assert_eq!(TemplateModule::white_list(collection_id, 3), false);
     });
@@ -1029,9 +1038,9 @@
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
 
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
         assert_noop!(
-            TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),
+            TemplateModule::remove_from_white_list(origin2.clone(), collection_id, account(2)),
             Error::<Test>::NoPermission
         );
         assert_eq!(TemplateModule::white_list(collection_id, 2), true);
@@ -1045,7 +1054,7 @@
         let origin1 = Origin::signed(1);
 
         assert_noop!(
-            TemplateModule::remove_from_white_list(origin1.clone(), 1, 2),
+            TemplateModule::remove_from_white_list(origin1.clone(), 1, account(2)),
             Error::<Test>::CollectionNotFound
         );
     });
@@ -1060,10 +1069,10 @@
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
 
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
         assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));
         assert_noop!(
-            TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),
+            TemplateModule::remove_from_white_list(origin2.clone(), collection_id, account(2)),
             Error::<Test>::CollectionNotFound
         );
         assert_eq!(TemplateModule::white_list(collection_id, 2), false);
@@ -1079,16 +1088,16 @@
         let collection_id = create_test_collection(&CollectionMode::NFT, 1);
         let origin1 = Origin::signed(1);
 
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
         assert_ok!(TemplateModule::remove_from_white_list(
             origin1.clone(),
             collection_id,
-            2
+            account(2)
         ));
         assert_ok!(TemplateModule::remove_from_white_list(
             origin1.clone(),
             collection_id,
-            2
+            account(2)
         ));
         assert_eq!(TemplateModule::white_list(collection_id, 2), false);
     });
@@ -1112,10 +1121,10 @@
             collection_id,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
 
         assert_noop!(
-            TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),
+            TemplateModule::transfer(origin1.clone(), account(3), 1, 1, 1),
             Error::<Test>::AddresNotInWhiteList
         );
     });
@@ -1137,21 +1146,21 @@
             collection_id,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(1)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(2)));
 
         // do approve
-        assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1, 1));
+        assert_ok!(TemplateModule::approve(origin1.clone(), account(1), 1, 1, 1));
         assert_eq!(TemplateModule::approved(1, (1, 1, 1)), 1);
 
         assert_ok!(TemplateModule::remove_from_white_list(
             origin1.clone(),
             1,
-            1
+            account(1)
         ));
 
         assert_noop!(
-            TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1),
+            TemplateModule::transfer_from(origin1.clone(), account(1), account(3), 1, 1, 1),
             Error::<Test>::AddresNotInWhiteList
         );
     });
@@ -1175,10 +1184,10 @@
             collection_id,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, account(1)));
 
         assert_noop!(
-            TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),
+            TemplateModule::transfer(origin1.clone(), account(3), 1, 1, 1),
             Error::<Test>::AddresNotInWhiteList
         );
     });
@@ -1201,21 +1210,21 @@
             collection_id,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(1)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
 
         // do approve
-        assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1, 1));
+        assert_ok!(TemplateModule::approve(origin1.clone(), account(1), 1, 1, 1));
         assert_eq!(TemplateModule::approved(1, (1, 1, 1)), 1);
 
         assert_ok!(TemplateModule::remove_from_white_list(
             origin1.clone(),
             collection_id,
-            2
+            account(2)
         ));
 
         assert_noop!(
-            TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1),
+            TemplateModule::transfer_from(origin1.clone(), account(1), account(3), 1, 1, 1),
             Error::<Test>::AddresNotInWhiteList
         );
     });
@@ -1267,7 +1276,7 @@
 
         // do approve
         assert_noop!(
-            TemplateModule::approve(origin1.clone(), 1, 1, 1, 5),
+            TemplateModule::approve(origin1.clone(), account(1), 1, 1, 5),
             Error::<Test>::AddresNotInWhiteList
         );
     });
@@ -1292,10 +1301,10 @@
             collection_id,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(1)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
 
-        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1));
+        assert_ok!(TemplateModule::transfer(origin1.clone(), account(2), 1, 1, 1));
     });
 }
 
@@ -1316,17 +1325,17 @@
             collection_id,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(1)));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
 
         // do approve
-        assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1, 5));
+        assert_ok!(TemplateModule::approve(origin1.clone(), account(1), 1, 1, 5));
         assert_eq!(TemplateModule::approved(1, (1, 1, 1)), 5);
 
         assert_ok!(TemplateModule::transfer_from(
             origin1.clone(),
-            1,
-            2,
+            account(1),
+            account(2),
             1,
             1,
             1
@@ -1381,12 +1390,12 @@
             false
         ));
 
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, account(2)));
 
         assert_ok!(TemplateModule::create_item(
             origin2.clone(),
             collection_id,
-            2,
+            account(2),
             default_nft_data().into()
         ));
     });
@@ -1413,10 +1422,10 @@
             collection_id,
             false
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
 
         assert_noop!(
-            TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),
+            TemplateModule::create_item(origin2.clone(), 1, account(2), default_nft_data().into()),
             Error::<Test>::PublicMintingNotAllowed
         );
     });
@@ -1445,7 +1454,7 @@
         ));
 
         assert_noop!(
-            TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),
+            TemplateModule::create_item(origin2.clone(), 1, account(2), default_nft_data().into()),
             Error::<Test>::PublicMintingNotAllowed
         );
     });
@@ -1499,12 +1508,12 @@
             true
         ));
 
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, account(2)));
 
         assert_ok!(TemplateModule::create_item(
             origin2.clone(),
             1,
-            2,
+            account(2),
             default_nft_data().into()
         ));
     });
@@ -1533,7 +1542,7 @@
         ));
 
         assert_noop!(
-            TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),
+            TemplateModule::create_item(origin2.clone(), 1, account(2), default_nft_data().into()),
             Error::<Test>::AddresNotInWhiteList
         );
     });
@@ -1560,12 +1569,12 @@
             collection_id,
             true
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, account(2)));
 
         assert_ok!(TemplateModule::create_item(
             origin2.clone(),
             1,
-            2,
+            account(2),
             default_nft_data().into()
         ));
     });
@@ -1648,7 +1657,7 @@
         assert_noop!(TemplateModule::create_item(
             origin1.clone(),
             1,
-            1,
+            account(1),
             data.into()
         ),  Error::<Test>::AddressOwnershipLimitExceeded);
     });
@@ -1675,8 +1684,8 @@
 
         let origin1 = Origin::signed(1);
         
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, account(2)));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, account(3)));
     });
 }
 
@@ -1701,8 +1710,8 @@
 
         let origin1 = Origin::signed(1);
 
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
-        assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3), Error::<Test>::CollectionAdminsLimitExceeded);
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, account(2)));
+        assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, account(3)), Error::<Test>::CollectionAdminsLimitExceeded);
     });
 }
 
@@ -1734,7 +1743,7 @@
         assert_noop!(TemplateModule::create_item(
             origin1.clone(),
             collection_id,
-            1,
+            account(1),
             too_big_const_data
         ), Error::<Test>::TokenConstDataLimitExceeded);
     });
@@ -1768,7 +1777,7 @@
         assert_noop!(TemplateModule::create_item(
             origin1.clone(),
             collection_id,
-            1,
+            account(1),
             too_big_const_data
         ), Error::<Test>::TokenVariableDataLimitExceeded);
     });
@@ -1802,7 +1811,7 @@
         assert_noop!(TemplateModule::create_item(
             origin1.clone(),
             collection_id,
-            1,
+            account(1),
             too_big_const_data
         ), Error::<Test>::TokenConstDataLimitExceeded);
     });
@@ -1836,7 +1845,7 @@
         assert_noop!(TemplateModule::create_item(
             origin1.clone(),
             collection_id,
-            1,
+            account(1),
             too_big_const_data
         ), Error::<Test>::TokenVariableDataLimitExceeded);
     });
modifiedpallets/scheduler/src/lib.rsdiffbeforeafterboth
--- a/pallets/scheduler/src/lib.rs
+++ b/pallets/scheduler/src/lib.rs
@@ -887,6 +887,7 @@
 		type ScheduleOrigin = EnsureOneOf<u64, EnsureRoot<u64>, EnsureSignedBy<One, u64>>;
 		type MaxScheduledPerBlock = MaxScheduledPerBlock;
 		type WeightInfo = ();
+        type SponsorshipHandler = ();
 	}
 
 	pub fn new_test_ext() -> sp_io::TestExternalities {
modifiedruntime/src/lib.rsdiffbeforeafterboth
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -689,7 +689,6 @@
 	type Event = Event;
 	type WeightInfo = nft_weights::WeightInfo;
 
-	type EvmWithdrawOrigin = EnsureAddressTruncated;
 	type EvmBackwardsAddressMapping = pallet_nft::MapBackwardsAddressTruncated;
 	type EvmAddressMapping = HashedAddressMapping<Self::Hashing>;
 	type CrossAccountId = pallet_nft::BasicCrossAccountId<Self>;