git.delta.rocks / unique-network / refs/commits / 23e0b8caf5e4

difftreelog

Merge pull request #113 from usetech-llc/feature/NFTPAR-196_sponsor_setVariableMetadata

Greg Zaitsev2021-03-22parents: #105eff5 #9180c84.patch.diff
in: master
Sponsored setVariableMetadata

19 files changed

modifiednode/src/chain_spec.rsdiffbeforeafterboth
--- a/node/src/chain_spec.rs
+++ b/node/src/chain_spec.rs
@@ -180,9 +180,9 @@
                 .collect(),
         }),
         pallet_nft: Some(NftConfig {
-            collection: vec![(
+            collection_id: vec![(
                 1,
-                CollectionType {
+                Collection {
                     owner: get_account_id_from_seed::<sr25519::Public>("Alice"),
                     mode: CollectionMode::NFT,
                     access: AccessMode::Normal,
modifiedpallets/nft/src/default_weights.rsdiffbeforeafterboth
--- a/pallets/nft/src/default_weights.rs
+++ b/pallets/nft/src/default_weights.rs
@@ -127,6 +127,11 @@
             .saturating_add(DbWeight::get().reads(0 as Weight))
             .saturating_add(DbWeight::get().writes(2 as Weight))
     }    
+    fn set_variable_meta_data_sponsoring_rate_limit() -> Weight {
+        (3_500_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(1 as Weight))
+    }
     fn toggle_contract_white_list() -> Weight {
         (3_000_000 as Weight)
             .saturating_add(DbWeight::get().reads(0 as Weight))
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -13,6 +13,7 @@
 #[cfg(feature = "std")]
 pub use serde::*;
 
+use core::ops::{Deref, DerefMut};
 use codec::{Decode, Encode};
 pub use frame_support::{
     construct_runtime, decl_event, decl_module, decl_storage, decl_error,
@@ -160,10 +161,10 @@
     }
 }
 
-#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
+#[derive(Encode, Decode, Clone, PartialEq)]
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-pub struct CollectionType<AccountId> {
-    pub owner: AccountId,
+pub struct Collection<T: Config> {
+    pub owner: T::AccountId,
     pub mode: CollectionMode,
     pub access: AccessMode,
     pub decimal_points: DecimalPoints,
@@ -174,11 +175,30 @@
     pub offchain_schema: Vec<u8>,
     pub schema_version: SchemaVersion,
     pub sponsorship: SponsorshipState<AccountId>,
-    pub limits: CollectionLimits, // Collection private restrictions 
+    pub limits: CollectionLimits<T::BlockNumber>, // Collection private restrictions 
     pub variable_on_chain_schema: Vec<u8>, //
     pub const_on_chain_schema: Vec<u8>, //
 }
 
+pub struct CollectionHandle<T: Config> {
+    pub id: CollectionId,
+    collection: Collection<T>,
+}
+
+impl<T: Config> Deref for CollectionHandle<T> {
+    type Target = Collection<T>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.collection
+    }
+}
+
+impl<T: Config> DerefMut for CollectionHandle<T> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.collection
+    }
+}
+
 #[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
 pub struct NftItemType<AccountId> {
@@ -214,9 +234,13 @@
 
 #[derive(Encode, Decode, Debug, Clone, PartialEq)]
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
-pub struct CollectionLimits {
+pub struct CollectionLimits<BlockNumber: Encode + Decode> {
     pub account_token_ownership_limit: u32,
     pub sponsored_data_size: u32,
+    /// None - setVariableMetadata is not sponsored
+    /// Some(v) - setVariableMetadata is sponsored 
+    ///           if there is v block between txs
+    pub sponsored_data_rate_limit: Option<BlockNumber>,
     pub token_limit: u32,
 
     // Timeouts for item types in passed blocks
@@ -225,12 +249,13 @@
     pub owner_can_destroy: bool,
 }
 
-impl Default for CollectionLimits {
-    fn default() -> CollectionLimits {
-        CollectionLimits { 
+impl<BlockNumber: Encode + Decode> Default for CollectionLimits<BlockNumber> {
+    fn default() -> Self {
+        Self { 
             account_token_ownership_limit: 10_000_000, 
             token_limit: u32::max_value(),
-            sponsored_data_size: u32::MAX,
+            sponsored_data_size: u32::MAX, 
+            sponsored_data_rate_limit: None,
             sponsor_transfer_timeout: 14400,
             owner_can_transfer: true,
             owner_can_destroy: true
@@ -283,6 +308,7 @@
     fn set_schema_version() -> Weight;
     fn set_chain_limits() -> Weight;
     fn set_contract_sponsoring_rate_limit() -> Weight;
+    fn set_variable_meta_data_sponsoring_rate_limit() -> Weight;
     fn toggle_contract_white_list() -> Weight;
     fn add_to_contract_white_list() -> Weight;
     fn remove_from_contract_white_list() -> Weight;
@@ -496,7 +522,7 @@
         //#region Basic collections
         /// Collection info
         /// Collection id (controlled?1)
-        pub Collection get(fn collection) config(): map hasher(blake2_128_concat) CollectionId => CollectionType<T::AccountId>;
+        pub CollectionById get(fn collection_id) config(): map hasher(blake2_128_concat) CollectionId => Option<Collection<T>> = None;
         /// List of collection admins
         /// Collection id (controlled?2)
         pub AdminList get(fn admin_list_collection): map hasher(blake2_128_concat) CollectionId => Vec<T::AccountId>;
@@ -538,6 +564,10 @@
         pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;
         //#endregion
 
+        /// Variable metadata sponsoring
+        /// Collection id (controlled?2), token id (controlled?2)
+        pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber> = None;
+      
         //#region Contract Sponsorship and Ownership
         /// Contract address (real)
         pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;
@@ -556,7 +586,7 @@
     add_extra_genesis {
         build(|config: &GenesisConfig<T>| {
             // Modification of storage
-            for (_num, _c) in &config.collection {
+            for (_num, _c) in &config.collection_id {
                 <Module<T>>::init_collection(_c);
             }
 
@@ -710,7 +740,7 @@
             };
 
             // Create new collection
-            let new_collection = CollectionType {
+            let new_collection = Collection {
                 owner: who.clone(),
                 name: collection_name,
                 mode: mode.clone(),
@@ -728,7 +758,7 @@
             };
 
             // Add new collection to map
-            <Collection<T>>::insert(next_id, new_collection);
+            <CollectionById<T>>::insert(next_id, new_collection);
 
             // call event
             Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));
@@ -750,10 +780,9 @@
         pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-            Self::check_owner_permissions(collection_id, sender)?;
-
-            let target_collection = <Collection<T>>::get(collection_id);
-            if !target_collection.limits.owner_can_destroy {
+            let collection = Self::get_collection(collection_id)?;
+            Self::check_owner_permissions(&collection, sender)?;
+            if !collection.limits.owner_can_destroy {
                 fail!(Error::<T>::NoPermission);
             }
 
@@ -762,7 +791,7 @@
             <Balance<T>>::remove_prefix(collection_id);
             <ItemListIndex>::remove(collection_id);
             <AdminList<T>>::remove(collection_id);
-            <Collection<T>>::remove(collection_id);
+            <CollectionById<T>>::remove(collection_id);
             <WhiteList<T>>::remove_prefix(collection_id);
 
             <NftItemList<T>>::remove_prefix(collection_id);
@@ -773,6 +802,8 @@
             <FungibleTransferBasket<T>>::remove_prefix(collection_id);
             <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);
 
+            <VariableMetaDataBasket<T>>::remove_prefix(collection_id);
+
             DestroyedCollectionCount::put(DestroyedCollectionCount::get()
                 .checked_add(1)
                 .ok_or(Error::<T>::NumOverflow)?);
@@ -797,7 +828,8 @@
         pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{
 
             let sender = ensure_signed(origin)?;
-            Self::check_owner_or_admin_permissions(collection_id, sender)?;
+            let collection = Self::get_collection(collection_id)?;
+            Self::check_owner_or_admin_permissions(&collection, sender)?;
 
             <WhiteList<T>>::insert(collection_id, address, true);
             
@@ -821,7 +853,8 @@
         pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{
 
             let sender = ensure_signed(origin)?;
-            Self::check_owner_or_admin_permissions(collection_id, sender)?;
+            let collection = Self::get_collection(collection_id)?;
+            Self::check_owner_or_admin_permissions(&collection, sender)?;
 
             <WhiteList<T>>::remove(collection_id, address);
 
@@ -845,10 +878,10 @@
         {
             let sender = ensure_signed(origin)?;
 
-            Self::check_owner_permissions(collection_id, sender)?;
-            let mut target_collection = <Collection<T>>::get(collection_id);
+            let mut target_collection = Self::get_collection(collection_id)?;
+            Self::check_owner_permissions(&target_collection, sender)?;
             target_collection.access = mode;
-            <Collection<T>>::insert(collection_id, target_collection);
+            Self::save_collection(target_collection);
 
             Ok(())
         }
@@ -872,10 +905,10 @@
         {
             let sender = ensure_signed(origin)?;
 
-            Self::check_owner_permissions(collection_id, sender)?;
-            let mut target_collection = <Collection<T>>::get(collection_id);
+            let mut target_collection = Self::get_collection(collection_id)?;
+            Self::check_owner_permissions(&target_collection, sender)?;
             target_collection.mint_mode = mint_permission;
-            <Collection<T>>::insert(collection_id, target_collection);
+            Self::save_collection(target_collection);
 
             Ok(())
         }
@@ -896,10 +929,10 @@
         pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-            Self::check_owner_permissions(collection_id, sender)?;
-            let mut target_collection = <Collection<T>>::get(collection_id);
+            let mut target_collection = Self::get_collection(collection_id)?;
+            Self::check_owner_permissions(&target_collection, sender)?;
             target_collection.owner = new_owner;
-            <Collection<T>>::insert(collection_id, target_collection);
+            Self::save_collection(target_collection);
 
             Ok(())
         }
@@ -922,7 +955,8 @@
         pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-            Self::check_owner_or_admin_permissions(collection_id, sender)?;
+            let collection = Self::get_collection(collection_id)?;
+            Self::check_owner_or_admin_permissions(&collection, sender)?;
             let mut admin_arr: Vec<T::AccountId> = Vec::new();
 
             if <AdminList<T>>::contains_key(collection_id)
@@ -957,7 +991,8 @@
         pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-            Self::check_owner_or_admin_permissions(collection_id, sender)?;
+            let collection = Self::get_collection(collection_id)?;
+            Self::check_owner_or_admin_permissions(&collection, sender)?;
             ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);
 
             let mut admin_arr = <AdminList<T>>::get(collection_id);
@@ -981,13 +1016,11 @@
         pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-            ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);
-
-            let mut target_collection = <Collection<T>>::get(collection_id);
-            ensure!(sender == target_collection.owner, Error::<T>::NoPermission);
+            let mut target_collection = Self::get_collection(collection_id)?;
+            Self::check_owner_permissions(&target_collection, sender)?;
 
             target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor);
-            <Collection<T>>::insert(collection_id, target_collection);
+            Self::save_collection(target_collection);
 
             Ok(())
         }
@@ -1004,16 +1037,15 @@
         pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-            ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);
 
-            let mut target_collection = <Collection<T>>::get(collection_id);
+            let mut target_collection = Self::get_collection(collection_id)?;
             ensure!(
                 target_collection.sponsorship.pending_sponsor() == Some(&sender),
                 Error::<T>::ConfirmUnsetSponsorFail
             );
 
             target_collection.sponsorship = SponsorshipState::Confirmed(sender);
-            <Collection<T>>::insert(collection_id, target_collection);
+            Self::save_collection(target_collection);
 
             Ok(())
         }
@@ -1032,13 +1064,12 @@
         pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-            ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);
 
-            let mut target_collection = <Collection<T>>::get(collection_id);
-            ensure!(sender == target_collection.owner, Error::<T>::NoPermission);
+            let mut target_collection = Self::get_collection(collection_id)?;
+            Self::check_owner_permissions(&target_collection, sender)?;
 
             target_collection.sponsorship = SponsorshipState::Disabled;
-            <Collection<T>>::insert(collection_id, target_collection);
+            Self::save_collection(target_collection);
 
             Ok(())
         }
@@ -1072,14 +1103,12 @@
         pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-
-            Self::collection_exists(collection_id)?;
 
-            let target_collection = <Collection<T>>::get(collection_id);
+            let target_collection = Self::get_collection(collection_id)?;
 
-            Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner, 1)?;
+            Self::can_create_items_in_collection(&target_collection, &sender, &owner, 1)?;
             Self::validate_create_item_args(&target_collection, &data)?;
-            Self::create_item_no_validation(collection_id, owner, data)?;
+            Self::create_item_no_validation(&target_collection, owner, data)?;
 
             Ok(())
         }
@@ -1111,16 +1140,15 @@
             ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);
             let sender = ensure_signed(origin)?;
 
-            Self::collection_exists(collection_id)?;
-            let target_collection = <Collection<T>>::get(collection_id);
+            let target_collection = Self::get_collection(collection_id)?;
 
-            Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner, items_data.len() as u32)?;
+            Self::can_create_items_in_collection(&target_collection, &sender, &owner, items_data.len() as u32)?;
 
             for data in &items_data {
                 Self::validate_create_item_args(&target_collection, data)?;
             }
             for data in &items_data {
-                Self::create_item_no_validation(collection_id, owner.clone(), data.clone())?;
+                Self::create_item_no_validation(&target_collection, owner.clone(), data.clone())?;
             }
 
             Ok(())
@@ -1144,33 +1172,32 @@
         pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-            Self::collection_exists(collection_id)?;
 
             // Transfer permissions check
-            let target_collection = <Collection<T>>::get(collection_id);
+            let target_collection = Self::get_collection(collection_id)?;
             ensure!(
-                Self::is_item_owner(sender.clone(), collection_id, item_id) ||
+                Self::is_item_owner(sender.clone(), &target_collection, item_id) ||
                 (
                     target_collection.limits.owner_can_transfer &&
-                    Self::is_owner_or_admin_permissions(collection_id, sender.clone())
+                    Self::is_owner_or_admin_permissions(&target_collection, sender.clone())
                 ),
                 Error::<T>::NoPermission
             );
 
             if target_collection.access == AccessMode::WhiteList {
-                Self::check_white_list(collection_id, &sender)?;
+                Self::check_white_list(&target_collection, &sender)?;
             }
 
             match target_collection.mode
             {
-                CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,
-                CollectionMode::Fungible(_)  => Self::burn_fungible_item(&sender, collection_id, value)?,
-                CollectionMode::ReFungible  => Self::burn_refungible_item(collection_id, item_id, &sender)?,
+                CollectionMode::NFT => Self::burn_nft_item(&target_collection, item_id)?,
+                CollectionMode::Fungible(_)  => Self::burn_fungible_item(&sender, &target_collection, value)?,
+                CollectionMode::ReFungible  => Self::burn_refungible_item(&target_collection, item_id, &sender)?,
                 _ => ()
             };
 
             // call event
-            Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));
+            Self::deposit_event(RawEvent::ItemDestroyed(target_collection.id, item_id));
 
             Ok(())
         }
@@ -1202,7 +1229,9 @@
         #[transactional]
         pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {
             let sender = ensure_signed(origin)?;
-            Self::transfer_internal(sender, recipient, collection_id, item_id, value)
+            let collection = Self::get_collection(collection_id)?;
+
+            Self::transfer_internal(sender, recipient, &collection, item_id, value)
         }
 
         /// Set, change, or remove approved address to transfer the ownership of the NFT.
@@ -1225,16 +1254,14 @@
         pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
+            let target_collection = Self::get_collection(collection_id)?;
 
-            Self::collection_exists(collection_id)?;
-            Self::token_exists(collection_id, item_id, &sender)?;
+            Self::token_exists(&target_collection, item_id, &sender)?;
 
             // Transfer permissions check
-            let target_collection = <Collection<T>>::get(collection_id);
-
             let bypasses_limits = target_collection.limits.owner_can_transfer &&
                 Self::is_owner_or_admin_permissions(
-                    collection_id,
+                    &target_collection,
                     sender.clone(),
                 );
 
@@ -1242,7 +1269,7 @@
                 None
             } else if let Some(amount) = Self::owned_amount(
                 sender.clone(),
-                collection_id,
+                &target_collection,
                 item_id,
             ) {
                 Some(amount)
@@ -1251,8 +1278,8 @@
             };
 
             if target_collection.access == AccessMode::WhiteList {
-                Self::check_white_list(collection_id, &sender)?;
-                Self::check_white_list(collection_id, &spender)?;
+                Self::check_white_list(&target_collection, &sender)?;
+                Self::check_white_list(&target_collection, &spender)?;
             }
 
             let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));
@@ -1292,6 +1319,8 @@
         pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
+            let target_collection = Self::get_collection(collection_id)?;
+
             let mut appoved_transfer = false;
 
             // Check approval
@@ -1302,24 +1331,22 @@
                 appoved_transfer = true;
             }
 
-            let target_collection = <Collection<T>>::get(collection_id);
-
             // Limits check
-            Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;
+            Self::is_correct_transfer(&target_collection, &recipient)?;
 
             // Transfer permissions check         
             ensure!(
                 appoved_transfer || 
                 (
                     target_collection.limits.owner_can_transfer &&
-                    Self::is_owner_or_admin_permissions(collection_id, sender.clone())
+                    Self::is_owner_or_admin_permissions(&target_collection, sender.clone())
                 ),
                 Error::<T>::NoPermission
             );
 
             if target_collection.access == AccessMode::WhiteList {
-                Self::check_white_list(collection_id, &sender)?;
-                Self::check_white_list(collection_id, &recipient)?;
+                Self::check_white_list(&target_collection, &sender)?;
+                Self::check_white_list(&target_collection, &recipient)?;
             }
 
             // Reduce approval by transferred amount or remove if remaining approval drops to 0
@@ -1332,9 +1359,9 @@
 
             match target_collection.mode
             {
-                CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,
-                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, value, &from, &recipient)?,
-                CollectionMode::ReFungible  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,
+                CollectionMode::NFT => Self::transfer_nft(&target_collection, item_id, from, recipient)?,
+                CollectionMode::Fungible(_)  => Self::transfer_fungible(&target_collection, value, &from, &recipient)?,
+                CollectionMode::ReFungible  => Self::transfer_refungible(&target_collection, item_id, value, from.clone(), recipient)?,
                 _ => ()
             };
 
@@ -1378,21 +1405,20 @@
         ) -> DispatchResult {
             let sender = ensure_signed(origin)?;
             
-            Self::collection_exists(collection_id)?;
-            Self::token_exists(collection_id, item_id, &sender)?;
+            let target_collection = Self::get_collection(collection_id)?;
+            Self::token_exists(&target_collection, item_id, &sender)?;
 
             ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);
 
             // Modify permissions check
-            let target_collection = <Collection<T>>::get(collection_id);
-            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||
-                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
+            ensure!(Self::is_item_owner(sender.clone(), &target_collection, item_id) ||
+                Self::is_owner_or_admin_permissions(&target_collection, sender.clone()),
                 Error::<T>::NoPermission);
 
             match target_collection.mode
             {
-                CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,
-                CollectionMode::ReFungible  => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,
+                CollectionMode::NFT => Self::set_nft_variable_data(&target_collection, item_id, data)?,
+                CollectionMode::ReFungible  => Self::set_re_fungible_variable_data(&target_collection, item_id, data)?,
                 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),
                 _ => fail!(Error::<T>::UnexpectedCollectionType)
             };
@@ -1422,10 +1448,10 @@
             version: SchemaVersion
         ) -> DispatchResult {
             let sender = ensure_signed(origin)?;
-            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
-            let mut target_collection = <Collection<T>>::get(collection_id);
+            let mut target_collection = Self::get_collection(collection_id)?;
+            Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?;
             target_collection.schema_version = version;
-            <Collection<T>>::insert(collection_id, target_collection);
+            Self::save_collection(target_collection);
 
             Ok(())
         }
@@ -1450,14 +1476,14 @@
             schema: Vec<u8>
         ) -> DispatchResult {
             let sender = ensure_signed(origin)?;
-            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
+            let mut target_collection = Self::get_collection(collection_id)?;
+            Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?;
 
             // check schema limit
             ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");
 
-            let mut target_collection = <Collection<T>>::get(collection_id);
             target_collection.offchain_schema = schema;
-            <Collection<T>>::insert(collection_id, target_collection);
+            Self::save_collection(target_collection);
 
             Ok(())
         }
@@ -1482,14 +1508,14 @@
             schema: Vec<u8>
         ) -> DispatchResult {
             let sender = ensure_signed(origin)?;
-            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
+            let mut target_collection = Self::get_collection(collection_id)?;
+            Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?;
 
             // check schema limit
             ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");
 
-            let mut target_collection = <Collection<T>>::get(collection_id);
             target_collection.const_on_chain_schema = schema;
-            <Collection<T>>::insert(collection_id, target_collection);
+            Self::save_collection(target_collection);
 
             Ok(())
         }
@@ -1514,14 +1540,14 @@
             schema: Vec<u8>
         ) -> DispatchResult {
             let sender = ensure_signed(origin)?;
-            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
+            let mut target_collection = Self::get_collection(collection_id)?;
+            Self::check_owner_or_admin_permissions(&target_collection, sender.clone())?;
 
             // check schema limit
             ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");
 
-            let mut target_collection = <Collection<T>>::get(collection_id);
             target_collection.variable_on_chain_schema = schema;
-            <Collection<T>>::insert(collection_id, target_collection);
+            Self::save_collection(target_collection);
 
             Ok(())
         }
@@ -1694,12 +1720,12 @@
         pub fn set_collection_limits(
             origin,
             collection_id: u32,
-            new_limits: CollectionLimits,
+            new_limits: CollectionLimits<T::BlockNumber>,
         ) -> DispatchResult {
             let sender = ensure_signed(origin)?;
-            Self::check_owner_permissions(collection_id, sender.clone())?;
-            let mut target_collection = <Collection<T>>::get(collection_id);
-            let old_limits = target_collection.limits;
+            let mut target_collection = Self::get_collection(collection_id)?;
+            Self::check_owner_permissions(&target_collection, sender.clone())?;
+            let old_limits = &target_collection.limits;
             let chain_limits = ChainLimit::get();
 
             // collection bounds
@@ -1719,7 +1745,7 @@
             );
 
             target_collection.limits = new_limits;
-            <Collection<T>>::insert(collection_id, target_collection);
+            Self::save_collection(target_collection);
 
             Ok(())
         } 
@@ -1728,38 +1754,36 @@
 
 impl<T: Config> Module<T> {
 
-    pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {
-
-        let target_collection = <Collection<T>>::get(collection_id);
-
+    pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, target_collection: &CollectionHandle<T>, item_id: TokenId, value: u128) -> DispatchResult {
         // Limits check
-        Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;
+        Self::is_correct_transfer(target_collection, &recipient)?;
 
         // Transfer permissions check
-        ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||
-            Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
+        ensure!(Self::is_item_owner(sender.clone(), target_collection, item_id) ||
+            Self::is_owner_or_admin_permissions(target_collection, sender.clone()),
             Error::<T>::NoPermission);
 
         if target_collection.access == AccessMode::WhiteList {
-            Self::check_white_list(collection_id, &sender)?;
-            Self::check_white_list(collection_id, &recipient)?;
+            Self::check_white_list(target_collection, &sender)?;
+            Self::check_white_list(target_collection, &recipient)?;
         }
 
         match target_collection.mode
         {
-            CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient.clone())?,
-            CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,
-            CollectionMode::ReFungible  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient.clone())?,
+            CollectionMode::NFT => Self::transfer_nft(target_collection, item_id, sender.clone(), recipient.clone())?,
+            CollectionMode::Fungible(_)  => Self::transfer_fungible(target_collection, value, &sender, &recipient)?,
+            CollectionMode::ReFungible  => Self::transfer_refungible(target_collection, item_id, value, sender.clone(), recipient.clone())?,
             _ => ()
         };
 
-        Self::deposit_event(RawEvent::Transfer(collection_id, item_id, sender, recipient, value));
+        Self::deposit_event(RawEvent::Transfer(target_collection.id, item_id, sender, recipient, value));
 
         Ok(())
     }
 
 
-    fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {
+    fn is_correct_transfer(collection: &CollectionHandle<T>, recipient: &T::AccountId) -> DispatchResult {
+        let collection_id = collection.id;
 
         // check token limit and account token limit
         let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;
@@ -1768,7 +1792,8 @@
         Ok(())
     }
 
-    fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId, amount: u32) -> DispatchResult {
+    fn can_create_items_in_collection(collection: &CollectionHandle<T>, sender: &T::AccountId, owner: &T::AccountId, amount: u32) -> DispatchResult {
+        let collection_id = collection.id;
 
         // check token limit and account token limit
         let total_items: u32 = ItemListIndex::get(collection_id)
@@ -1780,16 +1805,16 @@
         ensure!(collection.limits.token_limit >= total_items,  Error::<T>::CollectionTokenLimitExceeded);
         ensure!(collection.limits.account_token_ownership_limit >= account_items,  Error::<T>::AccountTokenLimitExceeded);
 
-        if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
+        if !Self::is_owner_or_admin_permissions(collection, sender.clone()) {
             ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);
-            Self::check_white_list(collection_id, owner)?;
-            Self::check_white_list(collection_id, sender)?;
+            Self::check_white_list(collection, owner)?;
+            Self::check_white_list(collection, sender)?;
         }
 
         Ok(())
     }
 
-    fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {
+    fn validate_create_item_args(target_collection: &CollectionHandle<T>, data: &CreateItemData) -> DispatchResult {
         match target_collection.mode
         {
             CollectionMode::NFT => {
@@ -1827,7 +1852,9 @@
         Ok(())
     }
 
-    fn create_item_no_validation(collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {
+    fn create_item_no_validation(collection: &CollectionHandle<T>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {
+        let collection_id = collection.id;
+
         match data
         {
             CreateItemData::NFT(data) => {
@@ -1837,10 +1864,10 @@
                     variable_data: data.variable_data
                 };
 
-                Self::add_nft_item(collection_id, item)?;
+                Self::add_nft_item(collection, item)?;
             },
             CreateItemData::Fungible(data) => {
-                Self::add_fungible_item(collection_id, &owner, data.value)?;
+                Self::add_fungible_item(collection, &owner, data.value)?;
             },
             CreateItemData::ReFungible(data) => {
                 let mut owner_list = Vec::new();
@@ -1852,14 +1879,15 @@
                     variable_data: data.variable_data
                 };
 
-                Self::add_refungible_item(collection_id, item)?;
+                Self::add_refungible_item(collection, item)?;
             }
         };
 
         Ok(())
     }
 
-    fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {
+    fn add_fungible_item(collection: &CollectionHandle<T>, owner: &T::AccountId, value: u128) -> DispatchResult {
+        let collection_id = collection.id;
 
         // Does new owner already have an account?
         let mut balance: u128 = 0;
@@ -1883,7 +1911,9 @@
         Ok(())
     }
 
-    fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {
+    fn add_refungible_item(collection: &CollectionHandle<T>, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {
+        let collection_id = collection.id;
+
         let current_index = <ItemListIndex>::get(collection_id)
             .checked_add(1)
             .ok_or(Error::<T>::NumOverflow)?;
@@ -1913,7 +1943,9 @@
         Ok(())
     }
 
-    fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {
+    fn add_nft_item(collection: &CollectionHandle<T>, item: NftItemType<T::AccountId>) -> DispatchResult {
+        let collection_id = collection.id;
+
         let current_index = <ItemListIndex>::get(collection_id)
             .checked_add(1)
             .ok_or(Error::<T>::NumOverflow)?;
@@ -1935,10 +1967,12 @@
     }
 
     fn burn_refungible_item(
-        collection_id: CollectionId,
+        collection: &CollectionHandle<T>,
         item_id: TokenId,
         owner: &T::AccountId,
     ) -> DispatchResult {
+        let collection_id = collection.id;
+
         ensure!(
             <ReFungibleItemList<T>>::contains_key(collection_id, item_id),
             Error::<T>::TokenNotFound
@@ -1969,6 +2003,7 @@
         // Burn the token completely if this was the last (only) owner
         if owner_count == 0 {
             <ReFungibleItemList<T>>::remove(collection_id, item_id);
+            <VariableMetaDataBasket<T>>::remove(collection_id, item_id);
         }
         else {
             <ReFungibleItemList<T>>::insert(collection_id, item_id, token);
@@ -1977,7 +2012,9 @@
         Ok(())
     }
 
-    fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {
+    fn burn_nft_item(collection: &CollectionHandle<T>, item_id: TokenId) -> DispatchResult {
+        let collection_id = collection.id;
+
         ensure!(
             <NftItemList<T>>::contains_key(collection_id, item_id),
             Error::<T>::TokenNotFound
@@ -1991,11 +2028,14 @@
             .ok_or(Error::<T>::NumOverflow)?;
         <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);
         <NftItemList<T>>::remove(collection_id, item_id);
+        <VariableMetaDataBasket<T>>::remove(collection_id, item_id);
 
         Ok(())
     }
 
-    fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {
+    fn burn_fungible_item(owner: &T::AccountId, collection: &CollectionHandle<T>, value: u128) -> DispatchResult {
+        let collection_id = collection.id;
+
         ensure!(
             <FungibleItemList<T>>::contains_key(collection_id, owner),
             Error::<T>::TokenNotFound
@@ -2020,18 +2060,20 @@
         Ok(())
     }
 
-    fn collection_exists(collection_id: CollectionId) -> DispatchResult {
-        ensure!(
-            <Collection<T>>::contains_key(collection_id),
-            Error::<T>::CollectionNotFound
-        );
-        Ok(())
+    pub fn get_collection(collection_id: CollectionId) -> Result<CollectionHandle<T>, sp_runtime::DispatchError> {
+        Ok(<CollectionById<T>>::get(collection_id)
+            .map(|collection| CollectionHandle {
+                id: collection_id,
+                collection
+            })
+            .ok_or(Error::<T>::CollectionNotFound)?)
     }
 
-    fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {
-        Self::collection_exists(collection_id)?;
+    fn save_collection(collection: CollectionHandle<T>) {
+        <CollectionById<T>>::insert(collection.id, collection.collection);
+    }
 
-        let target_collection = <Collection<T>>::get(collection_id);
+    fn check_owner_permissions(target_collection: &CollectionHandle<T>, subject: T::AccountId) -> DispatchResult {
         ensure!(
             subject == target_collection.owner,
             Error::<T>::NoPermission
@@ -2040,13 +2082,12 @@
         Ok(())
     }
 
-    fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {
-        let target_collection = <Collection<T>>::get(collection_id);
-        let mut result: bool = subject == target_collection.owner;
-        let exists = <AdminList<T>>::contains_key(collection_id);
+    fn is_owner_or_admin_permissions(collection: &CollectionHandle<T>, subject: T::AccountId) -> bool {
+        let mut result: bool = subject == collection.owner;
+        let exists = <AdminList<T>>::contains_key(collection.id);
 
         if !result & exists {
-            if <AdminList<T>>::get(collection_id).contains(&subject) {
+            if <AdminList<T>>::get(collection.id).contains(&subject) {
                 result = true
             }
         }
@@ -2055,11 +2096,10 @@
     }
 
     fn check_owner_or_admin_permissions(
-        collection_id: CollectionId,
+        collection: &CollectionHandle<T>,
         subject: T::AccountId,
     ) -> DispatchResult {
-        Self::collection_exists(collection_id)?;
-        let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());
+        let result = Self::is_owner_or_admin_permissions(collection, subject.clone());
 
         ensure!(
             result,
@@ -2070,10 +2110,10 @@
 
     fn owned_amount(
         subject: T::AccountId,
-        collection_id: CollectionId,
+        target_collection: &CollectionHandle<T>,
         item_id: TokenId,
     ) -> Option<u128> {
-        let target_collection = <Collection<T>>::get(collection_id);
+        let collection_id = target_collection.id;
 
         match target_collection.mode {
             CollectionMode::NFT => {
@@ -2098,8 +2138,8 @@
         }
     }
 
-    fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {
-        let target_collection = <Collection<T>>::get(collection_id);
+    fn is_item_owner(subject: T::AccountId, target_collection: &CollectionHandle<T>, item_id: TokenId) -> bool {
+        let collection_id = target_collection.id;
 
         match target_collection.mode {
             CollectionMode::NFT => {
@@ -2118,7 +2158,9 @@
         }
     }
 
-    fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {
+    fn check_white_list(collection: &CollectionHandle<T>, address: &T::AccountId) -> DispatchResult {
+        let collection_id = collection.id;
+
         let mes = Error::<T>::AddresNotInWhiteList;
         ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);
 
@@ -2128,11 +2170,11 @@
     /// Check if token exists. In case of Fungible, check if there is an entry for 
     /// the owner in fungible balances double map
     fn token_exists(
-        collection_id: CollectionId,
+        target_collection: &CollectionHandle<T>,
         item_id: TokenId,
         owner: &T::AccountId
     ) -> DispatchResult {
-        let target_collection = <Collection<T>>::get(collection_id);
+        let collection_id = target_collection.id;
         let exists = match target_collection.mode
         {
             CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),
@@ -2146,18 +2188,19 @@
     }
 
     fn transfer_fungible(
-        collection_id: CollectionId,
+        collection: &CollectionHandle<T>,
         value: u128,
         owner: &T::AccountId,
         recipient: &T::AccountId,
     ) -> DispatchResult {
-        Self::token_exists(collection_id, 0, owner)?;
+        let collection_id = collection.id;
+        Self::token_exists(&collection, 0, owner)?;
 
         let mut balance = <FungibleItemList<T>>::get(collection_id, owner);
         ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);
 
         // Send balance to recipient (updates balanceOf of recipient)
-        Self::add_fungible_item(collection_id, recipient, value)?;
+        Self::add_fungible_item(collection, recipient, value)?;
 
         // update balanceOf of sender
         <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);
@@ -2175,13 +2218,14 @@
     }
 
     fn transfer_refungible(
-        collection_id: CollectionId,
+        collection: &CollectionHandle<T>,
         item_id: TokenId,
         value: u128,
         owner: T::AccountId,
         new_owner: T::AccountId,
     ) -> DispatchResult {
-        Self::token_exists(collection_id, item_id, &owner)?;
+        let collection_id = collection.id;
+        Self::token_exists(collection, item_id, &owner)?;
 
         let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);
         let item = full_item
@@ -2257,12 +2301,13 @@
     }
 
     fn transfer_nft(
-        collection_id: CollectionId,
+        collection: &CollectionHandle<T>,
         item_id: TokenId,
         sender: T::AccountId,
         new_owner: T::AccountId,
     ) -> DispatchResult {
-        Self::token_exists(collection_id, item_id, &sender)?;
+        let collection_id = collection.id;
+        Self::token_exists(&collection, item_id, &sender)?;
 
         let mut item = <NftItemList<T>>::get(collection_id, item_id);
 
@@ -2294,10 +2339,11 @@
     }
     
     fn set_re_fungible_variable_data(
-        collection_id: CollectionId,
+        collection: &CollectionHandle<T>,
         item_id: TokenId,
         data: Vec<u8>
     ) -> DispatchResult {
+        let collection_id = collection.id;
         let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);
 
         item.variable_data = data;
@@ -2308,10 +2354,11 @@
     }
 
     fn set_nft_variable_data(
-        collection_id: CollectionId,
+        collection: &CollectionHandle<T>,
         item_id: TokenId,
         data: Vec<u8>
     ) -> DispatchResult {
+        let collection_id = collection.id;
         let mut item = <NftItemList<T>>::get(collection_id, item_id);
         
         item.variable_data = data;
@@ -2321,7 +2368,7 @@
         Ok(())
     }
 
-    fn init_collection(item: &CollectionType<T::AccountId>) {
+    fn init_collection(item: &Collection<T>) {
         // check params
         assert!(
             item.decimal_points <= MAX_DECIMAL_POINTS,
@@ -2401,7 +2448,6 @@
     }
 
     fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {
-
         // add to account limit
         if <AccountItemCount<T>>::contains_key(owner) {
 
@@ -2569,8 +2615,9 @@
 
         // Determine who is paying transaction fee based on ecnomic model
         // Parse call to extract collection ID and access collection sponsor
-        let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {
+        let mut sponsor: Option<T::AccountId> = (|| match IsSubType::<Call<T>>::is_sub_type(call) {
             Some(Call::create_item(collection_id, _owner, _properties)) => {
+                let collection = <CollectionById<T>>::get(collection_id)?;
 
                 // sponsor timeout
                 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;
@@ -2583,12 +2630,10 @@
                     let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));
                     let limit_time = last_tx_block + limit.into();
                     if block_number <= limit_time {
-                        sponsored = false;
+                        return None;
                     }
                 }
-                if sponsored {
-                    <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);
-                }
+                <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);
 
                 // check free create limit
                 if (collection.limits.sponsored_data_size >= (_properties.len() as u32)) &&
@@ -2596,18 +2641,18 @@
                 {
                     collection.sponsorship.sponsor()
                         .cloned()
-                        .unwrap_or_default()
                 } else {
-                    T::AccountId::default()
+                    None
                 }
             }
             Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {
+                let collection = <CollectionById<T>>::get(collection_id)?;
                 
                 let mut sponsor_transfer = false;
-                if <Collection<T>>::get(collection_id).sponsorship.confirmed() {
+                if collection.sponsorship.confirmed() {
 
-                    let collection_limits = <Collection<T>>::get(collection_id).limits;
-                    let collection_mode = <Collection<T>>::get(collection_id).mode;
+                    let collection_limits = collection.limits;
+                    let collection_mode = collection.mode;
     
                     // sponsor timeout
                     let block_number = <system::Module<T>>::block_number() as T::BlockNumber;
@@ -2689,19 +2734,68 @@
                 }
 
                 if !sponsor_transfer {
-                    T::AccountId::default()
+                    None
                 } else {
-                    <Collection<T>>::get(collection_id).sponsorship.sponsor()
+                    collection.sponsorship.sponsor()
                         .cloned()
-                        .unwrap_or_default()
                 }
             }
 
-            _ => T::AccountId::default(),
-        };
+            Some(Call::set_variable_meta_data(collection_id, item_id, data)) => {
+                let mut sponsor_metadata_changes = false;
+
+                let collection = <CollectionById<T>>::get(collection_id)?;
+
+                if
+                    collection.sponsor_confirmed &&
+                    // Can't sponsor fungible collection, this tx will be rejected
+                    // as invalid
+                    !matches!(collection.mode, CollectionMode::Fungible(_)) &&
+                    data.len() <= collection.limits.sponsored_data_size as usize
+                {
+                    if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit {
+                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;
+
+                        if <VariableMetaDataBasket<T>>::get(collection_id, item_id)
+                            .map(|last_block| block_number - last_block > rate_limit)
+                            .unwrap_or(true) 
+                        {
+                            sponsor_metadata_changes = true;
+                            <VariableMetaDataBasket<T>>::insert(collection_id, item_id, block_number);
+                        }
+                    }
+                }
+
+                if !sponsor_metadata_changes {
+                    None
+                } else {
+                    Some(collection.sponsor)
+                }
+            }
+
+            _ => None,
+        })();
+
+        match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {
+            Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {
 
+                let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());
+
+                let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())
+                  && <ContractOwner<T>>::get(called_contract.clone()) == *who;
+                let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());
+                  
+                if !owned_contract && white_list_enabled {
+                    if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {
+                        return Err(InvalidTransaction::Call.into());
+                    }
+                }
+            },
+            _ => {},
+        }
+
         // Sponsor smart contracts
-        sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {
+        sponsor = sponsor.or_else(|| match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {
 
             // On instantiation: set the contract owner
             Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {
@@ -2713,7 +2807,7 @@
                 );
                 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());
 
-                T::AccountId::default()
+                None
             },
 
             // On instantiation with code: set the contract owner
@@ -2727,23 +2821,13 @@
 
                 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());
 
-                T::AccountId::default()
+                None
             }
 
             // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is
             Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {
 
                 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());
-
-                let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())
-                  && <ContractOwner<T>>::get(called_contract.clone()) == *who;
-                let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());
-                  
-                if !owned_contract && white_list_enabled {
-                    if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {
-                        return Err(InvalidTransaction::Call.into());
-                    }
-                }
 
                 let mut sponsor_transfer = false;
                 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {
@@ -2760,26 +2844,21 @@
                     sponsor_transfer = false;
                 }
                
-                
-                let mut sp = T::AccountId::default();
                 if sponsor_transfer {
                     if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {
                         if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {
-                            sp = called_contract;
+                            return Some(called_contract);
                         }
                     }
                 }
 
-                sp
+                None
             },
 
-            _ => sponsor,
-        };
+            _ => None,
+        });
 
-        let mut who_pays_fee: T::AccountId = sponsor.clone();
-        if sponsor == T::AccountId::default() {
-            who_pays_fee = who.clone();
-        }
+        let who_pays_fee = sponsor.unwrap_or_else(|| who.clone());
 
 		<<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)
 			.map(|i| (fee, i))
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
before · pallets/nft/src/tests.rs
1// Tests to be written here2use super::*;3use crate::mock::*;4use crate::{AccessMode, CollectionMode,5    Ownership, ChainLimits, CreateItemData, CreateNftData, CreateFungibleData, CreateReFungibleData,6    CollectionId, TokenId, MAX_DECIMAL_POINTS};7use frame_support::{assert_noop, assert_ok};8use frame_system::{ RawOrigin };910fn default_collection_numbers_limit() -> u32 {11    1012}1314fn default_limits() {15    assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {16            collection_numbers_limit: default_collection_numbers_limit(),17            account_token_ownership_limit: 10,18            collections_admins_limit: 5,19            custom_data_limit: 2048,20            nft_sponsor_transfer_timeout: 15,21            fungible_sponsor_transfer_timeout: 15,22            refungible_sponsor_transfer_timeout: 15,23            const_on_chain_schema_limit: 1024,24            offchain_schema_limit: 1024,25            variable_on_chain_schema_limit: 1024,26        }));27}2829fn default_nft_data() -> CreateNftData {30    CreateNftData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] }31}3233fn default_fungible_data () -> CreateFungibleData {34    CreateFungibleData { value: 5 }35}3637fn default_re_fungible_data () -> CreateReFungibleData {38    CreateReFungibleData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1], pieces: 1023 }39}4041fn create_test_collection_for_owner(mode: &CollectionMode, owner: u64, id: CollectionId) -> CollectionId {42    let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();43    let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();44    let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();4546    let origin1 = Origin::signed(owner);47    assert_ok!(TemplateModule::create_collection(48            origin1.clone(),49            col_name1.clone(),50            col_desc1.clone(),51            token_prefix1.clone(),52            mode.clone()53        ));5455    let saved_col_name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();56    let saved_description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();57    let saved_prefix: Vec<u8> = b"token_prefix1\0".to_vec();58    assert_eq!(TemplateModule::collection(id).owner, owner);59    assert_eq!(TemplateModule::collection(id).name, saved_col_name);60    assert_eq!(TemplateModule::collection(id).mode, *mode);61    assert_eq!(TemplateModule::collection(id).description, saved_description);62    assert_eq!(TemplateModule::collection(id).token_prefix, saved_prefix);63    id64}6566fn create_test_collection(mode: &CollectionMode, id: CollectionId) -> CollectionId {67    create_test_collection_for_owner(&mode, 1, id)68}6970fn create_test_item(collection_id: CollectionId, data: &CreateItemData) {71    let origin1 = Origin::signed(1);72    assert_ok!(TemplateModule::create_item(73            origin1.clone(),74            collection_id,75            1,76            data.clone()77        ));7879}8081// Use cases tests region82// #region8384#[test]85fn set_version_schema() {86    new_test_ext().execute_with(|| {87        default_limits();88        let origin1 = Origin::signed(1);89        let collection_id = create_test_collection(&CollectionMode::NFT, 1);90        91        assert_ok!(TemplateModule::set_schema_version(origin1, collection_id, SchemaVersion::Unique));92        assert_eq!(TemplateModule::collection(collection_id).schema_version, SchemaVersion::Unique);93    });94}9596#[test]97fn create_fungible_collection_fails_with_large_decimal_numbers() {98    new_test_ext().execute_with(|| {99        default_limits();100101        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();102        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();103        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();104105        let origin1 = Origin::signed(1);106        assert_noop!(TemplateModule::create_collection(107            origin1,108            col_name1,109            col_desc1,110            token_prefix1,111            CollectionMode::Fungible(MAX_DECIMAL_POINTS + 1)112        ), Error::<Test>::CollectionDecimalPointLimitExceeded);113    });    114}115116#[test]117fn create_nft_item() {118    new_test_ext().execute_with(|| {119        default_limits();120        let collection_id = create_test_collection(&CollectionMode::NFT, 1);121        122        let data = default_nft_data();123        create_test_item(collection_id, &data.clone().into());124        assert_eq!(TemplateModule::nft_item_id(collection_id, 1).const_data, data.const_data);125        assert_eq!(TemplateModule::nft_item_id(collection_id, 1).variable_data, data.variable_data);126    });127}128129// Use cases tests region130// #region131#[test]132fn create_nft_multiple_items() {133    new_test_ext().execute_with(|| {134        default_limits();135        136        create_test_collection(&CollectionMode::NFT, 1);137138        let origin1 = Origin::signed(1);139140        let items_data = vec![default_nft_data(), default_nft_data(), default_nft_data()];141142        assert_ok!(TemplateModule::create_multiple_items(143            origin1.clone(),144            1,145            1,146            items_data.clone().into_iter().map(|d| { d.into() }).collect()147        ));148        for (index, data) in items_data.iter().enumerate() {149            assert_eq!(TemplateModule::nft_item_id(1, (index + 1) as TokenId).const_data.to_vec(), data.const_data);150            assert_eq!(TemplateModule::nft_item_id(1, (index + 1) as TokenId).variable_data.to_vec(), data.variable_data);151        }152    });153}154155#[test]156fn create_refungible_item() {157    new_test_ext().execute_with(|| {158        default_limits();159        let collection_id = create_test_collection(&CollectionMode::ReFungible, 1);160161        let data = default_re_fungible_data();162        create_test_item(collection_id, &data.clone().into());163        assert_eq!(164            TemplateModule::refungible_item_id(collection_id, 1).const_data,165            data.const_data166        );167        assert_eq!(168            TemplateModule::refungible_item_id(collection_id, 1).variable_data,169            data.variable_data170        );171        assert_eq!(172            TemplateModule::refungible_item_id(collection_id, 1).owner[0],173            Ownership {174                owner: 1,175                fraction: 1023176            }177        );178    });179}180181#[test]182fn create_multiple_refungible_items() {183    new_test_ext().execute_with(|| {184        default_limits();185        186        create_test_collection(&CollectionMode::ReFungible, 1);187188        let origin1 = Origin::signed(1);189190        let items_data = vec![default_re_fungible_data(), default_re_fungible_data(), default_re_fungible_data()];191192        assert_ok!(TemplateModule::create_multiple_items(193            origin1.clone(),194            1,195            1,196            items_data.clone().into_iter().map(|d| { d.into() }).collect()197        ));198        for (index, data) in items_data.iter().enumerate() {199200            let item = TemplateModule::refungible_item_id(1, (index + 1) as TokenId);201            assert_eq!(item.const_data.to_vec(), data.const_data);202            assert_eq!(item.variable_data.to_vec(), data.variable_data);203            assert_eq!(204                item.owner[0],205                Ownership {206                    owner: 1,207                    fraction: 1023208                }209            );210        }211    });212}213214#[test]215fn create_fungible_item() {216    new_test_ext().execute_with(|| {217        default_limits();218        219        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);220221        let data = default_fungible_data();222        create_test_item(collection_id, &data.into());223224        assert_eq!(TemplateModule::fungible_item_id(collection_id, 1).value, 5);225    });226}227228//#[test]229// fn create_multiple_fungible_items() {230//     new_test_ext().execute_with(|| {231//         default_limits();232233//         create_test_collection(&CollectionMode::Fungible(3), 1);234235//         let origin1 = Origin::signed(1);236237//         let items_data = vec![default_fungible_data(), default_fungible_data(), default_fungible_data()];238239//         assert_ok!(TemplateModule::create_multiple_items(240//             origin1.clone(),241//             1,242//             1,243//             items_data.clone().into_iter().map(|d| { d.into() }).collect()244//         ));245        246//         for (index, _) in items_data.iter().enumerate() {247//             assert_eq!(TemplateModule::fungible_item_id(1, (index + 1) as TokenId).value, 5);248//         }249//         assert_eq!(TemplateModule::balance_count(1, 1), 3000);250//         assert_eq!(TemplateModule::address_tokens(1, 1), [1, 2, 3]);251//     });252// }253254#[test]255fn transfer_fungible_item() {256    new_test_ext().execute_with(|| {257        default_limits();258        259        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);260261        let origin1 = Origin::signed(1);262        let origin2 = Origin::signed(2);263264        let data = default_fungible_data();265        create_test_item(collection_id, &data.into());266267        assert_eq!(TemplateModule::fungible_item_id(1, 1).value, 5);268        assert_eq!(TemplateModule::balance_count(1, 1), 5);269270        // change owner scenario271        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 5));272        assert_eq!(TemplateModule::fungible_item_id(1, 1).value, 0);273        assert_eq!(TemplateModule::balance_count(1, 1), 0);274        assert_eq!(TemplateModule::balance_count(1, 2), 5);275276        // split item scenario277        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 3));278        assert_eq!(TemplateModule::balance_count(1, 2), 2);279        assert_eq!(TemplateModule::balance_count(1, 3), 3);280281        // split item and new owner has account scenario282        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 1));283        assert_eq!(TemplateModule::fungible_item_id(1, 2).value, 1);284        assert_eq!(TemplateModule::fungible_item_id(1, 3).value, 4);285        assert_eq!(TemplateModule::balance_count(1, 2), 1);286        assert_eq!(TemplateModule::balance_count(1, 3), 4);287    });288}289290#[test]291fn transfer_refungible_item() {292    new_test_ext().execute_with(|| {293        default_limits();294        295        let collection_id = create_test_collection(&CollectionMode::ReFungible, 1);296297        let data = default_re_fungible_data();298        create_test_item(collection_id, &data.clone().into());299300        let origin1 = Origin::signed(1);301        let origin2 = Origin::signed(2);302        assert_eq!(303            TemplateModule::refungible_item_id(collection_id, 1).const_data,304            data.const_data305        );306        assert_eq!(307            TemplateModule::refungible_item_id(collection_id, 1).variable_data,308            data.variable_data309        );310        assert_eq!(311            TemplateModule::refungible_item_id(collection_id, 1).owner[0],312            Ownership {313                owner: 1,314                fraction: 1023315            }316        );317        assert_eq!(TemplateModule::balance_count(1, 1), 1023);318        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);319320        // change owner scenario321        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1023));322        assert_eq!(323            TemplateModule::refungible_item_id(1, 1).owner[0],324            Ownership {325                owner: 2,326                fraction: 1023327            }328        );329        assert_eq!(TemplateModule::balance_count(1, 1), 0);330        assert_eq!(TemplateModule::balance_count(1, 2), 1023);331        // assert_eq!(TemplateModule::address_tokens(1, 1), []);332        assert_eq!(TemplateModule::address_tokens(1, 2), [1]);333334        // split item scenario335        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 500));336        assert_eq!(337            TemplateModule::refungible_item_id(1, 1).owner[0],338            Ownership {339                owner: 2,340                fraction: 523341            }342        );343        assert_eq!(344            TemplateModule::refungible_item_id(1, 1).owner[1],345            Ownership {346                owner: 3,347                fraction: 500348            }349        );350        assert_eq!(TemplateModule::balance_count(1, 2), 523);351        assert_eq!(TemplateModule::balance_count(1, 3), 500);352        assert_eq!(TemplateModule::address_tokens(1, 2), [1]);353        assert_eq!(TemplateModule::address_tokens(1, 3), [1]);354355        // split item and new owner has account scenario356        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 200));357        assert_eq!(358            TemplateModule::refungible_item_id(1, 1).owner[0],359            Ownership {360                owner: 2,361                fraction: 323362            }363        );364        assert_eq!(365            TemplateModule::refungible_item_id(1, 1).owner[1],366            Ownership {367                owner: 3,368                fraction: 700369            }370        );371        assert_eq!(TemplateModule::balance_count(1, 2), 323);372        assert_eq!(TemplateModule::balance_count(1, 3), 700);373        assert_eq!(TemplateModule::address_tokens(1, 2), [1]);374        assert_eq!(TemplateModule::address_tokens(1, 3), [1]);375    });376}377378#[test]379fn transfer_nft_item() {380    new_test_ext().execute_with(|| {381        default_limits();382        383        let collection_id = create_test_collection(&CollectionMode::NFT, 1);384385        let data = default_nft_data();386        create_test_item(collection_id, &data.into());387        assert_eq!(TemplateModule::balance_count(1, 1), 1);388        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);389390        let origin1 = Origin::signed(1);391        // default scenario392        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));393        assert_eq!(TemplateModule::nft_item_id(1, 1).owner, 2);394        assert_eq!(TemplateModule::balance_count(1, 1), 0);395        assert_eq!(TemplateModule::balance_count(1, 2), 1);396        // assert_eq!(TemplateModule::address_tokens(1, 1), []);397        assert_eq!(TemplateModule::address_tokens(1, 2), [1]);398    });399}400401#[test]402fn nft_approve_and_transfer_from() {403    new_test_ext().execute_with(|| {404        default_limits();405        406        let collection_id = create_test_collection(&CollectionMode::NFT, 1);407408        let data = default_nft_data();409        create_test_item(collection_id, &data.into());410411        let origin1 = Origin::signed(1);412        let origin2 = Origin::signed(2);413414        assert_eq!(TemplateModule::balance_count(1, 1), 1);415        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);416417        // neg transfer418        assert_noop!(TemplateModule::transfer_from(419            origin2.clone(),420            1,421            2,422            1,423            1,424            1), Error::<Test>::NoPermission);425426        // do approve427        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));428        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);429        assert_eq!(430            TemplateModule::approved(1, (1, 1, 2)),431            5432        );433434        assert_ok!(TemplateModule::transfer_from(435            origin2.clone(),436            1,437            3,438            1,439            1,440            1441        ));442        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 4);443    });444}445446#[test]447fn nft_approve_and_transfer_from_white_list() {448    new_test_ext().execute_with(|| {449        default_limits();450        451        let collection_id = create_test_collection(&CollectionMode::NFT, 1);452453        let origin1 = Origin::signed(1);454        let origin2 = Origin::signed(2);455456        let data = default_nft_data();457        create_test_item(collection_id, &data.clone().into());458459        assert_eq!(TemplateModule::nft_item_id(1, 1).const_data, data.const_data);460        assert_eq!(TemplateModule::balance_count(1, 1), 1);461        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);462463        assert_ok!(TemplateModule::set_mint_permission(464            origin1.clone(),465            1,466            true467        ));468        assert_ok!(TemplateModule::set_public_access_mode(469            origin1.clone(),470            1,471            AccessMode::WhiteList472        ));473        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));474        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));475        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));476477        // do approve478        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));479        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);480        assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1, 5));481        assert_eq!(TemplateModule::approved(1, (1, 1, 3)), 5);482483        assert_ok!(TemplateModule::transfer_from(484            origin2.clone(),485            1,486            3,487            1,488            1,489            1490        ));491        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 4);492    });493}494495#[test]496fn refungible_approve_and_transfer_from() {497    new_test_ext().execute_with(|| {498        default_limits();499        500        let collection_id = create_test_collection(&CollectionMode::ReFungible, 1);501        502        let origin1 = Origin::signed(1);503        let origin2 = Origin::signed(2);504505        let data = default_re_fungible_data();506        create_test_item(collection_id, &data.into());507508        assert_eq!(TemplateModule::balance_count(1, 1), 1023);509        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);510511        assert_ok!(TemplateModule::set_mint_permission(512            origin1.clone(),513            1,514            true515        ));516        assert_ok!(TemplateModule::set_public_access_mode(517            origin1.clone(),518            1,519            AccessMode::WhiteList520        ));521        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));522        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));523        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));524525        // do approve526        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1023));527        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1023);528529        assert_ok!(TemplateModule::transfer_from(530            origin2.clone(),531            1,532            3,533            1,534            1,535            100536        ));537        assert_eq!(TemplateModule::balance_count(1, 1), 923);538        assert_eq!(TemplateModule::balance_count(1, 3), 100);539        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);540        assert_eq!(TemplateModule::address_tokens(1, 3), [1]);541542        assert_eq!(543            TemplateModule::approved(1, (1, 1, 2)),544            923545        );546    });547}548549#[test]550fn fungible_approve_and_transfer_from() {551    new_test_ext().execute_with(|| {552        default_limits();553        554        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);555        556        let data = default_fungible_data();557        create_test_item(collection_id, &data.into());558559        let origin1 = Origin::signed(1);560        let origin2 = Origin::signed(2);561562        assert_eq!(TemplateModule::balance_count(1, 1), 5);563564        assert_ok!(TemplateModule::set_mint_permission(565            origin1.clone(),566            1,567            true568        ));569        assert_ok!(TemplateModule::set_public_access_mode(570            origin1.clone(),571            1,572            AccessMode::WhiteList573        ));574        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));575        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));576        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));577578        // do approve579        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));580        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);581        assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1, 5));582        assert_eq!(TemplateModule::approved(1, (1, 1, 3)), 5);583        assert_eq!(584            TemplateModule::approved(1, (1, 1, 2)),585            5586        );587588        assert_ok!(TemplateModule::transfer_from(589            origin2.clone(),590            1,591            3,592            1,593            1,594            4595        ));596        assert_eq!(TemplateModule::balance_count(1, 1), 1);597        assert_eq!(TemplateModule::balance_count(1, 3), 4);598599        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1);600601        assert_noop!(TemplateModule::transfer_from(602            origin2.clone(),603            1,604            3,605            1,606            1,607            4608        ), Error::<Test>::TokenValueNotEnough);609    });610}611612#[test]613fn change_collection_owner() {614    new_test_ext().execute_with(|| {615        default_limits();616        617        let collection_id = create_test_collection(&CollectionMode::NFT, 1);618        619        let origin1 = Origin::signed(1);620        assert_ok!(TemplateModule::change_collection_owner(621            origin1.clone(),622            collection_id,623            2624        ));625        assert_eq!(TemplateModule::collection(collection_id).owner, 2);626    });627}628629#[test]630fn destroy_collection() {631    new_test_ext().execute_with(|| {632        default_limits();633        634        let collection_id = create_test_collection(&CollectionMode::NFT, 1);635        636        let origin1 = Origin::signed(1);637        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));638    });639}640641#[test]642fn burn_nft_item() {643    new_test_ext().execute_with(|| {644        default_limits();645        646        let collection_id = create_test_collection(&CollectionMode::NFT, 1);647648        let origin1 = Origin::signed(1);649        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));650        651        let data = default_nft_data();652        create_test_item(collection_id, &data.into());653654        // check balance (collection with id = 1, user id = 1)655        assert_eq!(TemplateModule::balance_count(1, 1), 1);656657        // burn item658        assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 5));659        assert_noop!(660            TemplateModule::burn_item(origin1.clone(), 1, 1, 5),661            Error::<Test>::TokenNotFound662        );663664        assert_eq!(TemplateModule::balance_count(1, 1), 0);665    });666}667668#[test]669fn burn_fungible_item() {670    new_test_ext().execute_with(|| {671        default_limits();672        673        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);674        675        let origin1 = Origin::signed(1);676        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));677        678        let data = default_fungible_data();679        create_test_item(collection_id, &data.into());680681        // check balance (collection with id = 1, user id = 1)682        assert_eq!(TemplateModule::balance_count(1, 1), 5);683684        // burn item685        assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 5));686        assert_noop!(687            TemplateModule::burn_item(origin1.clone(), 1, 1, 5),688            Error::<Test>::TokenNotFound689        );690691        assert_eq!(TemplateModule::balance_count(1, 1), 0);692    });693}694695#[test]696fn burn_refungible_item() {697    new_test_ext().execute_with(|| {698        default_limits();699        700        let collection_id = create_test_collection(&CollectionMode::ReFungible, 1);701        let origin1 = Origin::signed(1);702703        assert_ok!(TemplateModule::set_mint_permission(704            origin1.clone(),705            collection_id,706            true707        ));708        assert_ok!(TemplateModule::set_public_access_mode(709            origin1.clone(),710            collection_id,711            AccessMode::WhiteList712        ));713        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));714715        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));716        717        let data = default_re_fungible_data();718        create_test_item(collection_id, &data.into());719720        // check balance (collection with id = 1, user id = 2)721        assert_eq!(TemplateModule::balance_count(1, 1), 1023);722723        // burn item724        assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 1023));725        assert_noop!(726            TemplateModule::burn_item(origin1.clone(), 1, 1, 1023),727            Error::<Test>::TokenNotFound728        );729730        assert_eq!(TemplateModule::balance_count(1, 1), 0);731    });732}733734#[test]735fn add_collection_admin() {736    new_test_ext().execute_with(|| {737        default_limits();738        739        let collection1_id = create_test_collection_for_owner(&CollectionMode::NFT, 1, 1);740        create_test_collection_for_owner(&CollectionMode::NFT, 2, 2);741        create_test_collection_for_owner(&CollectionMode::NFT, 3, 3);742        743        let origin1 = Origin::signed(1);744745        // collection admin746        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 2));747        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 3));748749        assert_eq!(TemplateModule::admin_list_collection(collection1_id).contains(&2), true);750        assert_eq!(TemplateModule::admin_list_collection(collection1_id).contains(&3), true);751    });752}753754#[test]755fn remove_collection_admin() {756    new_test_ext().execute_with(|| {757        default_limits();758        759        let collection1_id = create_test_collection_for_owner(&CollectionMode::NFT, 1, 1);760        create_test_collection_for_owner(&CollectionMode::NFT, 2, 2);761        create_test_collection_for_owner(&CollectionMode::NFT, 3, 3);762763        let origin1 = Origin::signed(1);764        let origin2 = Origin::signed(2);765766        // collection admin767        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 2));768        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 3));769770        assert_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);771        assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);772773        // remove admin774        assert_ok!(TemplateModule::remove_collection_admin(775            origin2.clone(),776            1,777            3778        ));779        assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), false);780    });781}782783#[test]784fn balance_of() {785    new_test_ext().execute_with(|| {786        default_limits();787        788        let nft_collection_id = create_test_collection(&CollectionMode::NFT, 1);789        let fungible_collection_id = create_test_collection(&CollectionMode::Fungible(3), 2);790        let re_fungible_collection_id = create_test_collection(&CollectionMode::ReFungible, 3);791        792        // check balance before793        assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 0);794        assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 0);795        assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 0);796797        let nft_data = default_nft_data();798        create_test_item(nft_collection_id, &nft_data.into());799        800        let fungible_data = default_fungible_data();801        create_test_item(fungible_collection_id, &fungible_data.into());802        803        let re_fungible_data = default_re_fungible_data();804        create_test_item(re_fungible_collection_id, &re_fungible_data.into());805806        // check balance (collection with id = 1, user id = 1)807        assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 1);808        assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 5);809        assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 1023);810        assert_eq!(TemplateModule::nft_item_id(nft_collection_id, 1).owner, 1);811        assert_eq!(TemplateModule::fungible_item_id(fungible_collection_id, 1).value, 5);812        assert_eq!(TemplateModule::refungible_item_id(re_fungible_collection_id, 1).owner[0].owner, 1);813    });814}815816#[test]817fn approve() {818    new_test_ext().execute_with(|| {819        default_limits();820        821        let collection_id = create_test_collection(&CollectionMode::NFT, 1);822        823        let data = default_nft_data();824        create_test_item(collection_id, &data.into());825826        let origin1 = Origin::signed(1);827        828        // approve829        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1));830        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1);831    });832}833834#[test]835fn transfer_from() {836    new_test_ext().execute_with(|| {837        default_limits();838        839        let collection_id = create_test_collection(&CollectionMode::NFT, 1);840        let origin1 = Origin::signed(1);841        let origin2 = Origin::signed(2);842843        let data = default_nft_data();844        create_test_item(collection_id, &data.into());845846        // approve847        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1));848        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1);849850        assert_ok!(TemplateModule::set_mint_permission(851            origin1.clone(),852            1,853            true854        ));855        assert_ok!(TemplateModule::set_public_access_mode(856            origin1.clone(),857            1,858            AccessMode::WhiteList859        ));860        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));861        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));862        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));863864        assert_ok!(TemplateModule::transfer_from(865            origin2.clone(),866            1,867            2,868            1,869            1,870            1871        ));872873        // after transfer874        assert_eq!(TemplateModule::balance_count(1, 1), 0);875        assert_eq!(TemplateModule::balance_count(1, 2), 1);876    });877}878879// #endregion880881// Coverage tests region882// #region883884#[test]885fn owner_can_add_address_to_white_list() {886    new_test_ext().execute_with(|| {887        default_limits();888        889        let collection_id = create_test_collection(&CollectionMode::NFT, 1);890891        let origin1 = Origin::signed(1);892        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));893        assert_eq!(TemplateModule::white_list(collection_id, 2), true);894    });895}896897#[test]898fn admin_can_add_address_to_white_list() {899    new_test_ext().execute_with(|| {900        default_limits();901        902        let collection_id = create_test_collection(&CollectionMode::NFT, 1);903        let origin1 = Origin::signed(1);904        let origin2 = Origin::signed(2);905906        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));907        assert_ok!(TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3));908        assert_eq!(TemplateModule::white_list(collection_id, 3), true);909    });910}911912#[test]913fn nonprivileged_user_cannot_add_address_to_white_list() {914    new_test_ext().execute_with(|| {915        default_limits();916        917        let collection_id = create_test_collection(&CollectionMode::NFT, 1);918919        let origin2 = Origin::signed(2);920        assert_noop!(921            TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3),922            Error::<Test>::NoPermission923        );924    });925}926927#[test]928fn nobody_can_add_address_to_white_list_of_nonexisting_collection() {929    new_test_ext().execute_with(|| {930        default_limits();931932        let origin1 = Origin::signed(1);933934        assert_noop!(935            TemplateModule::add_to_white_list(origin1.clone(), 1, 2),936            Error::<Test>::CollectionNotFound937        );938    });939}940941#[test]942fn nobody_can_add_address_to_white_list_of_deleted_collection() {943    new_test_ext().execute_with(|| {944        default_limits();945        946        let collection_id = create_test_collection(&CollectionMode::NFT, 1);947948        let origin1 = Origin::signed(1);949        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));950        assert_noop!(951            TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2),952            Error::<Test>::CollectionNotFound953        );954    });955}956957// If address is already added to white list, nothing happens958#[test]959fn address_is_already_added_to_white_list() {960    new_test_ext().execute_with(|| {961        default_limits();962        963        let collection_id = create_test_collection(&CollectionMode::NFT, 1);964        let origin1 = Origin::signed(1);965        966        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));967        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));968        assert_eq!(TemplateModule::white_list(collection_id, 2), true);969    });970}971972#[test]973fn owner_can_remove_address_from_white_list() {974    new_test_ext().execute_with(|| {975        default_limits();976        977        let collection_id = create_test_collection(&CollectionMode::NFT, 1);978979        let origin1 = Origin::signed(1);980        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));981        assert_ok!(TemplateModule::remove_from_white_list(982            origin1.clone(),983            collection_id,984            2985        ));986        assert_eq!(TemplateModule::white_list(collection_id, 2), false);987    });988}989990#[test]991fn admin_can_remove_address_from_white_list() {992    new_test_ext().execute_with(|| {993        default_limits();994        995        let collection_id = create_test_collection(&CollectionMode::NFT, 1);996        let origin1 = Origin::signed(1);997        let origin2 = Origin::signed(2);998999        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));10001001        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 3));1002        assert_ok!(TemplateModule::remove_from_white_list(1003            origin2.clone(),1004            collection_id,1005            31006        ));1007        assert_eq!(TemplateModule::white_list(collection_id, 3), false);1008    });1009}10101011#[test]1012fn nonprivileged_user_cannot_remove_address_from_white_list() {1013    new_test_ext().execute_with(|| {1014        default_limits();1015        1016        let collection_id = create_test_collection(&CollectionMode::NFT, 1);1017        let origin1 = Origin::signed(1);1018        let origin2 = Origin::signed(2);10191020        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));1021        assert_noop!(1022            TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),1023            Error::<Test>::NoPermission1024        );1025        assert_eq!(TemplateModule::white_list(collection_id, 2), true);1026    });1027}10281029#[test]1030fn nobody_can_remove_address_from_white_list_of_nonexisting_collection() {1031    new_test_ext().execute_with(|| {1032        default_limits();1033        let origin1 = Origin::signed(1);10341035        assert_noop!(1036            TemplateModule::remove_from_white_list(origin1.clone(), 1, 2),1037            Error::<Test>::CollectionNotFound1038        );1039    });1040}10411042#[test]1043fn nobody_can_remove_address_from_white_list_of_deleted_collection() {1044    new_test_ext().execute_with(|| {1045        default_limits();1046        1047        let collection_id = create_test_collection(&CollectionMode::NFT, 1);1048        let origin1 = Origin::signed(1);1049        let origin2 = Origin::signed(2);10501051        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));1052        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));1053        assert_noop!(1054            TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),1055            Error::<Test>::CollectionNotFound1056        );1057        assert_eq!(TemplateModule::white_list(collection_id, 2), false);1058    });1059}10601061// If address is already removed from white list, nothing happens1062#[test]1063fn address_is_already_removed_from_white_list() {1064    new_test_ext().execute_with(|| {1065        default_limits();1066        1067        let collection_id = create_test_collection(&CollectionMode::NFT, 1);1068        let origin1 = Origin::signed(1);10691070        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));1071        assert_ok!(TemplateModule::remove_from_white_list(1072            origin1.clone(),1073            collection_id,1074            21075        ));1076        assert_ok!(TemplateModule::remove_from_white_list(1077            origin1.clone(),1078            collection_id,1079            21080        ));1081        assert_eq!(TemplateModule::white_list(collection_id, 2), false);1082    });1083}10841085// If Public Access mode is set to WhiteList, tokens can’t be transferred from a non-whitelisted address with transfer or transferFrom (2 tests)1086#[test]1087fn white_list_test_1() {1088    new_test_ext().execute_with(|| {1089        default_limits();1090        1091        let collection_id = create_test_collection(&CollectionMode::NFT, 1);10921093        let origin1 = Origin::signed(1);1094        1095        let data = default_nft_data();1096        create_test_item(collection_id, &data.into());10971098        assert_ok!(TemplateModule::set_public_access_mode(1099            origin1.clone(),1100            collection_id,1101            AccessMode::WhiteList1102        ));1103        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));11041105        assert_noop!(1106            TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),1107            Error::<Test>::AddresNotInWhiteList1108        );1109    });1110}11111112#[test]1113fn white_list_test_2() {1114    new_test_ext().execute_with(|| {1115        default_limits();1116        1117        let collection_id = create_test_collection(&CollectionMode::NFT, 1);1118        let origin1 = Origin::signed(1);1119        1120        let data = default_nft_data();1121        create_test_item(collection_id, &data.into());11221123        assert_ok!(TemplateModule::set_public_access_mode(1124            origin1.clone(),1125            collection_id,1126            AccessMode::WhiteList1127        ));1128        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));1129        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));11301131        // do approve1132        assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1, 1));1133        assert_eq!(TemplateModule::approved(1, (1, 1, 1)), 1);11341135        assert_ok!(TemplateModule::remove_from_white_list(1136            origin1.clone(),1137            1,1138            11139        ));11401141        assert_noop!(1142            TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1),1143            Error::<Test>::AddresNotInWhiteList1144        );1145    });1146}11471148// If Public Access mode is set to WhiteList, tokens can’t be transferred to a non-whitelisted address with transfer or transferFrom (2 tests)1149#[test]1150fn white_list_test_3() {1151    new_test_ext().execute_with(|| {1152        default_limits();1153        1154        let collection_id = create_test_collection(&CollectionMode::NFT, 1);11551156        let origin1 = Origin::signed(1);1157        1158        let data = default_nft_data();1159        create_test_item(collection_id, &data.into());11601161        assert_ok!(TemplateModule::set_public_access_mode(1162            origin1.clone(),1163            collection_id,1164            AccessMode::WhiteList1165        ));1166        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));11671168        assert_noop!(1169            TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),1170            Error::<Test>::AddresNotInWhiteList1171        );1172    });1173}11741175#[test]1176fn white_list_test_4() {1177    new_test_ext().execute_with(|| {1178        default_limits();1179        1180        let collection_id = create_test_collection(&CollectionMode::NFT, 1);11811182        let origin1 = Origin::signed(1);11831184        let data = default_nft_data();1185        create_test_item(collection_id, &data.into());11861187        assert_ok!(TemplateModule::set_public_access_mode(1188            origin1.clone(),1189            collection_id,1190            AccessMode::WhiteList1191        ));1192        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));1193        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));11941195        // do approve1196        assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1, 1));1197        assert_eq!(TemplateModule::approved(1, (1, 1, 1)), 1);11981199        assert_ok!(TemplateModule::remove_from_white_list(1200            origin1.clone(),1201            collection_id,1202            21203        ));12041205        assert_noop!(1206            TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1),1207            Error::<Test>::AddresNotInWhiteList1208        );1209    });1210}12111212// If Public Access mode is set to WhiteList, tokens can’t be destroyed by a non-whitelisted address (even if it owned them before enabling WhiteList mode)1213#[test]1214fn white_list_test_5() {1215    new_test_ext().execute_with(|| {1216        default_limits();1217        1218        let collection_id = create_test_collection(&CollectionMode::NFT, 1);12191220        let origin1 = Origin::signed(1);12211222        let data = default_nft_data();1223        create_test_item(collection_id, &data.into());12241225        assert_ok!(TemplateModule::set_public_access_mode(1226            origin1.clone(),1227            collection_id,1228            AccessMode::WhiteList1229        ));1230        assert_noop!(1231            TemplateModule::burn_item(origin1.clone(), 1, 1, 5),1232            Error::<Test>::AddresNotInWhiteList1233        );1234    });1235}12361237// If Public Access mode is set to WhiteList, token transfers can’t be Approved by a non-whitelisted address (see Approve method).1238#[test]1239fn white_list_test_6() {1240    new_test_ext().execute_with(|| {1241        default_limits();1242        1243        let collection_id = create_test_collection(&CollectionMode::NFT, 1);12441245        let origin1 = Origin::signed(1);12461247        let data = default_nft_data();1248        create_test_item(collection_id, &data.into());12491250        assert_ok!(TemplateModule::set_public_access_mode(1251            origin1.clone(),1252            collection_id,1253            AccessMode::WhiteList1254        ));12551256        // do approve1257        assert_noop!(1258            TemplateModule::approve(origin1.clone(), 1, 1, 1, 5),1259            Error::<Test>::AddresNotInWhiteList1260        );1261    });1262}12631264// If Public Access mode is set to WhiteList, tokens can be transferred from a whitelisted address with transfer or transferFrom (2 tests) and1265//          tokens can be transferred from a whitelisted address with transfer or transferFrom (2 tests)1266#[test]1267fn white_list_test_7() {1268    new_test_ext().execute_with(|| {1269        default_limits();1270        1271        let collection_id = create_test_collection(&CollectionMode::NFT, 1);12721273        let data = default_nft_data();1274        create_test_item(collection_id, &data.into());1275        1276        let origin1 = Origin::signed(1);12771278        assert_ok!(TemplateModule::set_public_access_mode(1279            origin1.clone(),1280            collection_id,1281            AccessMode::WhiteList1282        ));1283        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));1284        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));12851286        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1));1287    });1288}12891290#[test]1291fn white_list_test_8() {1292    new_test_ext().execute_with(|| {1293        default_limits();1294        1295        let collection_id = create_test_collection(&CollectionMode::NFT, 1);12961297        let data = default_nft_data();1298        create_test_item(collection_id, &data.into());1299        1300        let origin1 = Origin::signed(1);13011302        assert_ok!(TemplateModule::set_public_access_mode(1303            origin1.clone(),1304            collection_id,1305            AccessMode::WhiteList1306        ));1307        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));1308        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));13091310        // do approve1311        assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1, 5));1312        assert_eq!(TemplateModule::approved(1, (1, 1, 1)), 5);13131314        assert_ok!(TemplateModule::transfer_from(1315            origin1.clone(),1316            1,1317            2,1318            1,1319            1,1320            11321        ));1322    });1323}13241325// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens can be created by owner.1326#[test]1327fn white_list_test_9() {1328    new_test_ext().execute_with(|| {1329        default_limits();1330        1331        let collection_id = create_test_collection(&CollectionMode::NFT, 1);1332        let origin1 = Origin::signed(1);13331334        assert_ok!(TemplateModule::set_public_access_mode(1335            origin1.clone(),1336            collection_id,1337            AccessMode::WhiteList1338        ));1339        assert_ok!(TemplateModule::set_mint_permission(1340            origin1.clone(),1341            collection_id,1342            false1343        ));13441345        let data = default_nft_data();1346        create_test_item(collection_id, &data.into());1347    });1348}13491350// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens can be created by admin.1351#[test]1352fn white_list_test_10() {1353    new_test_ext().execute_with(|| {1354        default_limits();1355        1356        let collection_id = create_test_collection(&CollectionMode::NFT, 1);13571358        let origin1 = Origin::signed(1);1359        let origin2 = Origin::signed(2);13601361        assert_ok!(TemplateModule::set_public_access_mode(1362            origin1.clone(),1363            collection_id,1364            AccessMode::WhiteList1365        ));1366        assert_ok!(TemplateModule::set_mint_permission(1367            origin1.clone(),1368            collection_id,1369            false1370        ));13711372        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));13731374        assert_ok!(TemplateModule::create_item(1375            origin2.clone(),1376            collection_id,1377            2,1378            default_nft_data().into()1379        ));1380    });1381}13821383// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens cannot be created by non-privileged and white listed address.1384#[test]1385fn white_list_test_11() {1386    new_test_ext().execute_with(|| {1387        default_limits();1388        1389        let collection_id = create_test_collection(&CollectionMode::NFT, 1);13901391        let origin1 = Origin::signed(1);1392        let origin2 = Origin::signed(2);13931394        assert_ok!(TemplateModule::set_public_access_mode(1395            origin1.clone(),1396            collection_id,1397            AccessMode::WhiteList1398        ));1399        assert_ok!(TemplateModule::set_mint_permission(1400            origin1.clone(),1401            collection_id,1402            false1403        ));1404        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));14051406        assert_noop!(1407            TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),1408            Error::<Test>::PublicMintingNotAllowed1409        );1410    });1411}14121413// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens cannot be created by non-privileged and non-white listed address.1414#[test]1415fn white_list_test_12() {1416    new_test_ext().execute_with(|| {1417        default_limits();1418        1419        let collection_id = create_test_collection(&CollectionMode::NFT, 1);14201421        let origin1 = Origin::signed(1);1422        let origin2 = Origin::signed(2);14231424        assert_ok!(TemplateModule::set_public_access_mode(1425            origin1.clone(),1426            collection_id,1427            AccessMode::WhiteList1428        ));1429        assert_ok!(TemplateModule::set_mint_permission(1430            origin1.clone(),1431            collection_id,1432            false1433        ));14341435        assert_noop!(1436            TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),1437            Error::<Test>::PublicMintingNotAllowed1438        );1439    });1440}14411442// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens can be created by owner.1443#[test]1444fn white_list_test_13() {1445    new_test_ext().execute_with(|| {1446        default_limits();1447        1448        let collection_id = create_test_collection(&CollectionMode::NFT, 1);14491450        let origin1 = Origin::signed(1);14511452        assert_ok!(TemplateModule::set_public_access_mode(1453            origin1.clone(),1454            collection_id,1455            AccessMode::WhiteList1456        ));1457        assert_ok!(TemplateModule::set_mint_permission(1458            origin1.clone(),1459            collection_id,1460            true1461        ));14621463        let data = default_nft_data();1464        create_test_item(collection_id, &data.into());1465    });1466}14671468// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens can be created by admin.1469#[test]1470fn white_list_test_14() {1471    new_test_ext().execute_with(|| {1472        default_limits();1473        1474        let collection_id = create_test_collection(&CollectionMode::NFT, 1);14751476        let origin1 = Origin::signed(1);1477        let origin2 = Origin::signed(2);14781479        assert_ok!(TemplateModule::set_public_access_mode(1480            origin1.clone(),1481            collection_id,1482            AccessMode::WhiteList1483        ));1484        assert_ok!(TemplateModule::set_mint_permission(1485            origin1.clone(),1486            collection_id,1487            true1488        ));14891490        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));14911492        assert_ok!(TemplateModule::create_item(1493            origin2.clone(),1494            1,1495            2,1496            default_nft_data().into()1497        ));1498    });1499}15001501// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens cannot be created by non-privileged and non-white listed address.1502#[test]1503fn white_list_test_15() {1504    new_test_ext().execute_with(|| {1505        default_limits();1506        1507        let collection_id = create_test_collection(&CollectionMode::NFT, 1);15081509        let origin1 = Origin::signed(1);1510        let origin2 = Origin::signed(2);15111512        assert_ok!(TemplateModule::set_public_access_mode(1513            origin1.clone(),1514            collection_id,1515            AccessMode::WhiteList1516        ));1517        assert_ok!(TemplateModule::set_mint_permission(1518            origin1.clone(),1519            collection_id,1520            true1521        ));15221523        assert_noop!(1524            TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),1525            Error::<Test>::AddresNotInWhiteList1526        );1527    });1528}15291530// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens can be created by non-privileged and white listed address.1531#[test]1532fn white_list_test_16() {1533    new_test_ext().execute_with(|| {1534        default_limits();1535        1536        let collection_id = create_test_collection(&CollectionMode::NFT, 1);15371538        let origin1 = Origin::signed(1);1539        let origin2 = Origin::signed(2);15401541        assert_ok!(TemplateModule::set_public_access_mode(1542            origin1.clone(),1543            collection_id,1544            AccessMode::WhiteList1545        ));1546        assert_ok!(TemplateModule::set_mint_permission(1547            origin1.clone(),1548            collection_id,1549            true1550        ));1551        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));15521553        assert_ok!(TemplateModule::create_item(1554            origin2.clone(),1555            1,1556            2,1557            default_nft_data().into()1558        ));1559    });1560}15611562// Total number of collections. Positive test1563#[test]1564fn total_number_collections_bound() {1565    new_test_ext().execute_with(|| {1566        default_limits();1567        1568        create_test_collection(&CollectionMode::NFT, 1);1569    });1570}15711572// Total number of collections. Negotive test1573#[test]1574fn total_number_collections_bound_neg() {1575    new_test_ext().execute_with(|| {1576        default_limits();15771578        let origin1 = Origin::signed(1);15791580        for i in 0..default_collection_numbers_limit() {1581            create_test_collection(&CollectionMode::NFT, i + 1);1582        }15831584        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();1585        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();1586        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();15871588        // 11-th collection in chain. Expects error1589        assert_noop!(TemplateModule::create_collection(1590            origin1.clone(),1591            col_name1.clone(),1592            col_desc1.clone(),1593            token_prefix1.clone(),1594            CollectionMode::NFT1595        ), Error::<Test>::TotalCollectionsLimitExceeded);1596    });1597}15981599// Owned tokens by a single address. Positive test1600#[test]1601fn owned_tokens_bound() {1602    new_test_ext().execute_with(|| {1603        default_limits();1604        1605        let collection_id = create_test_collection(&CollectionMode::NFT, 1);16061607        let data = default_nft_data();1608        create_test_item(collection_id, &data.clone().into());1609        create_test_item(collection_id, &data.into());1610    });1611}16121613// Owned tokens by a single address. Negotive test1614#[test]1615fn owned_tokens_bound_neg() {1616    new_test_ext().execute_with(|| {1617        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1618            collection_numbers_limit: 10,1619            account_token_ownership_limit: 1,1620            collections_admins_limit: 5,1621            custom_data_limit: 2048,1622            nft_sponsor_transfer_timeout: 15,1623            fungible_sponsor_transfer_timeout: 15,1624            refungible_sponsor_transfer_timeout: 15,1625            const_on_chain_schema_limit: 1024,1626            offchain_schema_limit: 1024,1627            variable_on_chain_schema_limit: 1024,1628        }));1629        1630        let collection_id = create_test_collection(&CollectionMode::NFT, 1);16311632        let origin1 = Origin::signed(1);1633        let data = default_nft_data();1634        create_test_item(collection_id, &data.clone().into());16351636        assert_noop!(TemplateModule::create_item(1637            origin1.clone(),1638            1,1639            1,1640            data.into()1641        ),  Error::<Test>::AddressOwnershipLimitExceeded);1642    });1643}16441645// Number of collection admins. Positive test1646#[test]1647fn collection_admins_bound() {1648    new_test_ext().execute_with(|| {1649        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1650            collection_numbers_limit: 10,1651            account_token_ownership_limit: 10,1652            collections_admins_limit: 2,1653            custom_data_limit: 2048,1654            nft_sponsor_transfer_timeout: 15,1655            fungible_sponsor_transfer_timeout: 15,1656            refungible_sponsor_transfer_timeout: 15,1657            const_on_chain_schema_limit: 1024,1658            offchain_schema_limit: 1024,1659            variable_on_chain_schema_limit: 1024,1660        }));1661        1662        let collection_id = create_test_collection(&CollectionMode::NFT, 1);16631664        let origin1 = Origin::signed(1);1665        1666        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));1667        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3));1668    });1669}16701671// Number of collection admins. Negotive test1672#[test]1673fn collection_admins_bound_neg() {1674    new_test_ext().execute_with(|| {1675        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1676            collection_numbers_limit: 10,1677            account_token_ownership_limit: 1,1678            collections_admins_limit: 1,1679            custom_data_limit: 2048,1680            nft_sponsor_transfer_timeout: 15,1681            fungible_sponsor_transfer_timeout: 15,1682            refungible_sponsor_transfer_timeout: 15,1683            const_on_chain_schema_limit: 1024,1684            offchain_schema_limit: 1024,1685            variable_on_chain_schema_limit: 1024,1686        }));1687        1688        let collection_id = create_test_collection(&CollectionMode::NFT, 1);16891690        let origin1 = Origin::signed(1);16911692        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));1693        assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3), Error::<Test>::CollectionAdminsLimitExceeded);1694    });1695}16961697// NFT custom data size. Negative test const_data.1698#[test]1699fn custom_data_size_nft_const_data_bound_neg() {1700    new_test_ext().execute_with(|| {1701        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1702            collection_numbers_limit: 10,1703            account_token_ownership_limit: 10,1704            collections_admins_limit: 5,1705            custom_data_limit: 2,1706            nft_sponsor_transfer_timeout: 15,1707            fungible_sponsor_transfer_timeout: 15,1708            refungible_sponsor_transfer_timeout: 15,1709            const_on_chain_schema_limit: 1024,1710            offchain_schema_limit: 1024,1711            variable_on_chain_schema_limit: 1024,1712        }));1713        1714        let collection_id = create_test_collection(&CollectionMode::NFT, 1);17151716        let origin1 = Origin::signed(1);1717        let too_big_const_data = CreateItemData::NFT(CreateNftData{1718            const_data: vec![1, 2, 3, 4],1719            variable_data: vec![]1720        });17211722        assert_noop!(TemplateModule::create_item(1723            origin1.clone(),1724            collection_id,1725            1,1726            too_big_const_data1727        ), Error::<Test>::TokenConstDataLimitExceeded);1728    });1729}17301731// NFT custom data size. Negative test variable_data.1732#[test]1733fn custom_data_size_nft_variable_data_bound_neg() {1734    new_test_ext().execute_with(|| {1735        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1736            collection_numbers_limit: 10,1737            account_token_ownership_limit: 10,1738            collections_admins_limit: 5,1739            custom_data_limit: 2,1740            nft_sponsor_transfer_timeout: 15,1741            fungible_sponsor_transfer_timeout: 15,1742            refungible_sponsor_transfer_timeout: 15,1743            const_on_chain_schema_limit: 1024,1744            offchain_schema_limit: 1024,1745            variable_on_chain_schema_limit: 1024,1746        }));17471748        let collection_id = create_test_collection(&CollectionMode::NFT, 1);17491750        let origin1 = Origin::signed(1);1751        let too_big_const_data = CreateItemData::NFT(CreateNftData{1752            const_data: vec![],1753            variable_data: vec![1, 2, 3, 4]1754        });17551756        assert_noop!(TemplateModule::create_item(1757            origin1.clone(),1758            collection_id,1759            1,1760            too_big_const_data1761        ), Error::<Test>::TokenVariableDataLimitExceeded);1762    });1763}17641765// Re fungible custom data size. Negative test const_data.1766#[test]1767fn custom_data_size_re_fungible_const_data_bound_neg() {1768    new_test_ext().execute_with(|| {1769        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1770            collection_numbers_limit: 10,1771            account_token_ownership_limit: 10,1772            collections_admins_limit: 5,1773            custom_data_limit: 2,1774            nft_sponsor_transfer_timeout: 15,1775            fungible_sponsor_transfer_timeout: 15,1776            refungible_sponsor_transfer_timeout: 15,1777            const_on_chain_schema_limit: 1024,1778            offchain_schema_limit: 1024,1779            variable_on_chain_schema_limit: 1024,1780        }));17811782        let collection_id = create_test_collection(&CollectionMode::NFT, 1);17831784        let origin1 = Origin::signed(1);1785        let too_big_const_data = CreateItemData::NFT(CreateNftData{1786            const_data: vec![1, 2, 3, 4],1787            variable_data: vec![]1788        });17891790        assert_noop!(TemplateModule::create_item(1791            origin1.clone(),1792            collection_id,1793            1,1794            too_big_const_data1795        ), Error::<Test>::TokenConstDataLimitExceeded);1796    });1797}17981799// Re fungible custom data size. Negative test variable_data.1800#[test]1801fn custom_data_size_re_fungible_variable_data_bound_neg() {1802    new_test_ext().execute_with(|| {1803        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1804            collection_numbers_limit: 10,1805            account_token_ownership_limit: 10,1806            collections_admins_limit: 5,1807            custom_data_limit: 2,1808            nft_sponsor_transfer_timeout: 15,1809            fungible_sponsor_transfer_timeout: 15,1810            refungible_sponsor_transfer_timeout: 15,1811            const_on_chain_schema_limit: 1024,1812            offchain_schema_limit: 1024,1813            variable_on_chain_schema_limit: 1024,1814        }));18151816        let collection_id = create_test_collection(&CollectionMode::NFT, 1);18171818        let origin1 = Origin::signed(1);1819        let too_big_const_data = CreateItemData::NFT(CreateNftData{1820            const_data: vec![],1821            variable_data: vec![1, 2, 3, 4]1822        });18231824        assert_noop!(TemplateModule::create_item(1825            origin1.clone(),1826            collection_id,1827            1,1828            too_big_const_data1829        ), Error::<Test>::TokenVariableDataLimitExceeded);1830    });1831}1832// #endregion18331834#[test]1835fn set_const_on_chain_schema() {1836    new_test_ext().execute_with(|| {1837        default_limits();18381839        let collection_id = create_test_collection(&CollectionMode::NFT, 1);18401841        let origin1 = Origin::signed(1);1842        assert_ok!(TemplateModule::set_const_on_chain_schema(origin1, collection_id, b"test const on chain schema".to_vec()));18431844        assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, b"test const on chain schema".to_vec());1845        assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, b"".to_vec());1846    });1847}18481849#[test]1850fn set_variable_on_chain_schema() {1851    new_test_ext().execute_with(|| {1852        default_limits();1853        1854        let collection_id = create_test_collection(&CollectionMode::NFT, 1);18551856        let origin1 = Origin::signed(1);1857        assert_ok!(TemplateModule::set_variable_on_chain_schema(origin1, collection_id, b"test variable on chain schema".to_vec()));18581859        assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, b"".to_vec());1860        assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, b"test variable on chain schema".to_vec());1861    });1862}18631864#[test]1865fn set_variable_meta_data_on_nft_token_stores_variable_meta_data() {1866    new_test_ext().execute_with(|| {1867        default_limits();18681869        let collection_id = create_test_collection(&CollectionMode::NFT, 1);18701871        let origin1 = Origin::signed(1);1872        1873        let data = default_nft_data();1874        create_test_item(1, &data.into());1875        1876        let variable_data = b"test set_variable_meta_data method.".to_vec();1877        assert_ok!(TemplateModule::set_variable_meta_data(origin1, collection_id, 1, variable_data.clone()));18781879        assert_eq!(TemplateModule::nft_item_id(collection_id, 1).variable_data, variable_data);1880    });1881}18821883#[test]1884fn set_variable_meta_data_on_re_fungible_token_stores_variable_meta_data() {1885    new_test_ext().execute_with(|| {1886        default_limits();18871888        let collection_id = create_test_collection(&CollectionMode::ReFungible, 1);18891890        let origin1 = Origin::signed(1);18911892        let data = default_re_fungible_data();1893        create_test_item(1, &data.into());18941895        let variable_data = b"test set_variable_meta_data method.".to_vec();1896        assert_ok!(TemplateModule::set_variable_meta_data(origin1, collection_id, 1, variable_data.clone()));18971898        assert_eq!(TemplateModule::refungible_item_id(collection_id, 1).variable_data, variable_data);1899    });1900}190119021903#[test]1904fn set_variable_meta_data_on_fungible_token_fails() {1905    new_test_ext().execute_with(|| {1906        default_limits();19071908        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);19091910        let origin1 = Origin::signed(1);19111912        let data = default_fungible_data();1913        create_test_item(1, &data.into());19141915        let variable_data = b"test set_variable_meta_data method.".to_vec();1916        assert_noop!(TemplateModule::set_variable_meta_data(origin1, collection_id, 1, variable_data.clone()), Error::<Test>::CantStoreMetadataInFungibleTokens);1917    });1918}19191920#[test]1921fn set_variable_meta_data_on_nft_token_fails_for_big_data() {1922    new_test_ext().execute_with(|| {1923        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1924            collection_numbers_limit: default_collection_numbers_limit(),1925            account_token_ownership_limit: 10,1926            collections_admins_limit: 5,1927            custom_data_limit: 10,1928            nft_sponsor_transfer_timeout: 15,1929            fungible_sponsor_transfer_timeout: 15,1930            refungible_sponsor_transfer_timeout: 15,1931            const_on_chain_schema_limit: 1024,1932            offchain_schema_limit: 1024,1933            variable_on_chain_schema_limit: 1024,1934        }));19351936        let collection_id = create_test_collection(&CollectionMode::NFT, 1);19371938        let origin1 = Origin::signed(1);19391940        let data = default_nft_data();1941        create_test_item(1, &data.into());19421943        let variable_data = b"test set_variable_meta_data method, bigger than limits.".to_vec();1944        assert_noop!(TemplateModule::set_variable_meta_data(origin1, collection_id, 1, variable_data), Error::<Test>::TokenVariableDataLimitExceeded);1945    });1946}19471948#[test]1949fn set_variable_meta_data_on_re_fungible_token_fails_for_big_data() {1950    new_test_ext().execute_with(|| {1951        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1952            collection_numbers_limit: default_collection_numbers_limit(),1953            account_token_ownership_limit: 10,1954            collections_admins_limit: 5,1955            custom_data_limit: 10,1956            nft_sponsor_transfer_timeout: 15,1957            fungible_sponsor_transfer_timeout: 15,1958            refungible_sponsor_transfer_timeout: 15,1959            const_on_chain_schema_limit: 1024,1960            offchain_schema_limit: 1024,1961            variable_on_chain_schema_limit: 1024,1962        }));196319641965        let collection_id = create_test_collection(&CollectionMode::ReFungible, 1);19661967        let origin1 = Origin::signed(1);19681969        let data = default_re_fungible_data();1970        create_test_item(1, &data.into());19711972        let variable_data = b"test set_variable_meta_data method, bigger than limits.".to_vec();1973        assert_noop!(TemplateModule::set_variable_meta_data(origin1, collection_id, 1, variable_data), Error::<Test>::TokenVariableDataLimitExceeded);1974    });1975}
modifiedruntime/src/chain_extension.rsdiffbeforeafterboth
--- a/runtime/src/chain_extension.rs
+++ b/runtime/src/chain_extension.rs
@@ -60,7 +60,9 @@
                 }
                 let recipient = AccountId32::from(bytes_rec);
 
-                match pallet_nft::Module::<Runtime>::transfer_internal(sender, recipient, input.collection_id, input.token_id, input.amount) {
+                let collection = pallet_nft::Module::<Runtime>::get_collection(input.collection_id)?;
+
+                match pallet_nft::Module::<Runtime>::transfer_internal(sender, recipient, &collection, input.token_id, input.amount) {
                     Ok(_) => Ok(RetVal::Converging(func_id)),
                     _ => Err(DispatchError::Other("Transfer error"))
                 }
modifiedruntime/src/nft_weights.rsdiffbeforeafterboth
--- a/runtime/src/nft_weights.rs
+++ b/runtime/src/nft_weights.rs
@@ -133,6 +133,11 @@
             .saturating_add(DbWeight::get().reads(0 as Weight))
             .saturating_add(DbWeight::get().writes(2 as Weight))
     }    
+    fn set_variable_meta_data_sponsoring_rate_limit() -> Weight {
+        (3_500_000 as Weight)
+            .saturating_add(DbWeight::get().reads(1 as Weight))
+            .saturating_add(DbWeight::get().writes(2 as Weight))
+    }
     fn toggle_contract_white_list() -> Weight {
         (3_000_000 as Weight)
             .saturating_add(DbWeight::get().reads(0 as Weight))
modifiedruntime_types.jsondiffbeforeafterboth
--- a/runtime_types.json
+++ b/runtime_types.json
@@ -38,7 +38,7 @@
         "Confirmed": "AccountId"
       }
     },
-    "CollectionType": {
+    "Collection": {
       "Owner": "AccountId",
       "Mode": "CollectionMode",
       "Access": "AccessMode",
@@ -99,7 +99,8 @@
     },
     "CollectionLimits": {
       "AccountTokenOwnershipLimit": "u32",
-      "SponsoredMintSize": "u32",
+      "SponsoredDataSize": "u32",
+      "SponsoredDataRateLimit": "Option<BlockNumber>",
       "TokenLimit": "u32",
       "SponsorTimeout": "u32",
       "OwnerCanTransfer": "bool",
modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -46,7 +46,8 @@
     "testEnableContractSponsoring": "mocha --timeout 9999999 -r ts-node/register ./**/enableContractSponsoring.test.ts",
     "testSetContractSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setContractSponsoringRateLimit.test.ts",
     "testSetOffchainSchema": "mocha --timeout 9999999 -r ts-node/register ./**/setOffchainSchema.test.ts",
-    "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts"
+    "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts",
+    "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts"
   },
   "author": "",
   "license": "SEE LICENSE IN ../LICENSE",
modifiedtests/src/addCollectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/addCollectionAdmin.test.ts
+++ b/tests/src/addCollectionAdmin.test.ts
@@ -1,135 +1,135 @@
-//
-// This file is subject to the terms and conditions defined in
-// file 'LICENSE', which is part of this source code package.
-//
-
-import { ApiPromise } from '@polkadot/api';
-import BN from 'bn.js';
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import privateKey from './substrate/privateKey';
-import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';
-import {createCollectionExpectSuccess, destroyCollectionExpectSuccess} from './util/helpers';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-
-describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
-  it('Add collection admin.', async () => {
-    await usingApi(async (api) => {
-      const collectionId = await createCollectionExpectSuccess();
-      const alice = privateKey('//Alice');
-      const bob = privateKey('//Bob');
-
-      const collection: any = (await api.query.nft.collection(collectionId));
-      expect(collection.Owner.toString()).to.be.eq(alice.address);
-
-      const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address);
-      await submitTransactionAsync(alice, changeAdminTx);
-
-      const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
-      expect(adminListAfterAddAdmin).to.be.contains(bob.address);
-    });
-  });
-
-  it('Add admin using added collection admin.', async () => {
-    await usingApi(async (api) => {
-      const collectionId = await createCollectionExpectSuccess();
-      const Alice = privateKey('//Alice');
-      const Bob = privateKey('//Bob');
-      const Charlie = privateKey('//CHARLIE');
-
-      const collection: any = (await api.query.nft.collection(collectionId));
-      expect(collection.Owner.toString()).to.be.eq(Alice.address);
-
-      const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);
-      await submitTransactionAsync(Alice, changeAdminTx);
-
-      const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
-      expect(adminListAfterAddAdmin).to.be.contains(Bob.address);
-
-      const changeAdminTxCharlie = api.tx.nft.addCollectionAdmin(collectionId, Charlie.address);
-      await submitTransactionAsync(Bob, changeAdminTxCharlie);
-      const adminListAfterAddNewAdmin: any = (await api.query.nft.adminList(collectionId));
-      expect(adminListAfterAddNewAdmin).to.be.contains(Bob.address);
-      expect(adminListAfterAddNewAdmin).to.be.contains(Charlie.address);
-    });
-  });
-});
-
-describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
-  it("Not owner can't add collection admin.", async () => {
-    await usingApi(async (api) => {
-      const collectionId = await createCollectionExpectSuccess();
-      const alice = privateKey('//Alice');
-      const nonOwner = privateKey('//Bob_stash');
-
-      const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, alice.address);
-      await expect(submitTransactionExpectFailAsync(nonOwner, changeAdminTx)).to.be.rejected;
-
-      const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
-      expect(adminListAfterAddAdmin).not.to.be.contains(alice.address);
-
-      // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
-      await createCollectionExpectSuccess();
-    });
-  });
-  it("Can't add collection admin of not existing collection.", async () => {
-    await usingApi(async (api) => {
-      // tslint:disable-next-line: no-bitwise
-      const collectionId = (1 << 32) - 1;
-      const alice = privateKey('//Alice');
-      const bob = privateKey('//Bob');
-
-      const changeOwnerTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address);
-      await expect(submitTransactionExpectFailAsync(alice, changeOwnerTx)).to.be.rejected;
-
-      // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
-      await createCollectionExpectSuccess();
-    });
-  });
-
-  it("Can't add an admin to a destroyed collection.", async () => {
-    await usingApi(async (api) => {
-      const collectionId = await createCollectionExpectSuccess();
-      const Alice = privateKey('//Alice');
-      const Bob = privateKey('//Bob');
-      await destroyCollectionExpectSuccess(collectionId);
-      const changeOwnerTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);
-      await expect(submitTransactionExpectFailAsync(Alice, changeOwnerTx)).to.be.rejected;
-
-      // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
-      await createCollectionExpectSuccess();
-    });
-  });
-
-  it('Add an admin to a collection that has reached the maximum number of admins limit', async () => {
-    await usingApi(async (api: ApiPromise) => {
-      const Alice = privateKey('//Alice');
-      const accounts = [
-        'GsvVmjr1CBHwQHw84pPHMDxgNY3iBLz6Qn7qS3CH8qPhrHz',
-        'FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP',
-        'JKspFU6ohf1Grg3Phdzj2pSgWvsYWzSfKghhfzMbdhNBWs5',
-        'Fr4NzY1udSFFLzb2R3qxVQkwz9cZraWkyfH4h3mVVk7BK7P',
-        'DfnTB4z7eUvYRqcGtTpFsLC69o6tvBSC1pEv8vWPZFtCkaK',
-        'HnMAUz7r2G8G3hB27SYNyit5aJmh2a5P4eMdDtACtMFDbam',
-        'DE14BzQ1bDXWPKeLoAqdLAm1GpyAWaWF1knF74cEZeomTBM',
-      ];
-      const collectionId = await createCollectionExpectSuccess();
-
-      const chainLimit = await api.query.nft.chainLimit() as unknown as { CollectionAdminsLimit: BN };
-      const chainAdminLimit = chainLimit.CollectionAdminsLimit.toNumber();
-      expect(chainAdminLimit).to.be.equal(5);
-
-      for (let i = 0; i < chainAdminLimit; i++) {
-        const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, accounts[i]);
-        await submitTransactionAsync(Alice, changeAdminTx);
-        const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
-        expect(adminListAfterAddAdmin).to.be.contains(accounts[i]);
-      }
-
-      const tx = api.tx.nft.addCollectionAdmin(collectionId, accounts[chainAdminLimit]);
-      await expect(submitTransactionExpectFailAsync(Alice, tx)).to.be.rejected;
-    });
-  });
-});
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
+import { ApiPromise } from '@polkadot/api';
+import BN from 'bn.js';
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+import privateKey from './substrate/privateKey';
+import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';
+import {createCollectionExpectSuccess, destroyCollectionExpectSuccess} from './util/helpers';
+
+chai.use(chaiAsPromised);
+const expect = chai.expect;
+
+describe('Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
+  it('Add collection admin.', async () => {
+    await usingApi(async (api) => {
+      const collectionId = await createCollectionExpectSuccess();
+      const alice = privateKey('//Alice');
+      const bob = privateKey('//Bob');
+
+      const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
+      expect(collection.Owner.toString()).to.be.eq(alice.address);
+
+      const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address);
+      await submitTransactionAsync(alice, changeAdminTx);
+
+      const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
+      expect(adminListAfterAddAdmin).to.be.contains(bob.address);
+    });
+  });
+
+  it('Add admin using added collection admin.', async () => {
+    await usingApi(async (api) => {
+      const collectionId = await createCollectionExpectSuccess();
+      const Alice = privateKey('//Alice');
+      const Bob = privateKey('//Bob');
+      const Charlie = privateKey('//CHARLIE');
+
+      const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
+      expect(collection.Owner.toString()).to.be.eq(Alice.address);
+
+      const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);
+      await submitTransactionAsync(Alice, changeAdminTx);
+
+      const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
+      expect(adminListAfterAddAdmin).to.be.contains(Bob.address);
+
+      const changeAdminTxCharlie = api.tx.nft.addCollectionAdmin(collectionId, Charlie.address);
+      await submitTransactionAsync(Bob, changeAdminTxCharlie);
+      const adminListAfterAddNewAdmin: any = (await api.query.nft.adminList(collectionId));
+      expect(adminListAfterAddNewAdmin).to.be.contains(Bob.address);
+      expect(adminListAfterAddNewAdmin).to.be.contains(Charlie.address);
+    });
+  });
+});
+
+describe('Negative Integration Test addCollectionAdmin(collection_id, new_admin_id):', () => {
+  it("Not owner can't add collection admin.", async () => {
+    await usingApi(async (api) => {
+      const collectionId = await createCollectionExpectSuccess();
+      const alice = privateKey('//Alice');
+      const nonOwner = privateKey('//Bob_stash');
+
+      const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, alice.address);
+      await expect(submitTransactionExpectFailAsync(nonOwner, changeAdminTx)).to.be.rejected;
+
+      const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
+      expect(adminListAfterAddAdmin).not.to.be.contains(alice.address);
+
+      // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
+      await createCollectionExpectSuccess();
+    });
+  });
+  it("Can't add collection admin of not existing collection.", async () => {
+    await usingApi(async (api) => {
+      // tslint:disable-next-line: no-bitwise
+      const collectionId = (1 << 32) - 1;
+      const alice = privateKey('//Alice');
+      const bob = privateKey('//Bob');
+
+      const changeOwnerTx = api.tx.nft.addCollectionAdmin(collectionId, bob.address);
+      await expect(submitTransactionExpectFailAsync(alice, changeOwnerTx)).to.be.rejected;
+
+      // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
+      await createCollectionExpectSuccess();
+    });
+  });
+
+  it("Can't add an admin to a destroyed collection.", async () => {
+    await usingApi(async (api) => {
+      const collectionId = await createCollectionExpectSuccess();
+      const Alice = privateKey('//Alice');
+      const Bob = privateKey('//Bob');
+      await destroyCollectionExpectSuccess(collectionId);
+      const changeOwnerTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);
+      await expect(submitTransactionExpectFailAsync(Alice, changeOwnerTx)).to.be.rejected;
+
+      // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
+      await createCollectionExpectSuccess();
+    });
+  });
+
+  it('Add an admin to a collection that has reached the maximum number of admins limit', async () => {
+    await usingApi(async (api: ApiPromise) => {
+      const Alice = privateKey('//Alice');
+      const accounts = [
+        'GsvVmjr1CBHwQHw84pPHMDxgNY3iBLz6Qn7qS3CH8qPhrHz',
+        'FoQJpPyadYccjavVdTWxpxU7rUEaYhfLCPwXgkfD6Zat9QP',
+        'JKspFU6ohf1Grg3Phdzj2pSgWvsYWzSfKghhfzMbdhNBWs5',
+        'Fr4NzY1udSFFLzb2R3qxVQkwz9cZraWkyfH4h3mVVk7BK7P',
+        'DfnTB4z7eUvYRqcGtTpFsLC69o6tvBSC1pEv8vWPZFtCkaK',
+        'HnMAUz7r2G8G3hB27SYNyit5aJmh2a5P4eMdDtACtMFDbam',
+        'DE14BzQ1bDXWPKeLoAqdLAm1GpyAWaWF1knF74cEZeomTBM',
+      ];
+      const collectionId = await createCollectionExpectSuccess();
+
+      const chainLimit = await api.query.nft.chainLimit() as unknown as { CollectionAdminsLimit: BN };
+      const chainAdminLimit = chainLimit.CollectionAdminsLimit.toNumber();
+      expect(chainAdminLimit).to.be.equal(5);
+
+      for (let i = 0; i < chainAdminLimit; i++) {
+        const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, accounts[i]);
+        await submitTransactionAsync(Alice, changeAdminTx);
+        const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
+        expect(adminListAfterAddAdmin).to.be.contains(accounts[i]);
+      }
+
+      const tx = api.tx.nft.addCollectionAdmin(collectionId, accounts[chainAdminLimit]);
+      await expect(submitTransactionExpectFailAsync(Alice, tx)).to.be.rejected;
+    });
+  });
+});
modifiedtests/src/change-collection-owner.test.tsdiffbeforeafterboth
--- a/tests/src/change-collection-owner.test.ts
+++ b/tests/src/change-collection-owner.test.ts
@@ -19,13 +19,13 @@
       const alice = privateKey('//Alice');
       const bob = privateKey('//Bob');
 
-      const collection: any = (await api.query.nft.collection(collectionId));
+      const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
       expect(collection.Owner.toString()).to.be.eq(alice.address);
 
       const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address);
       await submitTransactionAsync(alice, changeOwnerTx);
 
-      const collectionAfterOwnerChange: any = (await api.query.nft.collection(collectionId));
+      const collectionAfterOwnerChange: any = (await api.query.nft.collectionById(collectionId)).toJSON();
       expect(collectionAfterOwnerChange.Owner.toString()).to.be.eq(bob.address);
     });
   });
@@ -41,7 +41,7 @@
       const changeOwnerTx = api.tx.nft.changeCollectionOwner(collectionId, bob.address);
       await expect(submitTransactionExpectFailAsync(bob, changeOwnerTx)).to.be.rejected;
 
-      const collectionAfterOwnerChange: any = (await api.query.nft.collection(collectionId));
+      const collectionAfterOwnerChange: any = (await api.query.nft.collectionById(collectionId)).toJSON();
       expect(collectionAfterOwnerChange.Owner.toString()).to.be.eq(alice.address);
 
       // Verifying that nothing bad happened (network is live, new collections can be created, etc.)
modifiedtests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/removeCollectionAdmin.test.ts
+++ b/tests/src/removeCollectionAdmin.test.ts
@@ -19,7 +19,7 @@
       const collectionId = await createCollectionExpectSuccess();
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
-      const collection: any = (await api.query.nft.collection(collectionId));
+      const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
       expect(collection.Owner.toString()).to.be.eq(Alice.address);
       // first - add collection admin Bob
       const addAdminTx = api.tx.nft.addCollectionAdmin(collectionId, Bob.address);
modifiedtests/src/setCollectionLimits.test.tsdiffbeforeafterboth
--- a/tests/src/setCollectionLimits.test.ts
+++ b/tests/src/setCollectionLimits.test.ts
@@ -61,12 +61,12 @@
 
       // tslint:disable-next-line:no-unused-expression
       expect(result.success).to.be.true;
-      expect(collectionInfo.Limits.AccountTokenOwnershipLimit.toNumber()).to.be.equal(accountTokenOwnershipLimit);
-      expect(collectionInfo.Limits.SponsoredMintSize.toNumber()).to.be.equal(sponsoredDataSize);
-      expect(collectionInfo.Limits.TokenLimit.toNumber()).to.be.equal(tokenLimit);
-      expect(collectionInfo.Limits.SponsorTimeout.toNumber()).to.be.equal(sponsorTimeout);
-      expect(collectionInfo.Limits.OwnerCanTransfer.valueOf()).to.be.true;
-      expect(collectionInfo.Limits.OwnerCanDestroy.valueOf()).to.be.true;
+      expect(collectionInfo.Limits.AccountTokenOwnershipLimit).to.be.equal(accountTokenOwnershipLimit);
+      expect(collectionInfo.Limits.SponsoredDataSize).to.be.equal(sponsoredDataSize);
+      expect(collectionInfo.Limits.TokenLimit).to.be.equal(tokenLimit);
+      expect(collectionInfo.Limits.SponsorTimeout).to.be.equal(sponsorTimeout);
+      expect(collectionInfo.Limits.OwnerCanTransfer).to.be.true;
+      expect(collectionInfo.Limits.OwnerCanDestroy).to.be.true;
     });
   });
 });
modifiedtests/src/setConstOnChainSchema.test.tsdiffbeforeafterboth
--- a/tests/src/setConstOnChainSchema.test.ts
+++ b/tests/src/setConstOnChainSchema.test.ts
@@ -36,7 +36,7 @@
   it('Run extrinsic with parameters of the collection id, set the scheme', async () => {
       await usingApi(async (api) => {
       const collectionId = await createCollectionExpectSuccess();
-      const collection: any = (await api.query.nft.collection(collectionId));
+      const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
       expect(collection.Owner.toString()).to.be.eq(Alice.address);
       const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);
       await submitTransactionAsync(Alice, setShema);
@@ -48,7 +48,7 @@
         const collectionId = await createCollectionExpectSuccess();
         const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);
         await submitTransactionAsync(Alice, setShema);
-        const collection: any = (await api.query.nft.collection(collectionId));
+        const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
         expect(collection.ConstOnChainSchema.toString()).to.be.eq(Shema);
 
     });
@@ -86,7 +86,7 @@
   it('Execute method not on behalf of the collection owner', async () => {
     await usingApi(async (api) => {
       const collectionId = await createCollectionExpectSuccess();
-      const collection: any = (await api.query.nft.collection(collectionId));
+      const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
       expect(collection.Owner.toString()).to.be.eq(Alice.address);
       const setShema = api.tx.nft.setConstOnChainSchema(collectionId, Shema);
       await expect(submitTransactionExpectFailAsync(Bob, setShema)).to.be.rejected;
modifiedtests/src/setOffchainSchema.test.tsdiffbeforeafterboth
--- a/tests/src/setOffchainSchema.test.ts
+++ b/tests/src/setOffchainSchema.test.ts
@@ -36,7 +36,7 @@
     await setOffchainSchemaExpectSuccess(alice, collectionId, DATA);
     const collection = await queryCollectionExpectSuccess(collectionId);
 
-    expect(Array.from(collection.OffchainSchema)).to.be.deep.equal(DATA);
+    expect(collection.OffchainSchema).to.be.equal('0x' + Buffer.from(DATA).toString('hex'));
   });
 });
 
addedtests/src/setVariableMetadataSponsoringRateLimit.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/setVariableMetadataSponsoringRateLimit.test.ts
@@ -0,0 +1,80 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
+import { IKeyringPair } from '@polkadot/types/types';
+import privateKey from './substrate/privateKey';
+import usingApi from './substrate/substrate-api';
+import {
+  confirmSponsorshipExpectSuccess,
+  createCollectionExpectSuccess,
+  createItemExpectSuccess,
+  findUnusedAddress,
+  setCollectionLimitsExpectSuccess,
+  setCollectionSponsorExpectSuccess,
+  setVariableMetaDataExpectFailure,
+  setVariableMetaDataExpectSuccess,
+} from './util/helpers';
+
+describe('Integration Test setVariableMetadataSponsoringRateLimit', () => {
+  let alice: IKeyringPair;
+  let userWithNoBalance: IKeyringPair;
+
+  before(async () => {
+    await usingApi(async (api) => {
+      alice = privateKey('//Alice');
+      userWithNoBalance = await findUnusedAddress(api);
+    });
+  });
+
+  it('sponsored setVariableMetaData can be called twice with pause for free', async () => {
+    const collectionId = await createCollectionExpectSuccess();
+    await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+    await confirmSponsorshipExpectSuccess(collectionId);
+    await setCollectionLimitsExpectSuccess(alice, collectionId, {
+      SponsoredDataRateLimit: 0,
+    });
+
+    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address);
+    await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1, 2, 3]);
+    await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1, 2, 3]);
+  });
+
+  it('sponsored setVariableMetaData can\'t be called twice without pause for free', async () => {
+    const collectionId = await createCollectionExpectSuccess();
+    await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+    await confirmSponsorshipExpectSuccess(collectionId);
+    await setCollectionLimitsExpectSuccess(alice, collectionId, {
+      SponsoredDataRateLimit: 10,
+    });
+
+    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address);
+    await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1, 2, 3]);
+    await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1, 2, 3]);
+  });
+
+  it('sponsored setVariableMetaData can\'t be called for free with variable metadata above collection limits', async () => {
+    const collectionId = await createCollectionExpectSuccess();
+    await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+    await confirmSponsorshipExpectSuccess(collectionId);
+    await setCollectionLimitsExpectSuccess(alice, collectionId, {
+      SponsoredDataRateLimit: 0,
+      SponsoredDataSize: 1,
+    });
+    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address);
+
+    await setVariableMetaDataExpectSuccess(userWithNoBalance, collectionId, itemId, [1]);
+    await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1, 2]);
+  });
+
+  it.only('Default value of rate limit does not sponsor setting variable metadata', async () => {
+    const collectionId = await createCollectionExpectSuccess();
+    await setCollectionSponsorExpectSuccess(collectionId, alice.address);
+    await confirmSponsorshipExpectSuccess(collectionId);
+
+    const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', userWithNoBalance.address);
+    await setVariableMetaDataExpectFailure(userWithNoBalance, collectionId, itemId, [1]);
+  });
+
+});
modifiedtests/src/setVariableOnChainSchema.test.tsdiffbeforeafterboth
--- a/tests/src/setVariableOnChainSchema.test.ts
+++ b/tests/src/setVariableOnChainSchema.test.ts
@@ -1,96 +1,96 @@
-//
-// This file is subject to the terms and conditions defined in
-// file 'LICENSE', which is part of this source code package.
-//
-
-import { Keyring } from '@polkadot/api';
-import { IKeyringPair } from '@polkadot/types/types';
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';
-import {
-  createCollectionExpectSuccess,
-  destroyCollectionExpectSuccess,
-} from './util/helpers';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-
-let Alice: IKeyringPair;
-let Bob: IKeyringPair;
-let Schema: any;
-let largeSchema: any;
-
-before(async () => {
-  await usingApi(async (api) => {
-    const keyring = new Keyring({ type: 'sr25519' });
-    Alice = keyring.addFromUri('//Alice');
-    Bob = keyring.addFromUri('//Bob');
-    Schema = '0x31';
-    largeSchema = new Array(4097).fill(0xff);
-
-  });
-});
-describe('Integration Test ext. setVariableOnChainSchema()', () => {
-
-  it('Run extrinsic with parameters of the collection id, set the scheme', async () => {
-      await usingApi(async (api) => {
-      const collectionId = await createCollectionExpectSuccess();
-      const collection: any = (await api.query.nft.collection(collectionId));
-      expect(collection.Owner.toString()).to.be.eq(Alice.address);
-      const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
-      await submitTransactionAsync(Alice, setSchema);
-    });
-  });
-
-  it('Checking collection data using the setVariableOnChainSchema parameter', async () => {
-      await usingApi(async (api) => {
-        const collectionId = await createCollectionExpectSuccess();
-        const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
-        await submitTransactionAsync(Alice, setSchema);
-        const collection: any = (await api.query.nft.collection(collectionId));
-        expect(collection.VariableOnChainSchema.toString()).to.be.eq(Schema);
-
-    });
-  });
-});
-
-describe('Negative Integration Test ext. setVariableOnChainSchema()', () => {
-
-  it('Set a non-existent collection', async () => {
-    await usingApi(async (api) => {
-      // tslint:disable-next-line: radix
-      const collectionId = parseInt((await api.query.nft.createdCollectionCount()).toString()) + 1;
-      const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
-      await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected;
-    });
-  });
-
-  it('Set a previously deleted collection', async () => {
-    await usingApi(async (api) => {
-      const collectionId = await createCollectionExpectSuccess();
-      await destroyCollectionExpectSuccess(collectionId);
-      const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
-      await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected;
-    });
-  });
-
-  it('Set invalid data in schema (size too large:> 1024b)', async () => {
-    await usingApi(async (api) => {
-      const collectionId = await createCollectionExpectSuccess();
-      const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, largeSchema);
-      await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected;
-    });
-  });
-
-  it('Execute method not on behalf of the collection owner', async () => {
-    await usingApi(async (api) => {
-      const collectionId = await createCollectionExpectSuccess();
-      const collection: any = (await api.query.nft.collection(collectionId));
-      expect(collection.Owner.toString()).to.be.eq(Alice.address);
-      const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
-      await expect(submitTransactionExpectFailAsync(Bob, setSchema)).to.be.rejected;
-    });
-  });
-
-});
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
+import { Keyring } from '@polkadot/api';
+import { IKeyringPair } from '@polkadot/types/types';
+import chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';
+import {
+  createCollectionExpectSuccess,
+  destroyCollectionExpectSuccess,
+} from './util/helpers';
+
+chai.use(chaiAsPromised);
+const expect = chai.expect;
+
+let Alice: IKeyringPair;
+let Bob: IKeyringPair;
+let Schema: any;
+let largeSchema: any;
+
+before(async () => {
+  await usingApi(async (api) => {
+    const keyring = new Keyring({ type: 'sr25519' });
+    Alice = keyring.addFromUri('//Alice');
+    Bob = keyring.addFromUri('//Bob');
+    Schema = '0x31';
+    largeSchema = new Array(4097).fill(0xff);
+
+  });
+});
+describe('Integration Test ext. setVariableOnChainSchema()', () => {
+
+  it('Run extrinsic with parameters of the collection id, set the scheme', async () => {
+      await usingApi(async (api) => {
+      const collectionId = await createCollectionExpectSuccess();
+      const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
+      expect(collection.Owner.toString()).to.be.eq(Alice.address);
+      const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
+      await submitTransactionAsync(Alice, setSchema);
+    });
+  });
+
+  it('Checking collection data using the setVariableOnChainSchema parameter', async () => {
+      await usingApi(async (api) => {
+        const collectionId = await createCollectionExpectSuccess();
+        const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
+        await submitTransactionAsync(Alice, setSchema);
+        const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
+        expect(collection.VariableOnChainSchema.toString()).to.be.eq(Schema);
+
+    });
+  });
+});
+
+describe('Negative Integration Test ext. setVariableOnChainSchema()', () => {
+
+  it('Set a non-existent collection', async () => {
+    await usingApi(async (api) => {
+      // tslint:disable-next-line: radix
+      const collectionId = parseInt((await api.query.nft.createdCollectionCount()).toString()) + 1;
+      const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
+      await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected;
+    });
+  });
+
+  it('Set a previously deleted collection', async () => {
+    await usingApi(async (api) => {
+      const collectionId = await createCollectionExpectSuccess();
+      await destroyCollectionExpectSuccess(collectionId);
+      const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
+      await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected;
+    });
+  });
+
+  it('Set invalid data in schema (size too large:> 1024b)', async () => {
+    await usingApi(async (api) => {
+      const collectionId = await createCollectionExpectSuccess();
+      const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, largeSchema);
+      await expect(submitTransactionExpectFailAsync(Alice, setSchema)).to.be.rejected;
+    });
+  });
+
+  it('Execute method not on behalf of the collection owner', async () => {
+    await usingApi(async (api) => {
+      const collectionId = await createCollectionExpectSuccess();
+      const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
+      expect(collection.Owner.toString()).to.be.eq(Alice.address);
+      const setSchema = api.tx.nft.setVariableOnChainSchema(collectionId, Schema);
+      await expect(submitTransactionExpectFailAsync(Bob, setSchema)).to.be.rejected;
+    });
+  });
+
+});
modifiedtests/src/types.tsdiffbeforeafterboth
--- a/tests/src/types.ts
+++ b/tests/src/types.ts
@@ -13,10 +13,11 @@
   Description: [BN, BN]; // utf16
   isReFungible: boolean;
   Limits: {
-    AccountTokenOwnershipLimit: BN;
-    SponsoredMintSize: BN;
-    TokenLimit: BN;
-    SponsorTimeout: BN;
+    AccountTokenOwnershipLimit: number;
+    SponsoredDataSize: number;
+    SponsoredDataRateLimit?: number,
+    TokenLimit: number;
+    SponsorTimeout: number;
     OwnerCanTransfer: boolean;
     OwnerCanDestroy: boolean;
   };
modifiedtests/src/util/contracthelpers.tsdiffbeforeafterboth
--- a/tests/src/util/contracthelpers.ts
+++ b/tests/src/util/contracthelpers.ts
@@ -22,9 +22,9 @@
 
 function deployContract(alice: IKeyringPair, code: CodePromise, constructor: string = 'default', ...args: any[]): Promise<Contract> {
   return new Promise<Contract>(async (resolve, reject) => {
-    const unsub = await code
+    const unsub = await (code as any)
       .tx[constructor]({value: endowment, gasLimit}, ...args)
-      .signAndSend(alice, (result) => {
+      .signAndSend(alice, (result: any) => {
         if (result.status.isInBlock || result.status.isFinalized) {
           // here we have an additional field in the result, containing the blueprint
           resolve((result as any).contract);
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -212,7 +212,7 @@
     const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);
 
     // Get the collection
-    const collection: any = (await api.query.nft.collection(result.collectionId)).toJSON();
+    const collection: any = (await api.query.nft.collectionById(result.collectionId)).toJSON();
 
     // What to expect
     // tslint:disable-next-line:no-unused-expression
@@ -324,18 +324,17 @@
     const result = getDestroyResult(events);
 
     // Get the collection
-    const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
+    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
 
     // What to expect
     expect(result).to.be.true;
-    expect(collection).to.be.not.null;
-    expect(collection.Owner).to.be.equal(nullPublicKey);
+    expect(collection).to.be.null;
   });
 }
 
 export async function queryCollectionLimits(collectionId: number) {
   return await usingApi(async (api) => {
-    return ((await api.query.nft.collection(collectionId)).toJSON() as any).Limits;
+    return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;
   });
 }
 
@@ -373,7 +372,7 @@
     const result = getGenericResult(events);
 
     // Get the collection
-    const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
+    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
 
     // What to expect
     expect(result.success).to.be.true;
@@ -393,7 +392,7 @@
     const result = getGenericResult(events);
 
     // Get the collection
-    const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
+    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
 
     // What to expect
     expect(result.success).to.be.true;
@@ -431,7 +430,7 @@
     const result = getGenericResult(events);
 
     // Get the collection
-    const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
+    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
 
     // What to expect
     expect(result.success).to.be.true;
@@ -839,7 +838,7 @@
     const result = getGenericResult(events);
 
     // Get the collection
-    const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
+    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
 
     // What to expect
     // tslint:disable-next-line:no-unused-expression
@@ -865,7 +864,7 @@
     const result = getGenericResult(events);
 
     // Get the collection
-    const collection: any = (await api.query.nft.collection(collectionId)).toJSON();
+    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();
 
     // What to expect
     // tslint:disable-next-line:no-unused-expression
@@ -947,7 +946,7 @@
 
 export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)
   : Promise<ICollectionInterface | null> => {
-  return await api.query.nft.collection(collectionId) as unknown as ICollectionInterface;
+  return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;
 };
 
 export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {
@@ -957,6 +956,6 @@
 
 export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {
   return await usingApi(async (api) => {
-    return (await api.query.nft.collection(collectionId)) as unknown as ICollectionInterface;
+    return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;
   });
 }