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

difftreelog

Merge pull request #16 from usetech-llc/feature/NFTPAR-142

str-mv2020-11-16parents: #6d406a4 #eca8c84.patch.diff
in: master
Feature/nftpar-142

7 files changed

modifiedREADME.mddiffbeforeafterboth
--- a/README.md
+++ b/README.md
@@ -167,9 +167,9 @@
   "CollectionMode": {
     "_enum": {
       "Invalid": null,
-      "NFT": "u32",
+      "NFT": null,
       "Fungible": "u32",
-      "ReFungible": "(u32, u32)"
+      "ReFungible": "u32"
     }
   },
   "Ownership": {
@@ -189,7 +189,8 @@
   "NftItemType": {
     "Collection": "u64",
     "Owner": "AccountId",
-    "Data": "Vec<u8>"
+    "ConstData": "Vec<u8>",
+    "VariableData": "Vec<u8>"
   },
   "Ownership": {
     "owner": "AccountId",
@@ -198,7 +199,8 @@
   "ReFungibleItemType": {
     "Collection": "u64",
     "Owner": "Vec<Ownership<AccountId>>",
-    "Data": "Vec<u8>"
+    "ConstData": "Vec<u8>",
+    "VariableData": "Vec<u8>"
   },
   "CollectionType": {
     "Owner": "AccountId",
@@ -208,11 +210,12 @@
     "Name": "Vec<u16>",
     "Description": "Vec<u16>",
     "TokenPrefix": "Vec<u8>",
-    "CustomDataSize": "u32",
     "MintMode": "bool",
     "OffchainSchema": "Vec<u8>",
     "Sponsor": "AccountId",
-    "UnconfirmedSponsor": "AccountId"
+    "UnconfirmedSponsor": "AccountId",
+    "VariableOnChainSchema": "Vec<u8>",
+    "ConstOnChainSchema": "Vec<u8>"
   },
   "ApprovePermissions": {
     "Approved": "AccountId",
@@ -221,7 +224,23 @@
   "RawData": "Vec<u8>",
   "Address": "AccountId",
   "LookupSource": "AccountId",
-  "Weight": "u64"
+  "Weight": "u64",
+  "CreateNftData": {
+    "const_data": "Vec<u8>",
+    "variable_data": "Vec<u8>" 
+  },
+  "CreateFungibleData": {},
+  "CreateReFungibleData": {
+    "const_data": "Vec<u8>",
+    "variable_data": "Vec<u8>" 
+  },
+  "CreateItemData": {
+    "_enum": {
+      "NFT": "CreateNftData",
+      "Fungible": "CreateFungibleData",
+      "ReFungible": "CreateReFungibleData"
+    }
+  }
 }
 
 ```
\ No newline at end of file
modifiednode/src/chain_spec.rsdiffbeforeafterboth
--- a/node/src/chain_spec.rs
+++ b/node/src/chain_spec.rs
@@ -159,17 +159,18 @@
                 1,
                 CollectionType {
                     owner: get_account_id_from_seed::<sr25519::Public>("Alice"),
-                    mode: CollectionMode::NFT(50),
+                    mode: CollectionMode::NFT,
                     access: AccessMode::Normal,
                     decimal_points: 0,
                     name: vec![],
                     description: vec![],
                     token_prefix: vec![],
-                    custom_data_size: 50,
                     mint_mode: false,
                     offchain_schema: vec![],
                     sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),
                     unconfirmed_sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),
+                    const_on_chain_schema: vec![],
+                    variable_on_chain_schema: vec![]
                 },
             )],
             nft_item_id: vec![],
modifiedpallets/nft/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/nft/src/benchmarking.rs
+++ b/pallets/nft/src/benchmarking.rs
@@ -9,6 +9,19 @@
 
     const SEED: u32 = 1;
 
+    fn default_nft_data() -> CreateItemData {
+        CreateItemData::NFT(CreateNftData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] })
+    }
+    
+    fn default_fungible_data () -> CreateItemData {
+        CreateItemData::Fungible(CreateFungibleData { })
+    }
+    
+    fn default_re_fungible_data () -> CreateItemData {
+        CreateItemData::ReFungible(CreateReFungibleData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] })
+    }
+
+
     benchmarks! {
 
         _ {}
@@ -17,7 +30,7 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = account("caller", 0, SEED);
         }: create_collection(RawOrigin::Signed(caller.clone()), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode)
         verify {
@@ -28,7 +41,7 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
         }: destroy_collection(RawOrigin::Signed(caller.clone()), 2)
@@ -37,7 +50,7 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             let whitelist_account: T::AccountId = account("admin", 0, SEED);
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
@@ -47,7 +60,7 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             let whitelist_account: T::AccountId = account("admin", 0, SEED);
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
@@ -58,7 +71,7 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
         }: set_public_access_mode(RawOrigin::Signed(caller.clone()), 2, AccessMode::WhiteList)
@@ -67,7 +80,7 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
         }: set_mint_permission(RawOrigin::Signed(caller.clone()), 2, true)
@@ -76,7 +89,7 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
             let new_owner: T::AccountId = account("admin", 0, SEED);
@@ -86,7 +99,7 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
             let new_admin: T::AccountId = account("admin", 0, SEED);
@@ -96,7 +109,7 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
             let new_admin: T::AccountId = account("admin", 0, SEED);
@@ -107,7 +120,7 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
         }: set_collection_sponsor(RawOrigin::Signed(caller.clone()), 2, caller.clone())
@@ -116,7 +129,7 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
             Nft::<T>::set_collection_sponsor(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone())?;
@@ -126,7 +139,7 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
             Nft::<T>::set_collection_sponsor(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone())?;
@@ -138,26 +151,32 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
-
-        }: create_item(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec(), caller.clone())
+            let data = default_nft_data();
+            
+        }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data)
 
         #[extra]
         create_item_nft_large {
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
-            let mut item_large: Vec<u8> = Vec::new(); 
+            let nft_data = CreateNftData {
+                const_data: vec![],
+                variable_data: vec![]
+            };
             for i in 0..1998 {
-                item_large.push(10);
+                nft_data.const_data.push(10);
+                nft_data.variable_data.push(10);
             }
+            let mut data = CreateItemData::NFT(nft_data);
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
 
-        }: create_item(RawOrigin::Signed(caller.clone()), 2, item_large, caller.clone())
+        }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data)
 
         // fungible item
         create_item_fungible {
@@ -167,28 +186,31 @@
             let mode: CollectionMode = CollectionMode::Fungible(3);
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            let data = default_fungible_data();
 
-        }: create_item(RawOrigin::Signed(caller.clone()), 2, [].to_vec(), caller.clone())
+        }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data)
 
         // refungible item
         create_item_refungible {
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::ReFungible(3, 3);
+            let mode: CollectionMode = CollectionMode::ReFungible(3);
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            let data = default_re_fungible_data();
 
-        }: create_item(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec(), caller.clone())
+        }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data)
 
         burn_item {
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
-            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1, 2, 3].to_vec(), caller.clone())?;
+            let data = default_nft_data();
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
 
         }: burn_item(RawOrigin::Signed(caller.clone()), 2, 1)
 
@@ -196,11 +218,12 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let mode: CollectionMode = CollectionMode::NFT;
             let recipient: T::AccountId = account("recipient", 0, SEED);
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
-            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1, 2, 3].to_vec(), caller.clone())?;
+            let data = default_nft_data();
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
 
         }: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1)
         
@@ -212,7 +235,8 @@
             let recipient: T::AccountId = account("recipient", 0, SEED);
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
-            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [].to_vec(), caller.clone())?;
+            let data = default_fungible_data();
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
 
         }: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1)
 
@@ -220,11 +244,12 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::ReFungible(3,3);
+            let mode: CollectionMode = CollectionMode::ReFungible(3);
             let recipient: T::AccountId = account("recipient", 0, SEED);
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
-            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1,2,3].to_vec(), caller.clone())?;
+            let data = default_re_fungible_data();
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
 
         }: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1)
 
@@ -232,11 +257,12 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::ReFungible(3,3);
+            let mode: CollectionMode = CollectionMode::ReFungible(3);
             let recipient: T::AccountId = account("recipient", 0, SEED);
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
-            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1,2,3].to_vec(), caller.clone())?;
+            let data = default_re_fungible_data();
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
 
         }: approve(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1)
 
@@ -245,11 +271,12 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::NFT(300);
+            let mode: CollectionMode = CollectionMode::NFT;
             let recipient: T::AccountId = account("recipient", 0, SEED);
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
-            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1,2,3].to_vec(), caller.clone())?;
+            let data = default_nft_data();
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
             Nft::<T>::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?;
 
         }: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1)
@@ -263,7 +290,8 @@
             let recipient: T::AccountId = account("recipient", 0, SEED);
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
-            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [].to_vec(), caller.clone())?;
+            let data = default_fungible_data();
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
             Nft::<T>::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?;
 
         }: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1)
@@ -273,11 +301,12 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::ReFungible(3,3);
+            let mode: CollectionMode = CollectionMode::ReFungible(3);
             let recipient: T::AccountId = account("recipient", 0, SEED);
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
-            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1,2,3].to_vec(), caller.clone())?;
+            let data = default_re_fungible_data();
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
             Nft::<T>::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?;
 
         }: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1)
@@ -286,9 +315,39 @@
             let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
             let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
-            let mode: CollectionMode = CollectionMode::ReFungible(3,3);
+            let mode: CollectionMode = CollectionMode::ReFungible(3);
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
 
         }: set_offchain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec())
-    }
\ No newline at end of file
+
+        set_const_on_chain_schema {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::ReFungible(3);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+        }: set_const_on_chain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec())
+        
+        set_variable_on_chain_schema {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::ReFungible(3);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+        }: set_variable_on_chain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec())
+
+        set_variable_meta_data {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT;
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            let data = default_nft_data();
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?;
+
+        }: set_variable_meta_data(RawOrigin::Signed(caller.clone()), 2, 1, [1, 2, 3].to_vec())
+}
\ No newline at end of file
modifiedpallets/nft/src/default_weights.rsdiffbeforeafterboth
--- a/pallets/nft/src/default_weights.rs
+++ b/pallets/nft/src/default_weights.rs
@@ -92,6 +92,21 @@
             .saturating_add(DbWeight::get().reads(2 as Weight))
             .saturating_add(DbWeight::get().writes(1 as Weight))
     }
+    fn set_const_on_chain_schema() -> Weight {
+        (11_100_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(1 as Weight))
+    }
+    fn set_variable_on_chain_schema() -> Weight {
+        (11_100_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(1 as Weight))
+    }
+    fn set_variable_meta_data() -> Weight {
+        (17_500_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(1 as Weight))
+    }
     // fn enable_contract_sponsoring() -> Weight {
     //     (0 as Weight)
     //         .saturating_add(DbWeight::get().reads(1 as Weight))
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
before · pallets/nft/src/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]23#[cfg(feature = "std")]4pub use std::*;56#[cfg(feature = "std")]7pub use serde::*;89use codec::{Decode, Encode};10pub use frame_support::{11    construct_runtime, decl_event, decl_module, decl_storage,12    dispatch::DispatchResult,13    ensure, parameter_types,14    traits::{15        Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,16        Randomness, WithdrawReason,17    },18    weights::{19        constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},20        DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,21        WeightToFeePolynomial,22    },23    IsSubType, StorageValue,24};25// use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};2627use frame_system::{self as system, ensure_signed, ensure_root};28use sp_runtime::sp_std::prelude::Vec;29use sp_runtime::{30    traits::{31        DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SignedExtension, Zero,32    },33    transaction_validity::{34        InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,35    },36    FixedPointOperand, FixedU128,37};38use pallet_contracts::ContractAddressFor;39use sp_runtime::traits::StaticLookup;4041#[cfg(test)]42mod mock;4344#[cfg(test)]45mod tests;4647mod default_weights;4849// Structs50// #region5152#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]53#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]54pub enum CollectionMode {55    Invalid,56    // custom data size57    NFT(u32),58    // decimal points59    Fungible(u32),60    // custom data size and decimal points61    ReFungible(u32, u32),62}6364impl Into<u8> for CollectionMode {65    fn into(self) -> u8 {66        match self {67            CollectionMode::Invalid => 0,68            CollectionMode::NFT(_) => 1,69            CollectionMode::Fungible(_) => 2,70            CollectionMode::ReFungible(_, _) => 3,71        }72    }73}7475#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]76#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]77pub enum AccessMode {78    Normal,79    WhiteList,80}81impl Default for AccessMode {82    fn default() -> Self {83        Self::Normal84    }85}8687impl Default for CollectionMode {88    fn default() -> Self {89        Self::Invalid90    }91}9293#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]94#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]95pub struct Ownership<AccountId> {96    pub owner: AccountId,97    pub fraction: u128,98}99100#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]101#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]102pub struct CollectionType<AccountId> {103    pub owner: AccountId,104    pub mode: CollectionMode,105    pub access: AccessMode,106    pub decimal_points: u32,107    pub name: Vec<u16>,        // 64 include null escape char108    pub description: Vec<u16>, // 256 include null escape char109    pub token_prefix: Vec<u8>, // 16 include null escape char110    pub custom_data_size: u32,111    pub mint_mode: bool,112    pub offchain_schema: Vec<u8>,113    pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender114    pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship115}116117#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]118#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]119pub struct CollectionAdminsType<AccountId> {120    pub admin: AccountId,121    pub collection_id: u64,122}123124#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]125#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]126pub struct NftItemType<AccountId> {127    pub collection: u64,128    pub owner: AccountId,129    pub data: Vec<u8>,130}131132#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]133#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]134pub struct FungibleItemType<AccountId> {135    pub collection: u64,136    pub owner: AccountId,137    pub value: u128,138}139140#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]141#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]142pub struct ReFungibleItemType<AccountId> {143    pub collection: u64,144    pub owner: Vec<Ownership<AccountId>>,145    pub data: Vec<u8>,146}147148#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]149#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]150pub struct ApprovePermissions<AccountId> {151    pub approved: AccountId,152    pub amount: u64,153}154155#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]156#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]157pub struct VestingItem<AccountId, Moment> {158    pub sender: AccountId,159    pub recipient: AccountId,160    pub collection_id: u64,161    pub item_id: u64,162    pub amount: u64,163    pub vesting_date: Moment,164}165166#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]167#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]168pub struct BasketItem<AccountId, BlockNumber> {169    pub address: AccountId,170    pub start_block: BlockNumber,171}172173#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]174#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]175pub struct ChainLimits {176    pub collection_numbers_limit: u64,177    pub account_token_ownership_limit: u64,178    pub collections_admins_limit: u64,179    pub custom_data_limit: u32,180181    // Timeouts for item types in passed blocks182    pub nft_sponsor_transfer_timeout: u32,183    pub fungible_sponsor_transfer_timeout: u32,184    pub refungible_sponsor_transfer_timeout: u32,185}186187pub trait WeightInfo {188	fn create_collection() -> Weight;189	fn destroy_collection() -> Weight;190	fn add_to_white_list() -> Weight;191	fn remove_from_white_list() -> Weight;192    fn set_public_access_mode() -> Weight;193    fn set_mint_permission() -> Weight;194    fn change_collection_owner() -> Weight;195    fn add_collection_admin() -> Weight;196    fn remove_collection_admin() -> Weight;197    fn set_collection_sponsor() -> Weight;198    fn confirm_sponsorship() -> Weight;199    fn remove_collection_sponsor() -> Weight;200    fn create_item(s: usize, ) -> Weight;201    fn burn_item() -> Weight;202    fn transfer() -> Weight;203    fn approve() -> Weight;204    fn transfer_from() -> Weight;205    fn set_offchain_schema() -> Weight;206    // fn enable_contract_sponsoring() -> Weight;207}208209pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {210    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;211212    /// Weight information for extrinsics in this pallet.213	type WeightInfo: WeightInfo;214}215216#[cfg(feature = "runtime-benchmarks")]217mod benchmarking;218219// #endregion220221decl_storage! {222    trait Store for Module<T: Trait> as Nft {223224        // Private members225        NextCollectionID: u64;226        CreatedCollectionCount: u64;227        ChainVersion: u64;228        ItemListIndex: map hasher(blake2_128_concat) u64 => u64;229230        // Chain limits struct231        pub ChainLimit get(fn chain_limit) config(): ChainLimits;232233        // Bound counters234        CollectionCount: u64;235        pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64;236237        // Basic collections238        pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;239        pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;240        pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;241242        /// Balance owner per collection map243        pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;244245        /// second parameter: item id + owner account id246        pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;247248        /// Item collections249        pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;250        pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;251        pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;252253        /// Index list254        pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;255256        /// Tokens transfer baskets257        pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;258        pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => Vec<BasketItem<T::AccountId, T::BlockNumber>>;259        pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;260261        // Contract Sponsorship and Ownership262        pub ContractOwner get(fn contract_owner): map hasher(identity) T::AccountId => T::AccountId;263        pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(identity) T::AccountId => bool;264    }265    add_extra_genesis {266        build(|config: &GenesisConfig<T>| {267            // Modification of storage268            for (_num, _c) in &config.collection {269                <Module<T>>::init_collection(_c);270            }271272            for (_num, _q, _i) in &config.nft_item_id {273                <Module<T>>::init_nft_token(_i);274            }275276            for (_num, _q, _i) in &config.fungible_item_id {277                <Module<T>>::init_fungible_token(_i);278            }279280            for (_num, _q, _i) in &config.refungible_item_id {281                <Module<T>>::init_refungible_token(_i);282            }283        })284    }285}286287decl_event!(288    pub enum Event<T>289    where290        AccountId = <T as system::Trait>::AccountId,291    {292        /// New collection was created293        /// 294        /// # Arguments295        /// 296        /// * collection_id: Globally unique identifier of newly created collection.297        /// 298        /// * mode: [CollectionMode] converted into u8.299        /// 300        /// * account_id: Collection owner.301        Created(u64, u8, AccountId),302303        /// New item was created.304        /// 305        /// # Arguments306        /// 307        /// * collection_id: Id of the collection where item was created.308        /// 309        /// * item_id: Id of an item. Unique within the collection.310        ItemCreated(u64, u64),311312        /// Collection item was burned.313        /// 314        /// # Arguments315        /// 316        /// collection_id.317        /// 318        /// item_id: Identifier of burned NFT.319        ItemDestroyed(u64, u64),320    }321);322323decl_module! {324    pub struct Module<T: Trait> for enum Call where origin: T::Origin {325326        fn deposit_event() = default;327328        fn on_initialize(now: T::BlockNumber) -> Weight {329330            if ChainVersion::get() < 2331            {332                let value = NextCollectionID::get();333                CreatedCollectionCount::put(value);334                ChainVersion::put(2);335            }336337            0338        }339340        /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner and admin of the collection are set to the address that signed the transaction. Both addresses can be changed later.341        /// 342        /// # Permissions343        /// 344        /// * Anyone.345        /// 346        /// # Arguments347        /// 348        /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.349        /// 350        /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.351        /// 352        /// * token_prefix: UTF-8 string with token prefix.353        /// 354        /// * mode: [CollectionMode] collection type and type dependent data.355        // returns collection ID356        #[weight = T::WeightInfo::create_collection()]357        pub fn create_collection(origin,358                                 collection_name: Vec<u16>,359                                 collection_description: Vec<u16>,360                                 token_prefix: Vec<u8>,361                                 mode: CollectionMode) -> DispatchResult {362363            // Anyone can create a collection364            let who = ensure_signed(origin)?;365            let custom_data_size = match mode {366                CollectionMode::NFT(size) => {367368                    // bound Custom data size369                    ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");370                    size371                },372                CollectionMode::ReFungible(size, _) => {373374                    // bound Custom data size375                    ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");376                    size377                },378                _ => 0379            };380381            let decimal_points = match mode {382                CollectionMode::Fungible(points) => points,383                CollectionMode::ReFungible(_, points) => points,384                _ => 0385            };386387            // bound Total number of collections388            ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded");389390            // check params391            ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");392393            let mut name = collection_name.to_vec();394            name.push(0);395            ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");396397            let mut description = collection_description.to_vec();398            description.push(0);399            ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");400401            let mut prefix = token_prefix.to_vec();402            prefix.push(0);403            ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");404405            // Generate next collection ID406            let next_id = CreatedCollectionCount::get()407                .checked_add(1)408                .expect("collection id error");409410            // bound counter411            let total = CollectionCount::get()412                .checked_add(1)413                .expect("collection counter error");414415            CreatedCollectionCount::put(next_id);416            CollectionCount::put(total);417418            // Create new collection419            let new_collection = CollectionType {420                owner: who.clone(),421                name: name,422                mode: mode.clone(),423                mint_mode: false,424                access: AccessMode::Normal,425                description: description,426                decimal_points: decimal_points,427                token_prefix: prefix,428                offchain_schema: Vec::new(),429                custom_data_size: custom_data_size,430                sponsor: T::AccountId::default(),431                unconfirmed_sponsor: T::AccountId::default(),432            };433434            // Add new collection to map435            <Collection<T>>::insert(next_id, new_collection);436437            // call event438            Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));439440            Ok(())441        }442443        /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.444        /// 445        /// # Permissions446        /// 447        /// * Collection Owner.448        /// 449        /// # Arguments450        /// 451        /// * collection_id: collection to destroy.452        #[weight = T::WeightInfo::destroy_collection()]453        pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {454455            let sender = ensure_signed(origin)?;456            Self::check_owner_permissions(collection_id, sender)?;457458            <AddressTokens<T>>::remove_prefix(collection_id);459            <ApprovedList<T>>::remove_prefix(collection_id);460            <Balance<T>>::remove_prefix(collection_id);461            <ItemListIndex>::remove(collection_id);462            <AdminList<T>>::remove(collection_id);463            <Collection<T>>::remove(collection_id);464            <WhiteList<T>>::remove(collection_id);465466            <NftItemList<T>>::remove_prefix(collection_id);467            <FungibleItemList<T>>::remove_prefix(collection_id);468            <ReFungibleItemList<T>>::remove_prefix(collection_id);469470            <NftTransferBasket<T>>::remove_prefix(collection_id);471            <FungibleTransferBasket<T>>::remove_prefix(collection_id);472            <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);473474            if CollectionCount::get() > 0475            {476                // bound couter477                let total = CollectionCount::get()478                    .checked_sub(1)479                    .expect("collection counter error");480481                CollectionCount::put(total);482            }483484            Ok(())485        }486487        /// Add an address to white list.488        /// 489        /// # Permissions490        /// 491        /// * Collection Owner492        /// * Collection Admin493        /// 494        /// # Arguments495        /// 496        /// * collection_id.497        /// 498        /// * address.499        #[weight = T::WeightInfo::add_to_white_list()]500        pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{501502            let sender = ensure_signed(origin)?;503            Self::check_owner_or_admin_permissions(collection_id, sender)?;504505            let mut white_list_collection: Vec<T::AccountId>;506            if <WhiteList<T>>::contains_key(collection_id) {507                white_list_collection = <WhiteList<T>>::get(collection_id);508                if !white_list_collection.contains(&address.clone())509                {510                    white_list_collection.push(address.clone());511                }512            }513            else {514                white_list_collection = Vec::new();515                white_list_collection.push(address.clone());516            }517518            <WhiteList<T>>::insert(collection_id, white_list_collection);519            Ok(())520        }521522        /// Remove an address from white list.523        /// 524        /// # Permissions525        /// 526        /// * Collection Owner527        /// * Collection Admin528        /// 529        /// # Arguments530        /// 531        /// * collection_id.532        /// 533        /// * address.534        #[weight = T::WeightInfo::remove_from_white_list()]535        pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{536537            let sender = ensure_signed(origin)?;538            Self::check_owner_or_admin_permissions(collection_id, sender)?;539540            if <WhiteList<T>>::contains_key(collection_id) {541                let mut white_list_collection = <WhiteList<T>>::get(collection_id);542                if white_list_collection.contains(&address.clone())543                {544                    white_list_collection.retain(|i| *i != address.clone());545                    <WhiteList<T>>::insert(collection_id, white_list_collection);546                }547            }548549            Ok(())550        }551552        /// Toggle between normal and white list access for the methods with access for `Anyone`.553        /// 554        /// # Permissions555        /// 556        /// * Collection Owner.557        /// 558        /// # Arguments559        /// 560        /// * collection_id.561        /// 562        /// * mode: [AccessMode]563        #[weight = T::WeightInfo::set_public_access_mode()]564        pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult565        {566            let sender = ensure_signed(origin)?;567568            Self::check_owner_permissions(collection_id, sender)?;569            let mut target_collection = <Collection<T>>::get(collection_id);570            target_collection.access = mode;571            <Collection<T>>::insert(collection_id, target_collection);572573            Ok(())574        }575576        /// Allows Anyone to create tokens if:577        /// * White List is enabled, and578        /// * Address is added to white list, and579        /// * This method was called with True parameter580        /// 581        /// # Permissions582        /// * Collection Owner583        ///584        /// # Arguments585        /// 586        /// * collection_id.587        /// 588        /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.589        #[weight = T::WeightInfo::set_mint_permission()]590        pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult591        {592            let sender = ensure_signed(origin)?;593594            Self::check_owner_permissions(collection_id, sender)?;595            let mut target_collection = <Collection<T>>::get(collection_id);596            target_collection.mint_mode = mint_permission;597            <Collection<T>>::insert(collection_id, target_collection);598599            Ok(())600        }601602        /// Change the owner of the collection.603        /// 604        /// # Permissions605        /// 606        /// * Collection Owner.607        /// 608        /// # Arguments609        /// 610        /// * collection_id.611        /// 612        /// * new_owner.613        #[weight = T::WeightInfo::change_collection_owner()]614        pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {615616            let sender = ensure_signed(origin)?;617            Self::check_owner_permissions(collection_id, sender)?;618            let mut target_collection = <Collection<T>>::get(collection_id);619            target_collection.owner = new_owner;620            <Collection<T>>::insert(collection_id, target_collection);621622            Ok(())623        }624625        /// Adds an admin of the Collection.626        /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership. 627        /// 628        /// # Permissions629        /// 630        /// * Collection Owner.631        /// * Collection Admin.632        /// 633        /// # Arguments634        /// 635        /// * collection_id: ID of the Collection to add admin for.636        /// 637        /// * new_admin_id: Address of new admin to add.638        #[weight = T::WeightInfo::add_collection_admin()]639        pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {640641            let sender = ensure_signed(origin)?;642            Self::check_owner_or_admin_permissions(collection_id, sender)?;643            let mut admin_arr: Vec<T::AccountId> = Vec::new();644645            if <AdminList<T>>::contains_key(collection_id)646            {647                admin_arr = <AdminList<T>>::get(collection_id);648                ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");649            }650651            // Number of collection admins652            ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded");653654            admin_arr.push(new_admin_id);655            <AdminList<T>>::insert(collection_id, admin_arr);656657            Ok(())658        }659660        /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.661        ///662        /// # Permissions663        /// 664        /// * Collection Owner.665        /// * Collection Admin.666        /// 667        /// # Arguments668        /// 669        /// * collection_id: ID of the Collection to remove admin for.670        /// 671        /// * account_id: Address of admin to remove.672        #[weight = T::WeightInfo::remove_collection_admin()]673        pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {674675            let sender = ensure_signed(origin)?;676            Self::check_owner_or_admin_permissions(collection_id, sender)?;677678            if <AdminList<T>>::contains_key(collection_id)679            {680                let mut admin_arr = <AdminList<T>>::get(collection_id);681                admin_arr.retain(|i| *i != account_id);682                <AdminList<T>>::insert(collection_id, admin_arr);683            }684685            Ok(())686        }687688        /// # Permissions689        /// 690        /// * Collection Owner691        /// 692        /// # Arguments693        /// 694        /// * collection_id.695        /// 696        /// * new_sponsor.697        #[weight = T::WeightInfo::set_collection_sponsor()]698        pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {699700            let sender = ensure_signed(origin)?;701            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");702703            let mut target_collection = <Collection<T>>::get(collection_id);704            ensure!(sender == target_collection.owner, "You do not own this collection");705706            target_collection.unconfirmed_sponsor = new_sponsor;707            <Collection<T>>::insert(collection_id, target_collection);708709            Ok(())710        }711712        /// # Permissions713        /// 714        /// * Sponsor.715        /// 716        /// # Arguments717        /// 718        /// * collection_id.719        #[weight = T::WeightInfo::confirm_sponsorship()]720        pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {721722            let sender = ensure_signed(origin)?;723            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");724725            let mut target_collection = <Collection<T>>::get(collection_id);726            ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");727728            target_collection.sponsor = target_collection.unconfirmed_sponsor;729            target_collection.unconfirmed_sponsor = T::AccountId::default();730            <Collection<T>>::insert(collection_id, target_collection);731732            Ok(())733        }734735        /// Switch back to pay-per-own-transaction model.736        ///737        /// # Permissions738        ///739        /// * Collection owner.740        /// 741        /// # Arguments742        /// 743        /// * collection_id.744        #[weight = T::WeightInfo::remove_collection_sponsor()]745        pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {746747            let sender = ensure_signed(origin)?;748            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");749750            let mut target_collection = <Collection<T>>::get(collection_id);751            ensure!(sender == target_collection.owner, "You do not own this collection");752753            target_collection.sponsor = T::AccountId::default();754            <Collection<T>>::insert(collection_id, target_collection);755756            Ok(())757        }758759        /// This method creates a concrete instance of NFT Collection created with CreateCollection method.760        /// 761        /// # Permissions762        /// 763        /// * Collection Owner.764        /// * Collection Admin.765        /// * Anyone if766        ///     * White List is enabled, and767        ///     * Address is added to white list, and768        ///     * MintPermission is enabled (see SetMintPermission method)769        /// 770        /// # Arguments771        /// 772        /// * collection_id: ID of the collection.773        /// 774        /// * properties: Array of bytes that contains NFT properties. Since NFT Module is agnostic of properties meaning, it is treated purely as an array of bytes.775        /// 776        /// * owner: Address, initial owner of the NFT.777        // #[weight =778        // (130_000_000 as Weight)779        // .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))780        // .saturating_add(RocksDbWeight::get().reads(10 as Weight))781        // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]782783        #[weight = T::WeightInfo::create_item(properties.len())]784        pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {785786            let sender = ensure_signed(origin)?;787            Self::collection_exists(collection_id)?;788            let target_collection = <Collection<T>>::get(collection_id);789790            if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {791                ensure!(target_collection.mint_mode == true, "Public minting is not allowed for this collection");792                Self::check_white_list(collection_id, &owner)?;793                Self::check_white_list(collection_id, &sender)?;794            }795796            match target_collection.mode797            {798                CollectionMode::NFT(_) => {799800                    // check size801                    ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");802803                    // Create nft item804                    let item = NftItemType {805                        collection: collection_id,806                        owner: owner,807                        data: properties.clone(),808                    };809810                    Self::add_nft_item(item)?;811812                },813                CollectionMode::Fungible(_) => {814815                    // check size816                    ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type");817818                    let item = FungibleItemType {819                        collection: collection_id,820                        owner: owner,821                        value: (10 as u128).pow(target_collection.decimal_points)822                    };823824                    Self::add_fungible_item(item)?;825                },826                CollectionMode::ReFungible(_, _) => {827828                    // check size829                    ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");830831                    let mut owner_list = Vec::new();832                    let value = (10 as u128).pow(target_collection.decimal_points);833                    owner_list.push(Ownership {owner: owner.clone(), fraction: value});834835                    let item = ReFungibleItemType {836                        collection: collection_id,837                        owner: owner_list,838                        data: properties.clone()839                    };840841                    Self::add_refungible_item(item)?;842                },843                _ => { ensure!(1 == 0,"just error"); }844845            };846847            // call event848            Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));849850            Ok(())851        }852853        /// Destroys a concrete instance of NFT.854        /// 855        /// # Permissions856        /// 857        /// * Collection Owner.858        /// * Collection Admin.859        /// * Current NFT Owner.860        /// 861        /// # Arguments862        /// 863        /// * collection_id: ID of the collection.864        /// 865        /// * item_id: ID of NFT to burn.866        #[weight = T::WeightInfo::burn_item()]867        pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {868869            let sender = ensure_signed(origin)?;870            Self::collection_exists(collection_id)?;871872            // Transfer permissions check873            let target_collection = <Collection<T>>::get(collection_id);874            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||875                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),876                "Only item owner, collection owner and admins can modify item");877878            if target_collection.access == AccessMode::WhiteList {879                Self::check_white_list(collection_id, &sender)?;880            }881882            match target_collection.mode883            {884                CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,885                CollectionMode::Fungible(_)  => Self::burn_fungible_item(collection_id, item_id)?,886                CollectionMode::ReFungible(_, _)  => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,887                _ => ()888            };889890            // call event891            Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));892893            Ok(())894        }895896        /// Change ownership of the token.897        /// 898        /// # Permissions899        /// 900        /// * Collection Owner901        /// * Collection Admin902        /// * Current NFT owner903        ///904        /// # Arguments905        /// 906        /// * recipient: Address of token recipient.907        /// 908        /// * collection_id.909        /// 910        /// * item_id: ID of the item911        ///     * Non-Fungible Mode: Required.912        ///     * Fungible Mode: Ignored.913        ///     * Re-Fungible Mode: Required.914        /// 915        /// * value: Amount to transfer.916        ///     * Non-Fungible Mode: Ignored917        ///     * Fungible Mode: Must specify transferred amount918        ///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)919        #[weight = T::WeightInfo::transfer()]920        pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {921922            let sender = ensure_signed(origin)?;923924            // Transfer permissions check925            let target_collection = <Collection<T>>::get(collection_id);926            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||927                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),928                "Only item owner, collection owner and admins can modify item");929930            if target_collection.access == AccessMode::WhiteList {931                Self::check_white_list(collection_id, &sender)?;932                Self::check_white_list(collection_id, &recipient)?;933            }934935            match target_collection.mode936            {937                CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,938                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,939                CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,940                _ => ()941            };942943            Ok(())944        }945946        /// Set, change, or remove approved address to transfer the ownership of the NFT.947        /// 948        /// # Permissions949        /// 950        /// * Collection Owner951        /// * Collection Admin952        /// * Current NFT owner953        /// 954        /// # Arguments955        /// 956        /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).957        /// 958        /// * collection_id.959        /// 960        /// * item_id: ID of the item.961        #[weight = T::WeightInfo::approve()]962        pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {963964            let sender = ensure_signed(origin)?;965966            // Transfer permissions check967            let target_collection = <Collection<T>>::get(collection_id);968            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||969                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),970                "Only item owner, collection owner and admins can approve");971972            if target_collection.access == AccessMode::WhiteList {973                Self::check_white_list(collection_id, &sender)?;974                Self::check_white_list(collection_id, &approved)?;975            }976977            // amount param stub978            let amount = 100000000;979980            let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));981            if list_exists {982983                let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));984                let item_contains = list.iter().any(|i| i.approved == approved);985986                if !item_contains {987                    list.push(ApprovePermissions { approved: approved.clone(), amount: amount });988                    <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);989                }990            } else {991992                let mut list = Vec::new();993                list.push(ApprovePermissions { approved: approved.clone(), amount: amount });994                <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);995            }996997            Ok(())998        }999        1000        /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.1001        /// 1002        /// # Permissions1003        /// * Collection Owner1004        /// * Collection Admin1005        /// * Current NFT owner1006        /// * Address approved by current NFT owner1007        /// 1008        /// # Arguments1009        /// 1010        /// * from: Address that owns token.1011        /// 1012        /// * recipient: Address of token recipient.1013        /// 1014        /// * collection_id.1015        /// 1016        /// * item_id: ID of the item.1017        /// 1018        /// * value: Amount to transfer.1019        #[weight = T::WeightInfo::transfer_from()]1020        pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {10211022            let sender = ensure_signed(origin)?;1023            let mut appoved_transfer = false;10241025            // Check approve1026            if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1027                let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1028                let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1029                if opt_item.is_some()1030                {1031                    appoved_transfer = true;1032                    ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");1033                }1034            }10351036            // Transfer permissions check1037            let target_collection = <Collection<T>>::get(collection_id);1038            ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1039                "Only item owner, collection owner and admins can modify items");10401041            if target_collection.access == AccessMode::WhiteList {1042                Self::check_white_list(collection_id, &sender)?;1043                Self::check_white_list(collection_id, &recipient)?;1044            }10451046            // remove approve1047            let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1048                .into_iter().filter(|i| i.approved != sender.clone()).collect();1049            <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);105010511052            match target_collection.mode1053            {1054                CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,1055                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1056                CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1057                _ => ()1058            };10591060            Ok(())1061        }10621063        ///1064        #[weight = 0]1065        pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {10661067            // let no_perm_mes = "You do not have permissions to modify this collection";1068            // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1069            // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1070            // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);10711072            // // on_nft_received  call10731074            // Self::transfer(origin, collection_id, item_id, new_owner)?;10751076            Ok(())1077        }10781079        /// Set off-chain data schema.1080        /// 1081        /// # Permissions1082        /// 1083        /// * Collection Owner1084        /// * Collection Admin1085        /// 1086        /// # Arguments1087        /// 1088        /// * collection_id.1089        /// 1090        /// * schema: String representing the offchain data schema.1091        #[weight = T::WeightInfo::set_offchain_schema()]1092        pub fn set_offchain_schema(1093            origin,1094            collection_id: u64,1095            schema: Vec<u8>1096        ) -> DispatchResult {1097            let sender = ensure_signed(origin)?;1098            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;10991100            let mut target_collection = <Collection<T>>::get(collection_id);1101            target_collection.offchain_schema = schema;1102            <Collection<T>>::insert(collection_id, target_collection);11031104            Ok(())1105        }11061107        // Sudo permissions function1108        #[weight = 0]1109        pub fn set_chain_limits(1110            origin,1111            limits: ChainLimits1112        ) -> DispatchResult {1113            ensure_root(origin)?;1114            <ChainLimit>::put(limits);1115            Ok(())1116        }11171118        /// Enable smart contract self-sponsoring.1119        /// 1120        /// # Permissions1121        /// 1122        /// * Contract Owner1123        /// 1124        /// # Arguments1125        /// 1126        /// * contract address1127        /// * enable flag1128        /// 1129        #[weight = 0]1130        pub fn enable_contract_sponsoring(1131            origin,1132            contract_address: T::AccountId,1133            enable: bool1134        ) -> DispatchResult {1135            let sender = ensure_signed(origin)?;1136            let mut is_owner = false;1137            if <ContractOwner<T>>::contains_key(contract_address.clone()) {1138                let owner = <ContractOwner<T>>::get(&contract_address);1139                is_owner = sender == owner;1140            }1141            ensure!(is_owner, "Only contract owner may call this method");11421143            <ContractSelfSponsoring<T>>::insert(contract_address, enable);1144            Ok(())1145        }11461147    }1148}11491150impl<T: Trait> Module<T> {1151    fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1152        let current_index = <ItemListIndex>::get(item.collection)1153            .checked_add(1)1154            .expect("Item list index id error");1155        let itemcopy = item.clone();1156        let owner = item.owner.clone();1157        let value = item.value as u64;11581159        Self::add_token_index(item.collection, current_index, owner.clone())?;11601161        <ItemListIndex>::insert(item.collection, current_index);1162        <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11631164        // Add current block1165        let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1166        <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1167        1168        // Update balance1169        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1170            .checked_add(value)1171            .unwrap();1172        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11731174        Ok(())1175    }11761177    fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1178        let current_index = <ItemListIndex>::get(item.collection)1179            .checked_add(1)1180            .expect("Item list index id error");1181        let itemcopy = item.clone();11821183        let value = item.owner.first().unwrap().fraction as u64;1184        let owner = item.owner.first().unwrap().owner.clone();11851186        Self::add_token_index(item.collection, current_index, owner.clone())?;11871188        <ItemListIndex>::insert(item.collection, current_index);1189        <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11901191        // Add current block1192        let block_number: T::BlockNumber = 0.into();1193        <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);11941195        // Update balance1196        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1197            .checked_add(value)1198            .unwrap();1199        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);12001201        Ok(())1202    }12031204    fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1205        let current_index = <ItemListIndex>::get(item.collection)1206            .checked_add(1)1207            .expect("Item list index id error");12081209        let item_owner = item.owner.clone();1210        let collection_id = item.collection.clone();1211        Self::add_token_index(collection_id, current_index, item.owner.clone())?;12121213        <ItemListIndex>::insert(collection_id, current_index);1214        <NftItemList<T>>::insert(collection_id, current_index, item);12151216        // Add current block1217        let block_number: T::BlockNumber = 0.into();1218        <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);12191220        // Update balance1221        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1222            .checked_add(1)1223            .unwrap();1224        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);12251226        Ok(())1227    }12281229    fn burn_refungible_item(1230        collection_id: u64,1231        item_id: u64,1232        owner: T::AccountId,1233    ) -> DispatchResult {1234        ensure!(1235            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1236            "Item does not exists"1237        );1238        let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1239        let item = collection1240            .owner1241            .iter()1242            .filter(|&i| i.owner == owner)1243            .next()1244            .unwrap();1245        Self::remove_token_index(collection_id, item_id, owner.clone())?;12461247        // remove approve list1248        <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));12491250        // update balance1251        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1252            .checked_sub(item.fraction as u64)1253            .unwrap();1254        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12551256        <ReFungibleItemList<T>>::remove(collection_id, item_id);12571258        Ok(())1259    }12601261    fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {1262        ensure!(1263            <NftItemList<T>>::contains_key(collection_id, item_id),1264            "Item does not exists"1265        );1266        let item = <NftItemList<T>>::get(collection_id, item_id);1267        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12681269        // remove approve list1270        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12711272        // update balance1273        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1274            .checked_sub(1)1275            .unwrap();1276        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1277        <NftItemList<T>>::remove(collection_id, item_id);12781279        Ok(())1280    }12811282    fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {1283        ensure!(1284            <FungibleItemList<T>>::contains_key(collection_id, item_id),1285            "Item does not exists"1286        );1287        let item = <FungibleItemList<T>>::get(collection_id, item_id);1288        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12891290        // remove approve list1291        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12921293        // update balance1294        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1295            .checked_sub(item.value as u64)1296            .unwrap();1297        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12981299        <FungibleItemList<T>>::remove(collection_id, item_id);13001301        Ok(())1302    }13031304    fn collection_exists(collection_id: u64) -> DispatchResult {1305        ensure!(1306            <Collection<T>>::contains_key(collection_id),1307            "This collection does not exist"1308        );1309        Ok(())1310    }13111312    fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {1313        Self::collection_exists(collection_id)?;13141315        let target_collection = <Collection<T>>::get(collection_id);1316        ensure!(1317            subject == target_collection.owner,1318            "You do not own this collection"1319        );13201321        Ok(())1322    }13231324    fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {1325        let target_collection = <Collection<T>>::get(collection_id);1326        let mut result: bool = subject == target_collection.owner;1327        let exists = <AdminList<T>>::contains_key(collection_id);13281329        if !result & exists {1330            if <AdminList<T>>::get(collection_id).contains(&subject) {1331                result = true1332            }1333        }13341335        result1336    }13371338    fn check_owner_or_admin_permissions(1339        collection_id: u64,1340        subject: T::AccountId,1341    ) -> DispatchResult {1342        Self::collection_exists(collection_id)?;1343        let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());13441345        ensure!(1346            result,1347            "You do not have permissions to modify this collection"1348        );1349        Ok(())1350    }13511352    fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1353        let target_collection = <Collection<T>>::get(collection_id);13541355        match target_collection.mode {1356            CollectionMode::NFT(_) => {1357                <NftItemList<T>>::get(collection_id, item_id).owner == subject1358            }1359            CollectionMode::Fungible(_) => {1360                <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1361            }1362            CollectionMode::ReFungible(_, _) => {1363                <ReFungibleItemList<T>>::get(collection_id, item_id)1364                    .owner1365                    .iter()1366                    .any(|i| i.owner == subject)1367            }1368            CollectionMode::Invalid => false,1369        }1370    }13711372    fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {1373        let mes = "Address is not in white list";1374        ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1375        let wl = <WhiteList<T>>::get(collection_id);1376        ensure!(wl.contains(address), mes);13771378        Ok(())1379    }13801381    fn transfer_fungible(1382        collection_id: u64,1383        item_id: u64,1384        value: u64,1385        owner: T::AccountId,1386        new_owner: T::AccountId,1387    ) -> DispatchResult {1388        ensure!(1389            <FungibleItemList<T>>::contains_key(collection_id, item_id),1390            "Item not exists"1391        );13921393        let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1394        let amount = full_item.value;13951396        ensure!(amount >= value.into(), "Item balance not enouth");13971398        // update balance1399        let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1400            .checked_sub(value)1401            .unwrap();1402        <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);14031404        let mut new_owner_account_id = 0;1405        let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1406        if new_owner_items.len() > 0 {1407            new_owner_account_id = new_owner_items[0];1408        }14091410        let val64 = value.into();14111412        // transfer1413        if amount == val64 && new_owner_account_id == 0 {1414            // change owner1415            // new owner do not have account1416            let mut new_full_item = full_item.clone();1417            new_full_item.owner = new_owner.clone();1418            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);14191420            // update balance1421            let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1422                .checked_add(value)1423                .unwrap();1424            <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14251426            // update index collection1427            Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1428        } else {1429            let mut new_full_item = full_item.clone();1430            new_full_item.value -= val64;14311432            // separate amount1433            if new_owner_account_id > 0 {1434                // new owner has account1435                let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1436                item.value += val64;14371438                // update balance1439                let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1440                    .checked_add(value)1441                    .unwrap();1442                <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14431444                <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1445            } else {1446                // new owner do not have account1447                let item = FungibleItemType {1448                    collection: collection_id,1449                    owner: new_owner.clone(),1450                    value: val64,1451                };14521453                Self::add_fungible_item(item)?;1454            }14551456            if amount == val64 {1457                Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;14581459                // remove approve list1460                <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1461                <FungibleItemList<T>>::remove(collection_id, item_id);1462            }14631464            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1465        }14661467        Ok(())1468    }14691470    fn transfer_refungible(1471        collection_id: u64,1472        item_id: u64,1473        value: u64,1474        owner: T::AccountId,1475        new_owner: T::AccountId,1476    ) -> DispatchResult {1477        ensure!(1478            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1479            "Item not exists"1480        );14811482        let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1483        let item = full_item1484            .owner1485            .iter()1486            .filter(|i| i.owner == owner)1487            .next()1488            .unwrap();1489        let amount = item.fraction;14901491        ensure!(amount >= value.into(), "Item balance not enouth");14921493        // update balance1494        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1495            .checked_sub(value)1496            .unwrap();1497        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);14981499        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1500            .checked_add(value)1501            .unwrap();1502        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15031504        let old_owner = item.owner.clone();1505        let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1506        let val64 = value.into();15071508        // transfer1509        if amount == val64 && !new_owner_has_account {1510            // change owner1511            // new owner do not have account1512            let mut new_full_item = full_item.clone();1513            new_full_item1514                .owner1515                .iter_mut()1516                .find(|i| i.owner == owner)1517                .unwrap()1518                .owner = new_owner.clone();1519            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);15201521            // update index collection1522            Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1523        } else {1524            let mut new_full_item = full_item.clone();1525            new_full_item1526                .owner1527                .iter_mut()1528                .find(|i| i.owner == owner)1529                .unwrap()1530                .fraction -= val64;15311532            // separate amount1533            if new_owner_has_account {1534                // new owner has account1535                new_full_item1536                    .owner1537                    .iter_mut()1538                    .find(|i| i.owner == new_owner)1539                    .unwrap()1540                    .fraction += val64;1541            } else {1542                // new owner do not have account1543                new_full_item.owner.push(Ownership {1544                    owner: new_owner.clone(),1545                    fraction: val64,1546                });1547                Self::add_token_index(collection_id, item_id, new_owner.clone())?;1548            }15491550            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1551        }15521553        Ok(())1554    }15551556    fn transfer_nft(1557        collection_id: u64,1558        item_id: u64,1559        sender: T::AccountId,1560        new_owner: T::AccountId,1561    ) -> DispatchResult {1562        ensure!(1563            <NftItemList<T>>::contains_key(collection_id, item_id),1564            "Item not exists"1565        );15661567        let mut item = <NftItemList<T>>::get(collection_id, item_id);15681569        ensure!(1570            sender == item.owner,1571            "sender parameter and item owner must be equal"1572        );15731574        // update balance1575        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1576            .checked_sub(1)1577            .unwrap();1578        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);15791580        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1581            .checked_add(1)1582            .unwrap();1583        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15841585        // change owner1586        let old_owner = item.owner.clone();1587        item.owner = new_owner.clone();1588        <NftItemList<T>>::insert(collection_id, item_id, item);15891590        // update index collection1591        Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;15921593        // reset approved list1594        <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1595        Ok(())1596    }15971598    fn init_collection(item: &CollectionType<T::AccountId>) {1599        // check params1600        assert!(1601            item.decimal_points <= 4,1602            "decimal_points parameter must be lower than 4"1603        );1604        assert!(1605            item.name.len() <= 64,1606            "Collection name can not be longer than 63 char"1607        );1608        assert!(1609            item.name.len() <= 256,1610            "Collection description can not be longer than 255 char"1611        );1612        assert!(1613            item.token_prefix.len() <= 16,1614            "Token prefix can not be longer than 15 char"1615        );16161617        // Generate next collection ID1618        let next_id = CreatedCollectionCount::get()1619            .checked_add(1)1620            .expect("collection id error");16211622        CreatedCollectionCount::put(next_id);1623    }16241625    fn init_nft_token(item: &NftItemType<T::AccountId>) {1626        let current_index = <ItemListIndex>::get(item.collection)1627            .checked_add(1)1628            .expect("Item list index id error");16291630        let item_owner = item.owner.clone();1631        let collection_id = item.collection.clone();1632        Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();16331634        <ItemListIndex>::insert(collection_id, current_index);16351636        // Update balance1637        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1638            .checked_add(1)1639            .unwrap();1640        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1641    }16421643    fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {1644        let current_index = <ItemListIndex>::get(item.collection)1645            .checked_add(1)1646            .expect("Item list index id error");1647        let owner = item.owner.clone();1648        let value = item.value as u64;16491650        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16511652        <ItemListIndex>::insert(item.collection, current_index);16531654        // Update balance1655        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1656            .checked_add(value)1657            .unwrap();1658        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1659    }16601661    fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {1662        let current_index = <ItemListIndex>::get(item.collection)1663            .checked_add(1)1664            .expect("Item list index id error");16651666        let value = item.owner.first().unwrap().fraction as u64;1667        let owner = item.owner.first().unwrap().owner.clone();16681669        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16701671        <ItemListIndex>::insert(item.collection, current_index);16721673        // Update balance1674        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1675            .checked_add(value)1676            .unwrap();1677        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1678    }16791680    fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {16811682        // add to account limit1683        if <AccountItemCount<T>>::contains_key(owner.clone()) {16841685            // bound Owned tokens by a single address1686            let count = <AccountItemCount<T>>::get(owner.clone());1687            ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded");16881689            <AccountItemCount<T>>::insert(owner.clone(), 1690                count.checked_add(1).unwrap());1691        }1692        else {1693            <AccountItemCount<T>>::insert(owner.clone(), 1);1694        }16951696        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1697        if list_exists {1698            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1699            let item_contains = list.contains(&item_index.clone());17001701            if !item_contains {1702                list.push(item_index.clone());1703            }17041705            <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1706        } else {1707            let mut itm = Vec::new();1708            itm.push(item_index.clone());1709            <AddressTokens<T>>::insert(collection_id, owner, itm);1710            1711        }17121713        Ok(())1714    }17151716    fn remove_token_index(1717        collection_id: u64,1718        item_index: u64,1719        owner: T::AccountId,1720    ) -> DispatchResult {17211722        // update counter1723        <AccountItemCount<T>>::insert(owner.clone(), 1724            <AccountItemCount<T>>::get(owner.clone()).checked_sub(1).unwrap());172517261727        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1728        if list_exists {1729            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1730            let item_contains = list.contains(&item_index.clone());17311732            if item_contains {1733                list.retain(|&item| item != item_index);1734                <AddressTokens<T>>::insert(collection_id, owner, list);1735            }1736        }17371738        Ok(())1739    }17401741    fn move_token_index(1742        collection_id: u64,1743        item_index: u64,1744        old_owner: T::AccountId,1745        new_owner: T::AccountId,1746    ) -> DispatchResult {1747        Self::remove_token_index(collection_id, item_index, old_owner)?;1748        Self::add_token_index(collection_id, item_index, new_owner)?;17491750        Ok(())1751    }1752}17531754////////////////////////////////////////////////////////////////////////////////////////////////////1755// Economic models1756// #region17571758/// Fee multiplier.1759pub type Multiplier = FixedU128;17601761type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1762    <T as system::Trait>::AccountId,1763>>::Balance;1764type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1765    <T as system::Trait>::AccountId,1766>>::NegativeImbalance;17671768/// Require the transactor pay for themselves and maybe include a tip to gain additional priority1769/// in the queue.1770#[derive(Encode, Decode, Clone, Eq, PartialEq)]1771pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(1772    #[codec(compact)] BalanceOf<T>1773);17741775impl<T: Trait + Send + Sync> sp_std::fmt::Debug1776    for ChargeTransactionPayment<T>1777{1778    #[cfg(feature = "std")]1779    fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1780        write!(f, "ChargeTransactionPayment<{:?}>", self.0)1781    }1782    #[cfg(not(feature = "std"))]1783    fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1784        Ok(())1785    }1786}17871788impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>1789where1790    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,1791    BalanceOf<T>: Send + Sync + FixedPointOperand,1792{1793    /// utility constructor. Used only in client/factory code.1794    pub fn from(fee: BalanceOf<T>) -> Self {1795        Self(fee)1796    }17971798    pub fn traditional_fee(1799        len: usize,1800        info: &DispatchInfoOf<T::Call>,1801        tip: BalanceOf<T>,1802    ) -> BalanceOf<T>1803    where1804        T::Call: Dispatchable<Info = DispatchInfo>,1805    {1806        <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)1807    }18081809    fn withdraw_fee(1810        &self,1811        who: &T::AccountId,1812        call: &T::Call,1813        info: &DispatchInfoOf<T::Call>,1814        len: usize,1815    ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {1816        let tip = self.0;18171818        // Set fee based on call type. Creating collection costs 1 Unique.1819        // All other transactions have traditional fees so far1820        // let fee = match call.is_sub_type() {1821        //     Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),1822        //     _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes1823        //                                                 // _ => <BalanceOf<T>>::from(100)1824        // };1825        let fee = Self::traditional_fee(len, info, tip);18261827        // Determine who is paying transaction fee based on ecnomic model1828        // Parse call to extract collection ID and access collection sponsor1829        let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {1830            Some(Call::create_item(collection_id, _properties, _owner)) => {1831                <Collection<T>>::get(collection_id).sponsor1832            }1833            Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {1834                let _collection_mode = <Collection<T>>::get(collection_id).mode;18351836                // sponsor timeout1837                let sponsor_transfer = match _collection_mode {1838                    CollectionMode::NFT(_) => {1839                        let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);1840                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1841                        let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1842                        if block_number >= limit_time {1843                            <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);1844                            true1845                        }1846                        else {1847                            false1848                        }1849                    }1850                    CollectionMode::Fungible(_) => {1851                        let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);1852                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1853                        if basket.iter().any(|i| i.address == _new_owner.clone())1854                        {1855                            let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();1856                            let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();1857                            if block_number >= limit_time {1858                                basket.retain(|x| x.address == item.address);1859                                basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });1860                                <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);1861                                true1862                            }1863                            else {1864                                false1865                            }1866                        }1867                        else {1868                            basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});1869                            true1870                        }1871                    }1872                    CollectionMode::ReFungible(_, _) => {1873                        let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);1874                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1875                        let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1876                        if block_number >= limit_time {1877                            <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);1878                            true1879                        } else {1880                            false1881                        }1882                    }1883                    _ => {1884                        false1885                    },1886                };18871888                if !sponsor_transfer {1889                    T::AccountId::default()1890                } else {1891                    <Collection<T>>::get(collection_id).sponsor1892                }1893            }18941895            _ => T::AccountId::default(),1896        };18971898        // Sponsor smart contracts1899        sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {19001901            // On instantiation: set the contract owner1902            Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {19031904                let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(1905                    code_hash,1906                    &data,1907                    &who,1908                );1909                <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());19101911                T::AccountId::default()1912            },19131914            // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is1915            Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {19161917                let mut sp = T::AccountId::default();1918                let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());1919                if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {1920                    if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {1921                        sp = called_contract;1922                    }1923                }19241925                sp1926            },19271928            _ => sponsor,1929        };19301931        let mut who_pays_fee: T::AccountId = sponsor.clone();1932        if sponsor == T::AccountId::default() {1933            who_pays_fee = who.clone();1934        }19351936        // Only mess with balances if fee is not zero.1937        if fee.is_zero() {1938            return Ok((fee, None));1939        }19401941        match <T as transaction_payment::Trait>::Currency::withdraw(1942            &who_pays_fee,1943            fee,1944            if tip.is_zero() {1945                WithdrawReason::TransactionPayment.into()1946            } else {1947                WithdrawReason::TransactionPayment | WithdrawReason::Tip1948            },1949            ExistenceRequirement::KeepAlive,1950        ) {1951            Ok(imbalance) => Ok((fee, Some(imbalance))),1952            Err(_) => Err(InvalidTransaction::Payment.into()),1953        }1954    }1955}195619571958impl<T: Trait + Send + Sync> SignedExtension1959    for ChargeTransactionPayment<T>1960where1961    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,1962    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,1963{1964    const IDENTIFIER: &'static str = "ChargeTransactionPayment";1965    type AccountId = T::AccountId;1966    type Call = T::Call;1967    type AdditionalSigned = ();1968    type Pre = (1969        BalanceOf<T>,1970        Self::AccountId,1971        Option<NegativeImbalanceOf<T>>,1972        BalanceOf<T>,1973    );1974    fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {1975        Ok(())1976    }19771978    fn validate(1979        &self,1980        _who: &Self::AccountId,1981        _call: &Self::Call,1982        _info: &DispatchInfoOf<Self::Call>,1983        _len: usize,1984    ) -> TransactionValidity {1985        Ok(ValidTransaction::default())1986    }19871988    fn pre_dispatch(1989        self,1990        who: &Self::AccountId,1991        call: &Self::Call,1992        info: &DispatchInfoOf<Self::Call>,1993        len: usize,1994    ) -> Result<Self::Pre, TransactionValidityError> {1995        let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;1996        Ok((self.0, who.clone(), imbalance, fee))1997    }19981999    fn post_dispatch(2000        pre: Self::Pre,2001        info: &DispatchInfoOf<Self::Call>,2002        post_info: &PostDispatchInfoOf<Self::Call>,2003        len: usize,2004        _result: &DispatchResult,2005    ) -> Result<(), TransactionValidityError> {2006        let (tip, who, imbalance, fee) = pre;2007        if let Some(payed) = imbalance {2008            let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2009                len as u32, info, post_info, tip,2010            );2011            let refund = fee.saturating_sub(actual_fee);2012            let actual_payment =2013                match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2014                    &who, refund,2015                ) {2016                    Ok(refund_imbalance) => {2017                        // The refund cannot be larger than the up front payed max weight.2018                        // `PostDispatchInfo::calc_unspent` guards against such a case.2019                        match payed.offset(refund_imbalance) {2020                            Ok(actual_payment) => actual_payment,2021                            Err(_) => return Err(InvalidTransaction::Payment.into()),2022                        }2023                    }2024                    // We do not recreate the account using the refund. The up front payment2025                    // is gone in that case.2026                    Err(_) => payed,2027                };2028            let imbalances = actual_payment.split(tip);2029            <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2030                Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2031            );2032        }2033        Ok(())2034    }2035}20362037// #endregion20382039
after · pallets/nft/src/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]23#[cfg(feature = "std")]4pub use std::*;56#[cfg(feature = "std")]7pub use serde::*;89use codec::{Decode, Encode};10pub use frame_support::{11    construct_runtime, decl_event, decl_module, decl_storage,12    dispatch::DispatchResult,13    ensure, parameter_types, fail,14    traits::{15        Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,16        Randomness, WithdrawReason,17    },18    weights::{19        constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},20        DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,21        WeightToFeePolynomial,22    },23    IsSubType, StorageValue,24};25// use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};2627use frame_system::{self as system, ensure_signed, ensure_root};28use sp_runtime::sp_std::prelude::Vec;29use sp_runtime::{30    traits::{31        DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SignedExtension, Zero,32    },33    transaction_validity::{34        InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,35    },36    FixedPointOperand, FixedU128,37};38use pallet_contracts::ContractAddressFor;39use sp_runtime::traits::StaticLookup;4041#[cfg(test)]42mod mock;4344#[cfg(test)]45mod tests;4647mod default_weights;4849// Structs50// #region5152#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]53#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]54pub enum CollectionMode {55    Invalid,56    NFT,57    // decimal points58    Fungible(u32),59    // decimal points60    ReFungible(u32),61}6263impl Into<u8> for CollectionMode {64    fn into(self) -> u8 {65        match self {66            CollectionMode::Invalid => 0,67            CollectionMode::NFT => 1,68            CollectionMode::Fungible(_) => 2,69            CollectionMode::ReFungible(_) => 3,70        }71    }72}7374#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]75#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]76pub enum AccessMode {77    Normal,78    WhiteList,79}80impl Default for AccessMode {81    fn default() -> Self {82        Self::Normal83    }84}8586impl Default for CollectionMode {87    fn default() -> Self {88        Self::Invalid89    }90}9192#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]93#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]94pub struct Ownership<AccountId> {95    pub owner: AccountId,96    pub fraction: u128,97}9899#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]100#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]101pub struct CollectionType<AccountId> {102    pub owner: AccountId,103    pub mode: CollectionMode,104    pub access: AccessMode,105    pub decimal_points: u32,106    pub name: Vec<u16>,        // 64 include null escape char107    pub description: Vec<u16>, // 256 include null escape char108    pub token_prefix: Vec<u8>, // 16 include null escape char109    pub mint_mode: bool,110    pub offchain_schema: Vec<u8>,111    pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender112    pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship113    pub variable_on_chain_schema: Vec<u8>, //114    pub const_on_chain_schema: Vec<u8>, //115}116117#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]118#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]119pub struct CollectionAdminsType<AccountId> {120    pub admin: AccountId,121    pub collection_id: u64,122}123124#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]125#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]126pub struct NftItemType<AccountId> {127    pub collection: u64,128    pub owner: AccountId,129    pub const_data: Vec<u8>,130    pub variable_data: Vec<u8>,131}132133#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]134#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]135pub struct FungibleItemType<AccountId> {136    pub collection: u64,137    pub owner: AccountId,138    pub value: u128,139}140141#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]142#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]143pub struct ReFungibleItemType<AccountId> {144    pub collection: u64,145    pub owner: Vec<Ownership<AccountId>>,146    pub const_data: Vec<u8>,147    pub variable_data: Vec<u8>,148}149150#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]151#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]152pub struct ApprovePermissions<AccountId> {153    pub approved: AccountId,154    pub amount: u64,155}156157#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]158#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]159pub struct VestingItem<AccountId, Moment> {160    pub sender: AccountId,161    pub recipient: AccountId,162    pub collection_id: u64,163    pub item_id: u64,164    pub amount: u64,165    pub vesting_date: Moment,166}167168#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]169#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]170pub struct BasketItem<AccountId, BlockNumber> {171    pub address: AccountId,172    pub start_block: BlockNumber,173}174175#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]176#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]177pub struct ChainLimits {178    pub collection_numbers_limit: u64,179    pub account_token_ownership_limit: u64,180    pub collections_admins_limit: u64,181    pub custom_data_limit: u32,182183    // Timeouts for item types in passed blocks184    pub nft_sponsor_transfer_timeout: u32,185    pub fungible_sponsor_transfer_timeout: u32,186    pub refungible_sponsor_transfer_timeout: u32,187}188189pub trait WeightInfo {190	fn create_collection() -> Weight;191	fn destroy_collection() -> Weight;192	fn add_to_white_list() -> Weight;193	fn remove_from_white_list() -> Weight;194    fn set_public_access_mode() -> Weight;195    fn set_mint_permission() -> Weight;196    fn change_collection_owner() -> Weight;197    fn add_collection_admin() -> Weight;198    fn remove_collection_admin() -> Weight;199    fn set_collection_sponsor() -> Weight;200    fn confirm_sponsorship() -> Weight;201    fn remove_collection_sponsor() -> Weight;202    fn create_item(s: usize) -> Weight;203    fn burn_item() -> Weight;204    fn transfer() -> Weight;205    fn approve() -> Weight;206    fn transfer_from() -> Weight;207    fn set_offchain_schema() -> Weight;208    fn set_const_on_chain_schema() -> Weight;209    fn set_variable_on_chain_schema() -> Weight;210    fn set_variable_meta_data() -> Weight;211    // fn enable_contract_sponsoring() -> Weight;212}213214#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]215#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]216pub struct CreateNftData {217    pub const_data: Vec<u8>,218    pub variable_data: Vec<u8>,219}220221#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]222#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]223pub struct CreateFungibleData {224}225226#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]227#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]228pub struct CreateReFungibleData {229    pub const_data: Vec<u8>,230    pub variable_data: Vec<u8>,231}232233#[derive(Encode, Decode, Debug, Clone, PartialEq)]234#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]235pub enum CreateItemData {236    NFT(CreateNftData),237    Fungible(CreateFungibleData),238    ReFungible(CreateReFungibleData)239}240241impl CreateItemData {242    pub fn len(&self) -> usize {243        let len = match self {244            CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),245            CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),246            _ => 0247        };248        249        return len;250    }251}252253impl From<CreateNftData> for CreateItemData {254    fn from(item: CreateNftData) -> Self {255        CreateItemData::NFT(item)256    }257}258259impl From<CreateReFungibleData> for CreateItemData {260    fn from(item: CreateReFungibleData) -> Self {261        CreateItemData::ReFungible(item)262    }263}264265impl From<CreateFungibleData> for CreateItemData {266    fn from(item: CreateFungibleData) -> Self {267        CreateItemData::Fungible(item)268    }269}270271pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {272    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;273274    /// Weight information for extrinsics in this pallet.275	type WeightInfo: WeightInfo;276}277278#[cfg(feature = "runtime-benchmarks")]279mod benchmarking;280281// #endregion282283decl_storage! {284    trait Store for Module<T: Trait> as Nft {285286        // Private members287        NextCollectionID: u64;288        CreatedCollectionCount: u64;289        ChainVersion: u64;290        ItemListIndex: map hasher(blake2_128_concat) u64 => u64;291292        // Chain limits struct293        pub ChainLimit get(fn chain_limit) config(): ChainLimits;294295        // Bound counters296        CollectionCount: u64;297        pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64;298299        // Basic collections300        pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;301        pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;302        pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;303304        /// Balance owner per collection map305        pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;306307        /// second parameter: item id + owner account id308        pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;309310        /// Item collections311        pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;312        pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;313        pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;314315        /// Index list316        pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;317318        /// Tokens transfer baskets319        pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;320        pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => Vec<BasketItem<T::AccountId, T::BlockNumber>>;321        pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;322323        // Contract Sponsorship and Ownership324        pub ContractOwner get(fn contract_owner): map hasher(identity) T::AccountId => T::AccountId;325        pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(identity) T::AccountId => bool;326    }327    add_extra_genesis {328        build(|config: &GenesisConfig<T>| {329            // Modification of storage330            for (_num, _c) in &config.collection {331                <Module<T>>::init_collection(_c);332            }333334            for (_num, _q, _i) in &config.nft_item_id {335                <Module<T>>::init_nft_token(_i);336            }337338            for (_num, _q, _i) in &config.fungible_item_id {339                <Module<T>>::init_fungible_token(_i);340            }341342            for (_num, _q, _i) in &config.refungible_item_id {343                <Module<T>>::init_refungible_token(_i);344            }345        })346    }347}348349decl_event!(350    pub enum Event<T>351    where352        AccountId = <T as system::Trait>::AccountId,353    {354        /// New collection was created355        /// 356        /// # Arguments357        /// 358        /// * collection_id: Globally unique identifier of newly created collection.359        /// 360        /// * mode: [CollectionMode] converted into u8.361        /// 362        /// * account_id: Collection owner.363        Created(u64, u8, AccountId),364365        /// New item was created.366        /// 367        /// # Arguments368        /// 369        /// * collection_id: Id of the collection where item was created.370        /// 371        /// * item_id: Id of an item. Unique within the collection.372        ItemCreated(u64, u64),373374        /// Collection item was burned.375        /// 376        /// # Arguments377        /// 378        /// collection_id.379        /// 380        /// item_id: Identifier of burned NFT.381        ItemDestroyed(u64, u64),382    }383);384385decl_module! {386    pub struct Module<T: Trait> for enum Call where origin: T::Origin {387388        fn deposit_event() = default;389390        fn on_initialize(now: T::BlockNumber) -> Weight {391392            if ChainVersion::get() < 2393            {394                let value = NextCollectionID::get();395                CreatedCollectionCount::put(value);396                ChainVersion::put(2);397            }398399            0400        }401402        /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner and admin of the collection are set to the address that signed the transaction. Both addresses can be changed later.403        /// 404        /// # Permissions405        /// 406        /// * Anyone.407        /// 408        /// # Arguments409        /// 410        /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.411        /// 412        /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.413        /// 414        /// * token_prefix: UTF-8 string with token prefix.415        /// 416        /// * mode: [CollectionMode] collection type and type dependent data.417        // returns collection ID418        #[weight = T::WeightInfo::create_collection()]419        pub fn create_collection(origin,420                                 collection_name: Vec<u16>,421                                 collection_description: Vec<u16>,422                                 token_prefix: Vec<u8>,423                                 mode: CollectionMode) -> DispatchResult {424425            // Anyone can create a collection426            let who = ensure_signed(origin)?;427428            let decimal_points = match mode {429                CollectionMode::Fungible(points) => points,430                CollectionMode::ReFungible(points) => points,431                _ => 0432            };433434            // bound Total number of collections435            ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded");436437            // check params438            ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");439440            let mut name = collection_name.to_vec();441            name.push(0);442            ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");443444            let mut description = collection_description.to_vec();445            description.push(0);446            ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");447448            let mut prefix = token_prefix.to_vec();449            prefix.push(0);450            ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");451452            // Generate next collection ID453            let next_id = CreatedCollectionCount::get()454                .checked_add(1)455                .expect("collection id error");456457            // bound counter458            let total = CollectionCount::get()459                .checked_add(1)460                .expect("collection counter error");461462            CreatedCollectionCount::put(next_id);463            CollectionCount::put(total);464465            // Create new collection466            let new_collection = CollectionType {467                owner: who.clone(),468                name: name,469                mode: mode.clone(),470                mint_mode: false,471                access: AccessMode::Normal,472                description: description,473                decimal_points: decimal_points,474                token_prefix: prefix,475                offchain_schema: Vec::new(),476                sponsor: T::AccountId::default(),477                unconfirmed_sponsor: T::AccountId::default(),478                variable_on_chain_schema: Vec::new(),479                const_on_chain_schema: Vec::new(),480            };481482            // Add new collection to map483            <Collection<T>>::insert(next_id, new_collection);484485            // call event486            Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));487488            Ok(())489        }490491        /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.492        ///     493        /// # Permissions494        /// 495        /// * Collection Owner.496        /// 497        /// # Arguments498        /// 499        /// * collection_id: collection to destroy.500        #[weight = T::WeightInfo::destroy_collection()]501        pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {502503            let sender = ensure_signed(origin)?;504            Self::check_owner_permissions(collection_id, sender)?;505506            <AddressTokens<T>>::remove_prefix(collection_id);507            <ApprovedList<T>>::remove_prefix(collection_id);508            <Balance<T>>::remove_prefix(collection_id);509            <ItemListIndex>::remove(collection_id);510            <AdminList<T>>::remove(collection_id);511            <Collection<T>>::remove(collection_id);512            <WhiteList<T>>::remove(collection_id);513514            <NftItemList<T>>::remove_prefix(collection_id);515            <FungibleItemList<T>>::remove_prefix(collection_id);516            <ReFungibleItemList<T>>::remove_prefix(collection_id);517518            <NftTransferBasket<T>>::remove_prefix(collection_id);519            <FungibleTransferBasket<T>>::remove_prefix(collection_id);520            <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);521522            if CollectionCount::get() > 0523            {524                // bound couter525                let total = CollectionCount::get()526                    .checked_sub(1)527                    .expect("collection counter error");528529                CollectionCount::put(total);530            }531532            Ok(())533        }534535        /// Add an address to white list.536        /// 537        /// # Permissions538        /// 539        /// * Collection Owner540        /// * Collection Admin541        /// 542        /// # Arguments543        /// 544        /// * collection_id.545        /// 546        /// * address.547        #[weight = T::WeightInfo::add_to_white_list()]548        pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{549550            let sender = ensure_signed(origin)?;551            Self::check_owner_or_admin_permissions(collection_id, sender)?;552553            let mut white_list_collection: Vec<T::AccountId>;554            if <WhiteList<T>>::contains_key(collection_id) {555                white_list_collection = <WhiteList<T>>::get(collection_id);556                if !white_list_collection.contains(&address.clone())557                {558                    white_list_collection.push(address.clone());559                }560            }561            else {562                white_list_collection = Vec::new();563                white_list_collection.push(address.clone());564            }565566            <WhiteList<T>>::insert(collection_id, white_list_collection);567            Ok(())568        }569570        /// Remove an address from white list.571        /// 572        /// # Permissions573        /// 574        /// * Collection Owner575        /// * Collection Admin576        /// 577        /// # Arguments578        /// 579        /// * collection_id.580        /// 581        /// * address.582        #[weight = T::WeightInfo::remove_from_white_list()]583        pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{584585            let sender = ensure_signed(origin)?;586            Self::check_owner_or_admin_permissions(collection_id, sender)?;587588            if <WhiteList<T>>::contains_key(collection_id) {589                let mut white_list_collection = <WhiteList<T>>::get(collection_id);590                if white_list_collection.contains(&address.clone())591                {592                    white_list_collection.retain(|i| *i != address.clone());593                    <WhiteList<T>>::insert(collection_id, white_list_collection);594                }595            }596597            Ok(())598        }599600        /// Toggle between normal and white list access for the methods with access for `Anyone`.601        /// 602        /// # Permissions603        /// 604        /// * Collection Owner.605        /// 606        /// # Arguments607        /// 608        /// * collection_id.609        /// 610        /// * mode: [AccessMode]611        #[weight = T::WeightInfo::set_public_access_mode()]612        pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult613        {614            let sender = ensure_signed(origin)?;615616            Self::check_owner_permissions(collection_id, sender)?;617            let mut target_collection = <Collection<T>>::get(collection_id);618            target_collection.access = mode;619            <Collection<T>>::insert(collection_id, target_collection);620621            Ok(())622        }623624        /// Allows Anyone to create tokens if:625        /// * White List is enabled, and626        /// * Address is added to white list, and627        /// * This method was called with True parameter628        /// 629        /// # Permissions630        /// * Collection Owner631        ///632        /// # Arguments633        /// 634        /// * collection_id.635        /// 636        /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.637        #[weight = T::WeightInfo::set_mint_permission()]638        pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult639        {640            let sender = ensure_signed(origin)?;641642            Self::check_owner_permissions(collection_id, sender)?;643            let mut target_collection = <Collection<T>>::get(collection_id);644            target_collection.mint_mode = mint_permission;645            <Collection<T>>::insert(collection_id, target_collection);646647            Ok(())648        }649650        /// Change the owner of the collection.651        /// 652        /// # Permissions653        /// 654        /// * Collection Owner.655        /// 656        /// # Arguments657        /// 658        /// * collection_id.659        /// 660        /// * new_owner.661        #[weight = T::WeightInfo::change_collection_owner()]662        pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {663664            let sender = ensure_signed(origin)?;665            Self::check_owner_permissions(collection_id, sender)?;666            let mut target_collection = <Collection<T>>::get(collection_id);667            target_collection.owner = new_owner;668            <Collection<T>>::insert(collection_id, target_collection);669670            Ok(())671        }672673        /// Adds an admin of the Collection.674        /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership. 675        /// 676        /// # Permissions677        /// 678        /// * Collection Owner.679        /// * Collection Admin.680        /// 681        /// # Arguments682        /// 683        /// * collection_id: ID of the Collection to add admin for.684        /// 685        /// * new_admin_id: Address of new admin to add.686        #[weight = T::WeightInfo::add_collection_admin()]687        pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {688689            let sender = ensure_signed(origin)?;690            Self::check_owner_or_admin_permissions(collection_id, sender)?;691            let mut admin_arr: Vec<T::AccountId> = Vec::new();692693            if <AdminList<T>>::contains_key(collection_id)694            {695                admin_arr = <AdminList<T>>::get(collection_id);696                ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");697            }698699            // Number of collection admins700            ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded");701702            admin_arr.push(new_admin_id);703            <AdminList<T>>::insert(collection_id, admin_arr);704705            Ok(())706        }707708        /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.709        ///710        /// # Permissions711        /// 712        /// * Collection Owner.713        /// * Collection Admin.714        /// 715        /// # Arguments716        /// 717        /// * collection_id: ID of the Collection to remove admin for.718        /// 719        /// * account_id: Address of admin to remove.720        #[weight = T::WeightInfo::remove_collection_admin()]721        pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {722723            let sender = ensure_signed(origin)?;724            Self::check_owner_or_admin_permissions(collection_id, sender)?;725726            if <AdminList<T>>::contains_key(collection_id)727            {728                let mut admin_arr = <AdminList<T>>::get(collection_id);729                admin_arr.retain(|i| *i != account_id);730                <AdminList<T>>::insert(collection_id, admin_arr);731            }732733            Ok(())734        }735736        /// # Permissions737        /// 738        /// * Collection Owner739        /// 740        /// # Arguments741        /// 742        /// * collection_id.743        /// 744        /// * new_sponsor.745        #[weight = T::WeightInfo::set_collection_sponsor()]746        pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {747748            let sender = ensure_signed(origin)?;749            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");750751            let mut target_collection = <Collection<T>>::get(collection_id);752            ensure!(sender == target_collection.owner, "You do not own this collection");753754            target_collection.unconfirmed_sponsor = new_sponsor;755            <Collection<T>>::insert(collection_id, target_collection);756757            Ok(())758        }759760        /// # Permissions761        /// 762        /// * Sponsor.763        /// 764        /// # Arguments765        /// 766        /// * collection_id.767        #[weight = T::WeightInfo::confirm_sponsorship()]768        pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {769770            let sender = ensure_signed(origin)?;771            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");772773            let mut target_collection = <Collection<T>>::get(collection_id);774            ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");775776            target_collection.sponsor = target_collection.unconfirmed_sponsor;777            target_collection.unconfirmed_sponsor = T::AccountId::default();778            <Collection<T>>::insert(collection_id, target_collection);779780            Ok(())781        }782783        /// Switch back to pay-per-own-transaction model.784        ///785        /// # Permissions786        ///787        /// * Collection owner.788        /// 789        /// # Arguments790        /// 791        /// * collection_id.792        #[weight = T::WeightInfo::remove_collection_sponsor()]793        pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {794795            let sender = ensure_signed(origin)?;796            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");797798            let mut target_collection = <Collection<T>>::get(collection_id);799            ensure!(sender == target_collection.owner, "You do not own this collection");800801            target_collection.sponsor = T::AccountId::default();802            <Collection<T>>::insert(collection_id, target_collection);803804            Ok(())805        }806807        /// This method creates a concrete instance of NFT Collection created with CreateCollection method.808        /// 809        /// # Permissions810        /// 811        /// * Collection Owner.812        /// * Collection Admin.813        /// * Anyone if814        ///     * White List is enabled, and815        ///     * Address is added to white list, and816        ///     * MintPermission is enabled (see SetMintPermission method)817        /// 818        /// # Arguments819        /// 820        /// * collection_id: ID of the collection.821        /// 822        /// * owner: Address, initial owner of the NFT.823        ///824        /// * data: Token data to store on chain.825        // #[weight =826        // (130_000_000 as Weight)827        // .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))828        // .saturating_add(RocksDbWeight::get().reads(10 as Weight))829        // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]830831        #[weight = T::WeightInfo::create_item(data.len())]832        pub fn create_item(origin, collection_id: u64, owner: T::AccountId, data: CreateItemData) -> DispatchResult {833834            let sender = ensure_signed(origin)?;835            Self::collection_exists(collection_id)?;836            let target_collection = <Collection<T>>::get(collection_id);837838            if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {839                ensure!(target_collection.mint_mode == true, "Public minting is not allowed for this collection.");840                Self::check_white_list(collection_id, &owner)?;841                Self::check_white_list(collection_id, &sender)?;842            }843844            match target_collection.mode845            {846                CollectionMode::NFT => {847                    if let CreateItemData::NFT(data) = data {848                        // check sizes849                        ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, "const_data exceeded data limit.");850                        ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, "variable_data exceeded data limit.");851    852                        // Create nft item853                        let item = NftItemType {854                            collection: collection_id,855                            owner: owner,856                            const_data: data.const_data.clone(),857                            variable_data: data.variable_data.clone() 858                        };859    860                        Self::add_nft_item(item)?;861                    862                    } else {863                        fail!("Not NFT item data used to mint in NFT collection.");864                    }865                },866                CollectionMode::Fungible(_) => {867                    if let CreateItemData::Fungible(_) = data {868    869                        let item = FungibleItemType {870                            collection: collection_id,871                            owner: owner,872                            value: (10 as u128).pow(target_collection.decimal_points)873                        };874    875                        Self::add_fungible_item(item)?;876                    } else {877                        fail!("Not Fungible item data used to mint in Fungible collection.");878                    }879                },880                CollectionMode::ReFungible(_) => {881                    if let CreateItemData::ReFungible(data) = data {882    883                        // check sizes884                        ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, "const_data exceeded data limit.");885                        ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, "variable_data exceeded data limit.");886    887                        let mut owner_list = Vec::new();888                        let value = (10 as u128).pow(target_collection.decimal_points);889                        owner_list.push(Ownership {owner: owner.clone(), fraction: value});890    891                        let item = ReFungibleItemType {892                            collection: collection_id,893                            owner: owner_list,894                            const_data: data.const_data.clone(),895                            variable_data: data.variable_data.clone() 896                        };897    898                        Self::add_refungible_item(item)?;899                    } else {900                        fail!("Not Re Fungible item data used to mint in Re Fungible collection.");901                    }902                },903                _ => { ensure!(1 == 0,"Unexpected collection type."); }904            };905906            // call event907            Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));908909            Ok(())910        }911912        /// Destroys a concrete instance of NFT.913        /// 914        /// # Permissions915        /// 916        /// * Collection Owner.917        /// * Collection Admin.918        /// * Current NFT Owner.919        /// 920        /// # Arguments921        /// 922        /// * collection_id: ID of the collection.923        /// 924        /// * item_id: ID of NFT to burn.925        #[weight = T::WeightInfo::burn_item()]926        pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {927928            let sender = ensure_signed(origin)?;929            Self::collection_exists(collection_id)?;930931            // Transfer permissions check932            let target_collection = <Collection<T>>::get(collection_id);933            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||934                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),935                "Only item owner, collection owner and admins can modify item");936937            if target_collection.access == AccessMode::WhiteList {938                Self::check_white_list(collection_id, &sender)?;939            }940941            match target_collection.mode942            {943                CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,944                CollectionMode::Fungible(_)  => Self::burn_fungible_item(collection_id, item_id)?,945                CollectionMode::ReFungible(_)  => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,946                _ => ()947            };948949            // call event950            Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));951952            Ok(())953        }954955        /// Change ownership of the token.956        /// 957        /// # Permissions958        /// 959        /// * Collection Owner960        /// * Collection Admin961        /// * Current NFT owner962        ///963        /// # Arguments964        /// 965        /// * recipient: Address of token recipient.966        /// 967        /// * collection_id.968        /// 969        /// * item_id: ID of the item970        ///     * Non-Fungible Mode: Required.971        ///     * Fungible Mode: Ignored.972        ///     * Re-Fungible Mode: Required.973        /// 974        /// * value: Amount to transfer.975        ///     * Non-Fungible Mode: Ignored976        ///     * Fungible Mode: Must specify transferred amount977        ///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)978        #[weight = T::WeightInfo::transfer()]979        pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {980981            let sender = ensure_signed(origin)?;982983            // Transfer permissions check984            let target_collection = <Collection<T>>::get(collection_id);985            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||986                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),987                "Only item owner, collection owner and admins can modify item");988989            if target_collection.access == AccessMode::WhiteList {990                Self::check_white_list(collection_id, &sender)?;991                Self::check_white_list(collection_id, &recipient)?;992            }993994            match target_collection.mode995            {996                CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,997                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,998                CollectionMode::ReFungible(_)  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,999                _ => ()1000            };10011002            Ok(())1003        }10041005        /// Set, change, or remove approved address to transfer the ownership of the NFT.1006        /// 1007        /// # Permissions1008        /// 1009        /// * Collection Owner1010        /// * Collection Admin1011        /// * Current NFT owner1012        /// 1013        /// # Arguments1014        /// 1015        /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).1016        /// 1017        /// * collection_id.1018        /// 1019        /// * item_id: ID of the item.1020        #[weight = T::WeightInfo::approve()]1021        pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {10221023            let sender = ensure_signed(origin)?;10241025            // Transfer permissions check1026            let target_collection = <Collection<T>>::get(collection_id);1027            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1028                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1029                "Only item owner, collection owner and admins can approve");10301031            if target_collection.access == AccessMode::WhiteList {1032                Self::check_white_list(collection_id, &sender)?;1033                Self::check_white_list(collection_id, &approved)?;1034            }10351036            // amount param stub1037            let amount = 100000000;10381039            let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1040            if list_exists {10411042                let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1043                let item_contains = list.iter().any(|i| i.approved == approved);10441045                if !item_contains {1046                    list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1047                    <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1048                }1049            } else {10501051                let mut list = Vec::new();1052                list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1053                <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1054            }10551056            Ok(())1057        }1058        1059        /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.1060        /// 1061        /// # Permissions1062        /// * Collection Owner1063        /// * Collection Admin1064        /// * Current NFT owner1065        /// * Address approved by current NFT owner1066        /// 1067        /// # Arguments1068        /// 1069        /// * from: Address that owns token.1070        /// 1071        /// * recipient: Address of token recipient.1072        /// 1073        /// * collection_id.1074        /// 1075        /// * item_id: ID of the item.1076        /// 1077        /// * value: Amount to transfer.1078        #[weight = T::WeightInfo::transfer_from()]1079        pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {10801081            let sender = ensure_signed(origin)?;1082            let mut appoved_transfer = false;10831084            // Check approve1085            if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1086                let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1087                let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1088                if opt_item.is_some()1089                {1090                    appoved_transfer = true;1091                    ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");1092                }1093            }10941095            // Transfer permissions check1096            let target_collection = <Collection<T>>::get(collection_id);1097            ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1098                "Only item owner, collection owner and admins can modify items");10991100            if target_collection.access == AccessMode::WhiteList {1101                Self::check_white_list(collection_id, &sender)?;1102                Self::check_white_list(collection_id, &recipient)?;1103            }11041105            // remove approve1106            let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1107                .into_iter().filter(|i| i.approved != sender.clone()).collect();1108            <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);110911101111            match target_collection.mode1112            {1113                CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1114                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1115                CollectionMode::ReFungible(_)  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1116                _ => ()1117            };11181119            Ok(())1120        }11211122        ///1123        #[weight = 0]1124        pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {11251126            // let no_perm_mes = "You do not have permissions to modify this collection";1127            // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1128            // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1129            // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);11301131            // // on_nft_received  call11321133            // Self::transfer(origin, collection_id, item_id, new_owner)?;11341135            Ok(())1136        }1137        1138        /// Set off-chain data schema.1139        /// 1140        /// # Permissions1141        /// 1142        /// * Collection Owner1143        /// * Collection Admin1144        /// 1145        /// # Arguments1146        /// 1147        /// * collection_id.1148        /// 1149        /// * schema: String representing the offchain data schema.1150        #[weight = T::WeightInfo::set_variable_meta_data()]1151        pub fn set_variable_meta_data (1152            origin,1153            collection_id: u64,1154            item_id: u64,1155            data: Vec<u8>1156        ) -> DispatchResult {1157            let sender = ensure_signed(origin)?;1158            1159            Self::collection_exists(collection_id)?;11601161            // Modify permissions check1162            let target_collection = <Collection<T>>::get(collection_id);1163            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1164                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1165                "Only item owner, collection owner and admins can modify item");11661167            Self::item_exists(collection_id, item_id, &target_collection.mode)?;11681169            match target_collection.mode1170            {1171                CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1172                CollectionMode::ReFungible(_)  => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1173                _ => ()1174            };11751176            Ok(())1177        }1178        11791180        /// Set off-chain data schema.1181        /// 1182        /// # Permissions1183        /// 1184        /// * Collection Owner1185        /// * Collection Admin1186        /// 1187        /// # Arguments1188        /// 1189        /// * collection_id.1190        /// 1191        /// * schema: String representing the offchain data schema.1192        #[weight = T::WeightInfo::set_offchain_schema()]1193        pub fn set_offchain_schema(1194            origin,1195            collection_id: u64,1196            schema: Vec<u8>1197        ) -> DispatchResult {1198            let sender = ensure_signed(origin)?;1199            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12001201            let mut target_collection = <Collection<T>>::get(collection_id);1202            target_collection.offchain_schema = schema;1203            <Collection<T>>::insert(collection_id, target_collection);12041205            Ok(())1206        }12071208        /// Set const on-chain data schema.1209        /// 1210        /// # Permissions1211        /// 1212        /// * Collection Owner1213        /// * Collection Admin1214        /// 1215        /// # Arguments1216        /// 1217        /// * collection_id.1218        /// 1219        /// * schema: String representing the const on-chain data schema.1220        #[weight = T::WeightInfo::set_const_on_chain_schema()]1221        pub fn set_const_on_chain_schema (1222            origin,1223            collection_id: u64,1224            schema: Vec<u8>1225        ) -> DispatchResult {1226            let sender = ensure_signed(origin)?;1227            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12281229            let mut target_collection = <Collection<T>>::get(collection_id);1230            target_collection.const_on_chain_schema = schema;1231            <Collection<T>>::insert(collection_id, target_collection);12321233            Ok(())1234        }12351236        /// Set variable on-chain data schema.1237        /// 1238        /// # Permissions1239        /// 1240        /// * Collection Owner1241        /// * Collection Admin1242        /// 1243        /// # Arguments1244        /// 1245        /// * collection_id.1246        /// 1247        /// * schema: String representing the variable on-chain data schema.1248        #[weight = T::WeightInfo::set_const_on_chain_schema()]1249        pub fn set_variable_on_chain_schema (1250            origin,1251            collection_id: u64,1252            schema: Vec<u8>1253        ) -> DispatchResult {1254            let sender = ensure_signed(origin)?;1255            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12561257            let mut target_collection = <Collection<T>>::get(collection_id);1258            target_collection.variable_on_chain_schema = schema;1259            <Collection<T>>::insert(collection_id, target_collection);12601261            Ok(())1262        }12631264        // Sudo permissions function1265        #[weight = 0]1266        pub fn set_chain_limits(1267            origin,1268            limits: ChainLimits1269        ) -> DispatchResult {1270            ensure_root(origin)?;1271            <ChainLimit>::put(limits);1272            Ok(())1273        }12741275        /// Enable smart contract self-sponsoring.1276        /// 1277        /// # Permissions1278        /// 1279        /// * Contract Owner1280        /// 1281        /// # Arguments1282        /// 1283        /// * contract address1284        /// * enable flag1285        /// 1286        #[weight = 0]1287        pub fn enable_contract_sponsoring(1288            origin,1289            contract_address: T::AccountId,1290            enable: bool1291        ) -> DispatchResult {1292            let sender = ensure_signed(origin)?;1293            let mut is_owner = false;1294            if <ContractOwner<T>>::contains_key(contract_address.clone()) {1295                let owner = <ContractOwner<T>>::get(&contract_address);1296                is_owner = sender == owner;1297            }1298            ensure!(is_owner, "Only contract owner may call this method");12991300            <ContractSelfSponsoring<T>>::insert(contract_address, enable);1301            Ok(())1302        }13031304    }1305}13061307impl<T: Trait> Module<T> {1308    fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1309        let current_index = <ItemListIndex>::get(item.collection)1310            .checked_add(1)1311            .expect("Item list index id error");1312        let itemcopy = item.clone();1313        let owner = item.owner.clone();1314        let value = item.value as u64;13151316        Self::add_token_index(item.collection, current_index, owner.clone())?;13171318        <ItemListIndex>::insert(item.collection, current_index);1319        <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);13201321        // Add current block1322        let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1323        <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1324        1325        // Update balance1326        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1327            .checked_add(value)1328            .unwrap();1329        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);13301331        Ok(())1332    }13331334    fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1335        let current_index = <ItemListIndex>::get(item.collection)1336            .checked_add(1)1337            .expect("Item list index id error");1338        let itemcopy = item.clone();13391340        let value = item.owner.first().unwrap().fraction as u64;1341        let owner = item.owner.first().unwrap().owner.clone();13421343        Self::add_token_index(item.collection, current_index, owner.clone())?;13441345        <ItemListIndex>::insert(item.collection, current_index);1346        <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);13471348        // Add current block1349        let block_number: T::BlockNumber = 0.into();1350        <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);13511352        // Update balance1353        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1354            .checked_add(value)1355            .unwrap();1356        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);13571358        Ok(())1359    }13601361    fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1362        let current_index = <ItemListIndex>::get(item.collection)1363            .checked_add(1)1364            .expect("Item list index id error");13651366        let item_owner = item.owner.clone();1367        let collection_id = item.collection.clone();1368        Self::add_token_index(collection_id, current_index, item.owner.clone())?;13691370        <ItemListIndex>::insert(collection_id, current_index);1371        <NftItemList<T>>::insert(collection_id, current_index, item);13721373        // Add current block1374        let block_number: T::BlockNumber = 0.into();1375        <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);13761377        // Update balance1378        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1379            .checked_add(1)1380            .unwrap();1381        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);13821383        Ok(())1384    }13851386    fn burn_refungible_item(1387        collection_id: u64,1388        item_id: u64,1389        owner: T::AccountId,1390    ) -> DispatchResult {1391        ensure!(1392            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1393            "Item does not exists"1394        );1395        let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1396        let item = collection1397            .owner1398            .iter()1399            .filter(|&i| i.owner == owner)1400            .next()1401            .unwrap();1402        Self::remove_token_index(collection_id, item_id, owner.clone())?;14031404        // remove approve list1405        <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));14061407        // update balance1408        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1409            .checked_sub(item.fraction as u64)1410            .unwrap();1411        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);14121413        <ReFungibleItemList<T>>::remove(collection_id, item_id);14141415        Ok(())1416    }14171418    fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {1419        ensure!(1420            <NftItemList<T>>::contains_key(collection_id, item_id),1421            "Item does not exists"1422        );1423        let item = <NftItemList<T>>::get(collection_id, item_id);1424        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;14251426        // remove approve list1427        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));14281429        // update balance1430        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1431            .checked_sub(1)1432            .unwrap();1433        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1434        <NftItemList<T>>::remove(collection_id, item_id);14351436        Ok(())1437    }14381439    fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {1440        ensure!(1441            <FungibleItemList<T>>::contains_key(collection_id, item_id),1442            "Item does not exists"1443        );1444        let item = <FungibleItemList<T>>::get(collection_id, item_id);1445        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;14461447        // remove approve list1448        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));14491450        // update balance1451        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1452            .checked_sub(item.value as u64)1453            .unwrap();1454        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);14551456        <FungibleItemList<T>>::remove(collection_id, item_id);14571458        Ok(())1459    }14601461    fn collection_exists(collection_id: u64) -> DispatchResult {1462        ensure!(1463            <Collection<T>>::contains_key(collection_id),1464            "This collection does not exist"1465        );1466        Ok(())1467    }14681469    fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {1470        Self::collection_exists(collection_id)?;14711472        let target_collection = <Collection<T>>::get(collection_id);1473        ensure!(1474            subject == target_collection.owner,1475            "You do not own this collection"1476        );14771478        Ok(())1479    }14801481    fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {1482        let target_collection = <Collection<T>>::get(collection_id);1483        let mut result: bool = subject == target_collection.owner;1484        let exists = <AdminList<T>>::contains_key(collection_id);14851486        if !result & exists {1487            if <AdminList<T>>::get(collection_id).contains(&subject) {1488                result = true1489            }1490        }14911492        result1493    }14941495    fn check_owner_or_admin_permissions(1496        collection_id: u64,1497        subject: T::AccountId,1498    ) -> DispatchResult {1499        Self::collection_exists(collection_id)?;1500        let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());15011502        ensure!(1503            result,1504            "You do not have permissions to modify this collection"1505        );1506        Ok(())1507    }15081509    fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1510        let target_collection = <Collection<T>>::get(collection_id);15111512        match target_collection.mode {1513            CollectionMode::NFT => {1514                <NftItemList<T>>::get(collection_id, item_id).owner == subject1515            }1516            CollectionMode::Fungible(_) => {1517                <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1518            }1519            CollectionMode::ReFungible(_) => {1520                <ReFungibleItemList<T>>::get(collection_id, item_id)1521                    .owner1522                    .iter()1523                    .any(|i| i.owner == subject)1524            }1525            CollectionMode::Invalid => false,1526        }1527    }15281529    fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {1530        let mes = "Address is not in white list";1531        ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1532        let wl = <WhiteList<T>>::get(collection_id);1533        ensure!(wl.contains(address), mes);15341535        Ok(())1536    }15371538    fn transfer_fungible(1539        collection_id: u64,1540        item_id: u64,1541        value: u64,1542        owner: T::AccountId,1543        new_owner: T::AccountId,1544    ) -> DispatchResult {1545        ensure!(1546            <FungibleItemList<T>>::contains_key(collection_id, item_id),1547            "Item not exists"1548        );15491550        let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1551        let amount = full_item.value;15521553        ensure!(amount >= value.into(), "Item balance not enouth");15541555        // update balance1556        let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1557            .checked_sub(value)1558            .unwrap();1559        <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);15601561        let mut new_owner_account_id = 0;1562        let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1563        if new_owner_items.len() > 0 {1564            new_owner_account_id = new_owner_items[0];1565        }15661567        let val64 = value.into();15681569        // transfer1570        if amount == val64 && new_owner_account_id == 0 {1571            // change owner1572            // new owner do not have account1573            let mut new_full_item = full_item.clone();1574            new_full_item.owner = new_owner.clone();1575            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);15761577            // update balance1578            let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1579                .checked_add(value)1580                .unwrap();1581            <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15821583            // update index collection1584            Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1585        } else {1586            let mut new_full_item = full_item.clone();1587            new_full_item.value -= val64;15881589            // separate amount1590            if new_owner_account_id > 0 {1591                // new owner has account1592                let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1593                item.value += val64;15941595                // update balance1596                let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1597                    .checked_add(value)1598                    .unwrap();1599                <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);16001601                <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1602            } else {1603                // new owner do not have account1604                let item = FungibleItemType {1605                    collection: collection_id,1606                    owner: new_owner.clone(),1607                    value: val64,1608                };16091610                Self::add_fungible_item(item)?;1611            }16121613            if amount == val64 {1614                Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;16151616                // remove approve list1617                <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1618                <FungibleItemList<T>>::remove(collection_id, item_id);1619            }16201621            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1622        }16231624        Ok(())1625    }16261627    fn transfer_refungible(1628        collection_id: u64,1629        item_id: u64,1630        value: u64,1631        owner: T::AccountId,1632        new_owner: T::AccountId,1633    ) -> DispatchResult {1634        ensure!(1635            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1636            "Item not exists"1637        );16381639        let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1640        let item = full_item1641            .owner1642            .iter()1643            .filter(|i| i.owner == owner)1644            .next()1645            .unwrap();1646        let amount = item.fraction;16471648        ensure!(amount >= value.into(), "Item balance not enouth");16491650        // update balance1651        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1652            .checked_sub(value)1653            .unwrap();1654        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);16551656        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1657            .checked_add(value)1658            .unwrap();1659        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);16601661        let old_owner = item.owner.clone();1662        let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1663        let val64 = value.into();16641665        // transfer1666        if amount == val64 && !new_owner_has_account {1667            // change owner1668            // new owner do not have account1669            let mut new_full_item = full_item.clone();1670            new_full_item1671                .owner1672                .iter_mut()1673                .find(|i| i.owner == owner)1674                .unwrap()1675                .owner = new_owner.clone();1676            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);16771678            // update index collection1679            Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1680        } else {1681            let mut new_full_item = full_item.clone();1682            new_full_item1683                .owner1684                .iter_mut()1685                .find(|i| i.owner == owner)1686                .unwrap()1687                .fraction -= val64;16881689            // separate amount1690            if new_owner_has_account {1691                // new owner has account1692                new_full_item1693                    .owner1694                    .iter_mut()1695                    .find(|i| i.owner == new_owner)1696                    .unwrap()1697                    .fraction += val64;1698            } else {1699                // new owner do not have account1700                new_full_item.owner.push(Ownership {1701                    owner: new_owner.clone(),1702                    fraction: val64,1703                });1704                Self::add_token_index(collection_id, item_id, new_owner.clone())?;1705            }17061707            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1708        }17091710        Ok(())1711    }17121713    fn transfer_nft(1714        collection_id: u64,1715        item_id: u64,1716        sender: T::AccountId,1717        new_owner: T::AccountId,1718    ) -> DispatchResult {1719        ensure!(1720            <NftItemList<T>>::contains_key(collection_id, item_id),1721            "Item not exists"1722        );17231724        let mut item = <NftItemList<T>>::get(collection_id, item_id);17251726        ensure!(1727            sender == item.owner,1728            "sender parameter and item owner must be equal"1729        );17301731        // update balance1732        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1733            .checked_sub(1)1734            .unwrap();1735        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);17361737        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1738            .checked_add(1)1739            .unwrap();1740        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);17411742        // change owner1743        let old_owner = item.owner.clone();1744        item.owner = new_owner.clone();1745        <NftItemList<T>>::insert(collection_id, item_id, item);17461747        // update index collection1748        Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;17491750        // reset approved list1751        <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1752        Ok(())1753    }1754    1755    fn item_exists(1756        collection_id: u64,1757        item_id: u64,1758        mode: &CollectionMode1759    ) -> DispatchResult {1760        match mode {1761            CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), "Item does not exists"),1762            CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), "Item does not exists"),1763            CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), "Item does not exists"),1764            _ => ()1765        };1766        1767        Ok(())1768    }17691770    fn set_re_fungible_variable_data(1771        collection_id: u64,1772        item_id: u64,1773        data: Vec<u8>1774    ) -> DispatchResult {1775        let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);17761777        item.variable_data = data;17781779        <ReFungibleItemList<T>>::insert(collection_id, item_id, item);17801781        Ok(())1782    }17831784    fn set_nft_variable_data(1785        collection_id: u64,1786        item_id: u64,1787        data: Vec<u8>1788    ) -> DispatchResult {1789        let mut item = <NftItemList<T>>::get(collection_id, item_id);1790        1791        item.variable_data = data;17921793        <NftItemList<T>>::insert(collection_id, item_id, item);1794        1795        Ok(())1796    }17971798    fn init_collection(item: &CollectionType<T::AccountId>) {1799        // check params1800        assert!(1801            item.decimal_points <= 4,1802            "decimal_points parameter must be lower than 4"1803        );1804        assert!(1805            item.name.len() <= 64,1806            "Collection name can not be longer than 63 char"1807        );1808        assert!(1809            item.name.len() <= 256,1810            "Collection description can not be longer than 255 char"1811        );1812        assert!(1813            item.token_prefix.len() <= 16,1814            "Token prefix can not be longer than 15 char"1815        );18161817        // Generate next collection ID1818        let next_id = CreatedCollectionCount::get()1819            .checked_add(1)1820            .expect("collection id error");18211822        CreatedCollectionCount::put(next_id);1823    }18241825    fn init_nft_token(item: &NftItemType<T::AccountId>) {1826        let current_index = <ItemListIndex>::get(item.collection)1827            .checked_add(1)1828            .expect("Item list index id error");18291830        let item_owner = item.owner.clone();1831        let collection_id = item.collection.clone();1832        Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();18331834        <ItemListIndex>::insert(collection_id, current_index);18351836        // Update balance1837        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1838            .checked_add(1)1839            .unwrap();1840        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1841    }18421843    fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {1844        let current_index = <ItemListIndex>::get(item.collection)1845            .checked_add(1)1846            .expect("Item list index id error");1847        let owner = item.owner.clone();1848        let value = item.value as u64;18491850        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();18511852        <ItemListIndex>::insert(item.collection, current_index);18531854        // Update balance1855        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1856            .checked_add(value)1857            .unwrap();1858        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1859    }18601861    fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {1862        let current_index = <ItemListIndex>::get(item.collection)1863            .checked_add(1)1864            .expect("Item list index id error");18651866        let value = item.owner.first().unwrap().fraction as u64;1867        let owner = item.owner.first().unwrap().owner.clone();18681869        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();18701871        <ItemListIndex>::insert(item.collection, current_index);18721873        // Update balance1874        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1875            .checked_add(value)1876            .unwrap();1877        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1878    }18791880    fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {18811882        // add to account limit1883        if <AccountItemCount<T>>::contains_key(owner.clone()) {18841885            // bound Owned tokens by a single address1886            let count = <AccountItemCount<T>>::get(owner.clone());1887            ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded");18881889            <AccountItemCount<T>>::insert(owner.clone(), 1890                count.checked_add(1).unwrap());1891        }1892        else {1893            <AccountItemCount<T>>::insert(owner.clone(), 1);1894        }18951896        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1897        if list_exists {1898            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1899            let item_contains = list.contains(&item_index.clone());19001901            if !item_contains {1902                list.push(item_index.clone());1903            }19041905            <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1906        } else {1907            let mut itm = Vec::new();1908            itm.push(item_index.clone());1909            <AddressTokens<T>>::insert(collection_id, owner, itm);1910            1911        }19121913        Ok(())1914    }19151916    fn remove_token_index(1917        collection_id: u64,1918        item_index: u64,1919        owner: T::AccountId,1920    ) -> DispatchResult {19211922        // update counter1923        <AccountItemCount<T>>::insert(owner.clone(), 1924            <AccountItemCount<T>>::get(owner.clone()).checked_sub(1).unwrap());192519261927        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1928        if list_exists {1929            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1930            let item_contains = list.contains(&item_index.clone());19311932            if item_contains {1933                list.retain(|&item| item != item_index);1934                <AddressTokens<T>>::insert(collection_id, owner, list);1935            }1936        }19371938        Ok(())1939    }19401941    fn move_token_index(1942        collection_id: u64,1943        item_index: u64,1944        old_owner: T::AccountId,1945        new_owner: T::AccountId,1946    ) -> DispatchResult {1947        Self::remove_token_index(collection_id, item_index, old_owner)?;1948        Self::add_token_index(collection_id, item_index, new_owner)?;19491950        Ok(())1951    }1952}19531954////////////////////////////////////////////////////////////////////////////////////////////////////1955// Economic models1956// #region19571958/// Fee multiplier.1959pub type Multiplier = FixedU128;19601961type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1962    <T as system::Trait>::AccountId,1963>>::Balance;1964type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1965    <T as system::Trait>::AccountId,1966>>::NegativeImbalance;19671968/// Require the transactor pay for themselves and maybe include a tip to gain additional priority1969/// in the queue.1970#[derive(Encode, Decode, Clone, Eq, PartialEq)]1971pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(1972    #[codec(compact)] BalanceOf<T>1973);19741975impl<T: Trait + Send + Sync> sp_std::fmt::Debug1976    for ChargeTransactionPayment<T>1977{1978    #[cfg(feature = "std")]1979    fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1980        write!(f, "ChargeTransactionPayment<{:?}>", self.0)1981    }1982    #[cfg(not(feature = "std"))]1983    fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1984        Ok(())1985    }1986}19871988impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>1989where1990    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,1991    BalanceOf<T>: Send + Sync + FixedPointOperand,1992{1993    /// utility constructor. Used only in client/factory code.1994    pub fn from(fee: BalanceOf<T>) -> Self {1995        Self(fee)1996    }19971998    pub fn traditional_fee(1999        len: usize,2000        info: &DispatchInfoOf<T::Call>,2001        tip: BalanceOf<T>,2002    ) -> BalanceOf<T>2003    where2004        T::Call: Dispatchable<Info = DispatchInfo>,2005    {2006        <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2007    }20082009    fn withdraw_fee(2010        &self,2011        who: &T::AccountId,2012        call: &T::Call,2013        info: &DispatchInfoOf<T::Call>,2014        len: usize,2015    ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2016        let tip = self.0;20172018        // Set fee based on call type. Creating collection costs 1 Unique.2019        // All other transactions have traditional fees so far2020        // let fee = match call.is_sub_type() {2021        //     Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),2022        //     _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes2023        //                                                 // _ => <BalanceOf<T>>::from(100)2024        // };2025        let fee = Self::traditional_fee(len, info, tip);20262027        // Determine who is paying transaction fee based on ecnomic model2028        // Parse call to extract collection ID and access collection sponsor2029        let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2030            Some(Call::create_item(collection_id, _properties, _owner)) => {2031                <Collection<T>>::get(collection_id).sponsor2032            }2033            Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2034                let _collection_mode = <Collection<T>>::get(collection_id).mode;20352036                // sponsor timeout2037                let sponsor_transfer = match _collection_mode {2038                    CollectionMode::NFT => {2039                        let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2040                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2041                        let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();2042                        if block_number >= limit_time {2043                            <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2044                            true2045                        }2046                        else {2047                            false2048                        }2049                    }2050                    CollectionMode::Fungible(_) => {2051                        let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2052                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2053                        if basket.iter().any(|i| i.address == _new_owner.clone())2054                        {2055                            let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2056                            let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();2057                            if block_number >= limit_time {2058                                basket.retain(|x| x.address == item.address);2059                                basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2060                                <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2061                                true2062                            }2063                            else {2064                                false2065                            }2066                        }2067                        else {2068                            basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2069                            true2070                        }2071                    }2072                    CollectionMode::ReFungible(_) => {2073                        let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2074                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2075                        let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();2076                        if block_number >= limit_time {2077                            <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2078                            true2079                        } else {2080                            false2081                        }2082                    }2083                    _ => {2084                        false2085                    },2086                };20872088                if !sponsor_transfer {2089                    T::AccountId::default()2090                } else {2091                    <Collection<T>>::get(collection_id).sponsor2092                }2093            }20942095            _ => T::AccountId::default(),2096        };20972098        // Sponsor smart contracts2099        sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {21002101            // On instantiation: set the contract owner2102            Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {21032104                let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2105                    code_hash,2106                    &data,2107                    &who,2108                );2109                <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());21102111                T::AccountId::default()2112            },21132114            // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is2115            Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {21162117                let mut sp = T::AccountId::default();2118                let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());2119                if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2120                    if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2121                        sp = called_contract;2122                    }2123                }21242125                sp2126            },21272128            _ => sponsor,2129        };21302131        let mut who_pays_fee: T::AccountId = sponsor.clone();2132        if sponsor == T::AccountId::default() {2133            who_pays_fee = who.clone();2134        }21352136        // Only mess with balances if fee is not zero.2137        if fee.is_zero() {2138            return Ok((fee, None));2139        }21402141        match <T as transaction_payment::Trait>::Currency::withdraw(2142            &who_pays_fee,2143            fee,2144            if tip.is_zero() {2145                WithdrawReason::TransactionPayment.into()2146            } else {2147                WithdrawReason::TransactionPayment | WithdrawReason::Tip2148            },2149            ExistenceRequirement::KeepAlive,2150        ) {2151            Ok(imbalance) => Ok((fee, Some(imbalance))),2152            Err(_) => Err(InvalidTransaction::Payment.into()),2153        }2154    }2155}215621572158impl<T: Trait + Send + Sync> SignedExtension2159    for ChargeTransactionPayment<T>2160where2161    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2162    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2163{2164    const IDENTIFIER: &'static str = "ChargeTransactionPayment";2165    type AccountId = T::AccountId;2166    type Call = T::Call;2167    type AdditionalSigned = ();2168    type Pre = (2169        BalanceOf<T>,2170        Self::AccountId,2171        Option<NegativeImbalanceOf<T>>,2172        BalanceOf<T>,2173    );2174    fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2175        Ok(())2176    }21772178    fn validate(2179        &self,2180        _who: &Self::AccountId,2181        _call: &Self::Call,2182        _info: &DispatchInfoOf<Self::Call>,2183        _len: usize,2184    ) -> TransactionValidity {2185        Ok(ValidTransaction::default())2186    }21872188    fn pre_dispatch(2189        self,2190        who: &Self::AccountId,2191        call: &Self::Call,2192        info: &DispatchInfoOf<Self::Call>,2193        len: usize,2194    ) -> Result<Self::Pre, TransactionValidityError> {2195        let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2196        Ok((self.0, who.clone(), imbalance, fee))2197    }21982199    fn post_dispatch(2200        pre: Self::Pre,2201        info: &DispatchInfoOf<Self::Call>,2202        post_info: &PostDispatchInfoOf<Self::Call>,2203        len: usize,2204        _result: &DispatchResult,2205    ) -> Result<(), TransactionValidityError> {2206        let (tip, who, imbalance, fee) = pre;2207        if let Some(payed) = imbalance {2208            let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2209                len as u32, info, post_info, tip,2210            );2211            let refund = fee.saturating_sub(actual_fee);2212            let actual_payment =2213                match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2214                    &who, refund,2215                ) {2216                    Ok(refund_imbalance) => {2217                        // The refund cannot be larger than the up front payed max weight.2218                        // `PostDispatchInfo::calc_unspent` guards against such a case.2219                        match payed.offset(refund_imbalance) {2220                            Ok(actual_payment) => actual_payment,2221                            Err(_) => return Err(InvalidTransaction::Payment.into()),2222                        }2223                    }2224                    // We do not recreate the account using the refund. The up front payment2225                    // is gone in that case.2226                    Err(_) => payed,2227                };2228            let imbalances = actual_payment.split(tip);2229            <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2230                Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2231            );2232        }2233        Ok(())2234    }2235}22362237// #endregion22382239
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -1,21 +1,16 @@
 // Tests to be written here
 use crate::mock::*;
-use crate::{AccessMode, ApprovePermissions, CollectionMode, Ownership, ChainLimits};
+use crate::{AccessMode, ApprovePermissions, CollectionMode, Ownership, ChainLimits, CreateItemData, CreateNftData, CreateFungibleData, CreateReFungibleData};
 use frame_support::{assert_noop, assert_ok};
 use frame_system::{ RawOrigin };
 
-// Use cases tests region
-// #region
-#[test]
-fn create_nft_item() {
-    new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+fn default_collection_numbers_limit() -> u64 {
+    10
+}
 
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
+fn default_limits() {
+    assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
+            collection_numbers_limit: default_collection_numbers_limit(),
             account_token_ownership_limit: 10,
             collections_admins_limit: 5,
             custom_data_limit: 2048,
@@ -23,67 +18,93 @@
             fungible_sponsor_transfer_timeout: 15,
             refungible_sponsor_transfer_timeout: 15,          
         }));
+}
+
+fn default_nft_data() -> CreateNftData {
+    CreateNftData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] }
+}
+
+fn default_fungible_data () -> CreateFungibleData {
+    CreateFungibleData { }
+}
+
+fn default_re_fungible_data () -> CreateReFungibleData {
+    CreateReFungibleData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] }
+}
+
+fn create_test_collection_for_owner(mode: &CollectionMode, owner: u64, id: u64) -> u64 {
+    let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+    let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+    let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
 
-        let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
+    let origin1 = Origin::signed(owner);
+    assert_ok!(TemplateModule::create_collection(
             origin1.clone(),
             col_name1.clone(),
             col_desc1.clone(),
             token_prefix1.clone(),
-            mode
+            mode.clone()
         ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        assert_ok!(TemplateModule::create_item(
+    let saved_col_name: Vec<u16> = "Test1\0\0".encode_utf16().collect::<Vec<u16>>();
+    let saved_description: Vec<u16> = "TestDescription1\0\0".encode_utf16().collect::<Vec<u16>>();
+    let saved_prefix: Vec<u8> = b"token_prefix1\0\0".to_vec();
+    assert_eq!(TemplateModule::collection(id).owner, owner);
+    assert_eq!(TemplateModule::collection(id).name, saved_col_name);
+    assert_eq!(TemplateModule::collection(id).mode, *mode);
+    assert_eq!(TemplateModule::collection(id).description, saved_description);
+    assert_eq!(TemplateModule::collection(id).token_prefix, saved_prefix);
+    id
+}
+
+fn create_test_collection(mode: &CollectionMode, id: u64) -> u64 {
+    create_test_collection_for_owner(&mode, 1, id)
+}
+
+fn create_test_item(collection_id: u64, data: &CreateItemData) {
+    let origin1 = Origin::signed(1);
+    assert_ok!(TemplateModule::create_item(
             origin1.clone(),
+            collection_id,
             1,
-            [1, 2, 3].to_vec(),
-            1
+            data.clone()
         ));
-        assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());
+
+}
+
+// Use cases tests region
+// #region
+#[test]
+fn create_nft_item() {
+    new_test_ext().execute_with(|| {
+        default_limits();
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
+        
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.clone().into());
+        assert_eq!(TemplateModule::nft_item_id(collection_id, 1).const_data, data.const_data);
+        assert_eq!(TemplateModule::nft_item_id(collection_id, 1).variable_data, data.variable_data);
     });
 }
 
 #[test]
 fn create_refungible_item() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::ReFungible(2000, 3);
+        default_limits();
+        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);
 
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
+        let data = default_re_fungible_data();
+        create_test_item(collection_id, &data.clone().into());
+        assert_eq!(
+            TemplateModule::refungible_item_id(collection_id, 1).const_data,
+            data.const_data
+        );
         assert_eq!(
-            TemplateModule::refungible_item_id(1, 1).data,
-            [1, 2, 3].to_vec()
+            TemplateModule::refungible_item_id(collection_id, 1).variable_data,
+            data.variable_data
         );
         assert_eq!(
-            TemplateModule::refungible_item_id(1, 1).owner[0],
+            TemplateModule::refungible_item_id(collection_id, 1).owner[0],
             Ownership {
                 owner: 1,
                 fraction: 1000
@@ -95,38 +116,14 @@
 #[test]
 fn create_fungible_item() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::Fungible(3);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);
 
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
+        let data = default_fungible_data();
+        create_test_item(collection_id, &data.into());
 
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [].to_vec(),
-            1
-        ));
-        assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);
+        assert_eq!(TemplateModule::fungible_item_id(collection_id, 1).owner, 1);
         assert_eq!(TemplateModule::balance_count(1, 1), 1000);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
     });
@@ -135,38 +132,16 @@
 #[test]
 fn transfer_fungible_item() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::Fungible(3);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);
 
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [].to_vec(),
-            1
-        ));
+        let data = default_fungible_data();
+        create_test_item(collection_id, &data.into());
+
         assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);
         assert_eq!(TemplateModule::balance_count(1, 1), 1000);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
@@ -203,44 +178,25 @@
 #[test]
 fn transfer_refungible_item() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::ReFungible(2000, 3);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);
 
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        let data = default_re_fungible_data();
+        create_test_item(collection_id, &data.clone().into());
 
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
         assert_eq!(
-            TemplateModule::refungible_item_id(1, 1).data,
-            [1, 2, 3].to_vec()
+            TemplateModule::refungible_item_id(collection_id, 1).const_data,
+            data.const_data
+        );
+        assert_eq!(
+            TemplateModule::refungible_item_id(collection_id, 1).variable_data,
+            data.variable_data
         );
         assert_eq!(
-            TemplateModule::refungible_item_id(1, 1).owner[0],
+            TemplateModule::refungible_item_id(collection_id, 1).owner[0],
             Ownership {
                 owner: 1,
                 fraction: 1000
@@ -310,41 +266,16 @@
 #[test]
 fn transfer_nft_item() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
-        let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
-        assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
         assert_eq!(TemplateModule::balance_count(1, 1), 1);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
 
+        let origin1 = Origin::signed(1);
         // default scenario
         assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));
         assert_eq!(TemplateModule::nft_item_id(1, 1).owner, 2);
@@ -358,39 +289,16 @@
 #[test]
 fn nft_approve_and_transfer_from() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
 
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
-        assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());
         assert_eq!(TemplateModule::balance_count(1, 1), 1);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
 
@@ -429,39 +337,17 @@
 #[test]
 fn nft_approve_and_transfer_from_white_list() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
-        assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.clone().into());
+
+        assert_eq!(TemplateModule::nft_item_id(1, 1).const_data, data.const_data);
         assert_eq!(TemplateModule::balance_count(1, 1), 1);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
 
@@ -507,49 +393,16 @@
 #[test]
 fn refungible_approve_and_transfer_from() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::ReFungible(2000, 3);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);
+        
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
-        assert_eq!(
-            TemplateModule::refungible_item_id(1, 1).data,
-            [1, 2, 3].to_vec()
-        );
-        assert_eq!(
-            TemplateModule::refungible_item_id(1, 1).owner[0],
-            Ownership {
-                owner: 1,
-                fraction: 1000
-            }
-        );
+        let data = default_re_fungible_data();
+        create_test_item(collection_id, &data.into());
+
         assert_eq!(TemplateModule::balance_count(1, 1), 1000);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
 
@@ -607,39 +460,16 @@
 #[test]
 fn fungible_approve_and_transfer_from() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::Fungible(3);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);
+        
+        let data = default_fungible_data();
+        create_test_item(collection_id, &data.into());
 
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [].to_vec(),
-            1
-        ));
-        assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);
         assert_eq!(TemplateModule::balance_count(1, 1), 1000);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
 
@@ -713,103 +543,44 @@
 #[test]
 fn change_collection_owner() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
+        
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
         assert_ok!(TemplateModule::change_collection_owner(
             origin1.clone(),
-            1,
+            collection_id,
             2
         ));
-        assert_eq!(TemplateModule::collection(1).owner, 2);
+        assert_eq!(TemplateModule::collection(collection_id).owner, 2);
     });
 }
 
 #[test]
 fn destroy_collection() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
+        
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));
+        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));
     });
 }
 
 #[test]
 fn burn_nft_item() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
-
-        assert_eq!(TemplateModule::nft_item_id(1, 1).data, [1, 2, 3].to_vec());
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+        
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
 
         // check balance (collection with id = 1, user id = 1)
         assert_eq!(TemplateModule::balance_count(1, 1), 1);
@@ -828,36 +599,15 @@
 #[test]
 fn burn_fungible_item() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::Fungible(3);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);
+        
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [].to_vec(),
-            1
-        ));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+        
+        let data = default_fungible_data();
+        create_test_item(collection_id, &data.into());
 
         // check balance (collection with id = 1, user id = 1)
         assert_eq!(TemplateModule::balance_count(1, 1), 1000);
@@ -876,56 +626,28 @@
 #[test]
 fn burn_refungible_item() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::ReFungible(200, 3);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);
         let origin1 = Origin::signed(1);
-        let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
 
         assert_ok!(TemplateModule::set_mint_permission(
             origin1.clone(),
-            1,
+            collection_id,
             true
         ));
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
         assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
 
         assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::create_item(
-            origin2.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
+        
+        let data = default_re_fungible_data();
+        create_test_item(collection_id, &data.into());
 
-        assert_eq!(
-            TemplateModule::refungible_item_id(1, 1).data,
-            [1, 2, 3].to_vec()
-        );
-
         // check balance (collection with id = 1, user id = 2)
         assert_eq!(TemplateModule::balance_count(1, 1), 1000);
 
@@ -943,110 +665,38 @@
 #[test]
 fn add_collection_admin() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
+        default_limits();
+        
+        let collection1_id = create_test_collection_for_owner(&CollectionMode::NFT, 1, 1);
+        create_test_collection_for_owner(&CollectionMode::NFT, 2, 2);
+        create_test_collection_for_owner(&CollectionMode::NFT, 3, 3);
+        
         let origin1 = Origin::signed(1);
-        let origin2 = Origin::signed(2);
-        let origin3 = Origin::signed(3);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode.clone()
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin2.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode.clone()
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin3.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode.clone()
-        ));
-
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-        assert_eq!(TemplateModule::collection(2).owner, 2);
-        assert_eq!(TemplateModule::collection(3).owner, 3);
 
         // collection admin
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 2));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 3));
 
-        assert_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);
-        assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);
+        assert_eq!(TemplateModule::admin_list_collection(collection1_id).contains(&2), true);
+        assert_eq!(TemplateModule::admin_list_collection(collection1_id).contains(&3), true);
     });
 }
 
 #[test]
 fn remove_collection_admin() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        default_limits();
+        
+        let collection1_id = create_test_collection_for_owner(&CollectionMode::NFT, 1, 1);
+        create_test_collection_for_owner(&CollectionMode::NFT, 2, 2);
+        create_test_collection_for_owner(&CollectionMode::NFT, 3, 3);
 
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        let origin3 = Origin::signed(3);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode.clone()
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin2.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode.clone()
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin3.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode.clone()
-        ));
 
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-        assert_eq!(TemplateModule::collection(2).owner, 2);
-        assert_eq!(TemplateModule::collection(3).owner, 3);
-
         // collection admin
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 2));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 3));
 
         assert_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);
         assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);
@@ -1064,125 +714,48 @@
 #[test]
 fn balance_of() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let nft_mode: CollectionMode = CollectionMode::NFT(2000);
-        let furg_mode: CollectionMode = CollectionMode::Fungible(3);
-        let refung_mode: CollectionMode = CollectionMode::ReFungible(2000, 3);
-
-        let origin1 = Origin::signed(1);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            nft_mode.clone()
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            furg_mode.clone()
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            refung_mode.clone()
-        ));
-
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-        assert_eq!(TemplateModule::collection(2).owner, 1);
-        assert_eq!(TemplateModule::collection(3).owner, 1);
-
+        default_limits();
+        
+        let nft_collection_id = create_test_collection(&CollectionMode::NFT, 1);
+        let fungible_collection_id = create_test_collection(&CollectionMode::Fungible(3), 2);
+        let re_fungible_collection_id = create_test_collection(&CollectionMode::ReFungible(3), 3);
+        
         // check balance before
-        assert_eq!(TemplateModule::balance_count(1, 1), 0);
-        assert_eq!(TemplateModule::balance_count(2, 1), 0);
-        assert_eq!(TemplateModule::balance_count(3, 1), 0);
-
-        // create item
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 1, 1].to_vec(),
-            1
-        ));
-
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            2,
-            [].to_vec(),
-            1
-        ));
+        assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 0);
+        assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 0);
+        assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 0);
 
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            3,
-            [1, 1, 1].to_vec(),
-            1
-        ));
+        let nft_data = default_nft_data();
+        create_test_item(nft_collection_id, &nft_data.into());
+        
+        let fungible_data = default_fungible_data();
+        create_test_item(fungible_collection_id, &fungible_data.into());
+        
+        let re_fungible_data = default_re_fungible_data();
+        create_test_item(re_fungible_collection_id, &re_fungible_data.into());
 
         // check balance (collection with id = 1, user id = 1)
-        assert_eq!(TemplateModule::balance_count(1, 1), 1);
-        assert_eq!(TemplateModule::balance_count(2, 1), 1000);
-        assert_eq!(TemplateModule::balance_count(3, 1), 1000);
-        assert_eq!(TemplateModule::nft_item_id(1, 1).owner, 1);
-        assert_eq!(TemplateModule::fungible_item_id(2, 1).owner, 1);
-        assert_eq!(TemplateModule::refungible_item_id(3, 1).owner[0].owner, 1);
+        assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 1);
+        assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 1000);
+        assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 1000);
+        assert_eq!(TemplateModule::nft_item_id(nft_collection_id, 1).owner, 1);
+        assert_eq!(TemplateModule::fungible_item_id(fungible_collection_id, 1).owner, 1);
+        assert_eq!(TemplateModule::refungible_item_id(re_fungible_collection_id, 1).owner[0].owner, 1);
     });
 }
 
 #[test]
 fn approve() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let nft_mode: CollectionMode = CollectionMode::NFT(2000);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
+        
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
+
         let origin1 = Origin::signed(1);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            nft_mode.clone()
-        ));
-
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-
-        // create item
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 1, 1].to_vec(),
-            1
-        ));
-
+        
         // approve
         assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
         assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);
@@ -1192,41 +765,15 @@
 #[test]
 fn transfer_from() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
 
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
 
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-
-        // create item
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 1, 1].to_vec(),
-            1
-        ));
-
         // approve
         assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
         assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);
@@ -1268,99 +815,41 @@
 #[test]
 fn owner_can_add_address_to_white_list() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
+
         let origin1 = Origin::signed(1);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
-        assert_eq!(TemplateModule::white_list(1)[0], 2);
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_eq!(TemplateModule::white_list(collection_id)[0], 2);
     });
 }
 
 #[test]
 fn admin_can_add_address_to_white_list() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
 
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::add_to_white_list(origin2.clone(), 1, 3));
-        assert_eq!(TemplateModule::white_list(1)[0], 3);
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3));
+        assert_eq!(TemplateModule::white_list(collection_id)[0], 3);
     });
 }
 
 #[test]
 fn nonprivileged_user_cannot_add_address_to_white_list() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-        let origin1 = Origin::signed(1);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
+
         let origin2 = Origin::signed(2);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-
         assert_noop!(
-            TemplateModule::add_to_white_list(origin2.clone(), 1, 3),
+            TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3),
             "You do not have permissions to modify this collection"
         );
     });
@@ -1369,17 +858,9 @@
 #[test]
 fn nobody_can_add_address_to_white_list_of_nonexisting_collection() {
     new_test_ext().execute_with(|| {
+        default_limits();
+
         let origin1 = Origin::signed(1);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
 
         assert_noop!(
             TemplateModule::add_to_white_list(origin1.clone(), 1, 2),
@@ -1391,33 +872,14 @@
 #[test]
 fn nobody_can_add_address_to_white_list_of_deleted_collection() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-        let origin1 = Origin::signed(1);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
-        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));
+        let origin1 = Origin::signed(1);
+        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));
         assert_noop!(
-            TemplateModule::add_to_white_list(origin1.clone(), 1, 2),
+            TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2),
             "This collection does not exist"
         );
     });
@@ -1427,165 +889,80 @@
 #[test]
 fn address_is_already_added_to_white_list() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
         let origin1 = Origin::signed(1);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
-        assert_eq!(TemplateModule::white_list(1)[0], 2);
-        assert_eq!(TemplateModule::white_list(1).len(), 1);
+        
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_eq!(TemplateModule::white_list(collection_id)[0], 2);
+        assert_eq!(TemplateModule::white_list(collection_id).len(), 1);
     });
 }
 
 #[test]
 fn owner_can_remove_address_from_white_list() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-        let origin1 = Origin::signed(1);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        let origin1 = Origin::signed(1);
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
         assert_ok!(TemplateModule::remove_from_white_list(
             origin1.clone(),
-            1,
+            collection_id,
             2
         ));
-        assert_eq!(TemplateModule::white_list(1).len(), 0);
+        assert_eq!(TemplateModule::white_list(collection_id).len(), 0);
     });
 }
 
 #[test]
 fn admin_can_remove_address_from_white_list() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
 
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
 
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
-
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 3));
         assert_ok!(TemplateModule::remove_from_white_list(
             origin2.clone(),
-            1,
+            collection_id,
             3
         ));
-        assert_eq!(TemplateModule::white_list(1).len(), 0);
+        assert_eq!(TemplateModule::white_list(collection_id).len(), 0);
     });
 }
 
 #[test]
 fn nonprivileged_user_cannot_remove_address_from_white_list() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
 
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
         assert_noop!(
-            TemplateModule::remove_from_white_list(origin2.clone(), 1, 2),
+            TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),
             "You do not have permissions to modify this collection"
         );
-        assert_eq!(TemplateModule::white_list(1)[0], 2);
+        assert_eq!(TemplateModule::white_list(collection_id)[0], 2);
     });
 }
 
 #[test]
 fn nobody_can_remove_address_from_white_list_of_nonexisting_collection() {
     new_test_ext().execute_with(|| {
+        default_limits();
         let origin1 = Origin::signed(1);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
 
         assert_noop!(
             TemplateModule::remove_from_white_list(origin1.clone(), 1, 2),
@@ -1597,38 +974,19 @@
 #[test]
 fn nobody_can_remove_address_from_white_list_of_deleted_collection() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
 
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));
         assert_noop!(
-            TemplateModule::remove_from_white_list(origin2.clone(), 1, 2),
+            TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),
             "This collection does not exist"
         );
-        assert_eq!(TemplateModule::white_list(1).len(), 0);
+        assert_eq!(TemplateModule::white_list(collection_id).len(), 0);
     });
 }
 
@@ -1636,42 +994,23 @@
 #[test]
 fn address_is_already_removed_from_white_list() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
         let origin1 = Origin::signed(1);
 
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
         assert_ok!(TemplateModule::remove_from_white_list(
             origin1.clone(),
-            1,
+            collection_id,
             2
         ));
         assert_ok!(TemplateModule::remove_from_white_list(
             origin1.clone(),
-            1,
+            collection_id,
             2
         ));
-        assert_eq!(TemplateModule::white_list(1).len(), 0);
+        assert_eq!(TemplateModule::white_list(collection_id).len(), 0);
     });
 }
 
@@ -1679,44 +1018,21 @@
 #[test]
 fn white_list_test_1() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
+        
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
 
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
-
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
 
         assert_noop!(
             TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),
@@ -1728,41 +1044,17 @@
 #[test]
 fn white_list_test_2() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
+        
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
         assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
@@ -1789,41 +1081,18 @@
 #[test]
 fn white_list_test_3() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
+        
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
         assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
@@ -1838,45 +1107,22 @@
 #[test]
 fn white_list_test_4() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
 
         // do approve
         assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));
@@ -1884,7 +1130,7 @@
 
         assert_ok!(TemplateModule::remove_from_white_list(
             origin1.clone(),
-            1,
+            collection_id,
             2
         ));
 
@@ -1899,41 +1145,18 @@
 #[test]
 fn white_list_test_5() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
         assert_noop!(
@@ -1947,32 +1170,14 @@
 #[test]
 fn white_list_test_6() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
 
@@ -1989,45 +1194,22 @@
 #[test]
 fn white_list_test_7() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
+        
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
 
         assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1));
     });
@@ -2036,45 +1218,22 @@
 #[test]
 fn white_list_test_8() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
+        
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
 
         // do approve
         assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));
@@ -2095,47 +1254,24 @@
 #[test]
 fn white_list_test_9() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
         assert_ok!(TemplateModule::set_mint_permission(
             origin1.clone(),
-            1,
+            collection_id,
             false
         ));
 
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
     });
 }
 
@@ -2143,49 +1279,31 @@
 #[test]
 fn white_list_test_10() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
         assert_ok!(TemplateModule::set_mint_permission(
             origin1.clone(),
-            1,
+            collection_id,
             false
         ));
 
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
 
         assert_ok!(TemplateModule::create_item(
             origin2.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            2
+            collection_id,
+            2,
+            default_nft_data().into()
         ));
     });
 }
@@ -2194,46 +1312,28 @@
 #[test]
 fn white_list_test_11() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
         assert_ok!(TemplateModule::set_mint_permission(
             origin1.clone(),
-            1,
+            collection_id,
             false
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
 
         assert_noop!(
-            TemplateModule::create_item(origin2.clone(), 1, [1, 2, 3].to_vec(), 2),
-            "Public minting is not allowed for this collection"
+            TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),
+            "Public minting is not allowed for this collection."
         );
     });
 }
@@ -2242,45 +1342,27 @@
 #[test]
 fn white_list_test_12() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
         assert_ok!(TemplateModule::set_mint_permission(
             origin1.clone(),
-            1,
+            collection_id,
             false
         ));
 
         assert_noop!(
-            TemplateModule::create_item(origin2.clone(), 1, [1, 2, 3].to_vec(), 2),
-            "Public minting is not allowed for this collection"
+            TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),
+            "Public minting is not allowed for this collection."
         );
     });
 }
@@ -2289,47 +1371,25 @@
 #[test]
 fn white_list_test_13() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
         assert_ok!(TemplateModule::set_mint_permission(
             origin1.clone(),
-            1,
+            collection_id,
             true
         ));
 
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.into());
     });
 }
 
@@ -2337,49 +1397,31 @@
 #[test]
 fn white_list_test_14() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
         assert_ok!(TemplateModule::set_mint_permission(
             origin1.clone(),
-            1,
+            collection_id,
             true
         ));
 
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
 
         assert_ok!(TemplateModule::create_item(
             origin2.clone(),
             1,
-            [1, 2, 3].to_vec(),
-            2
+            2,
+            default_nft_data().into()
         ));
     });
 }
@@ -2388,44 +1430,26 @@
 #[test]
 fn white_list_test_15() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
         assert_ok!(TemplateModule::set_mint_permission(
             origin1.clone(),
-            1,
+            collection_id,
             true
         ));
 
         assert_noop!(
-            TemplateModule::create_item(origin2.clone(), 1, [1, 2, 3].to_vec(), 2),
+            TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),
             "Address is not in white list"
         );
     });
@@ -2435,48 +1459,30 @@
 #[test]
 fn white_list_test_16() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
 
         assert_ok!(TemplateModule::set_public_access_mode(
             origin1.clone(),
-            1,
+            collection_id,
             AccessMode::WhiteList
         ));
         assert_ok!(TemplateModule::set_mint_permission(
             origin1.clone(),
-            1,
+            collection_id,
             true
         ));
-        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));
 
         assert_ok!(TemplateModule::create_item(
             origin2.clone(),
             1,
-            [1, 2, 3].to_vec(),
-            2
+            2,
+            default_nft_data().into()
         ));
     });
 }
@@ -2485,29 +1491,9 @@
 #[test]
 fn total_number_collections_bound() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
-
-        let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
+        default_limits();
+        
+        create_test_collection(&CollectionMode::NFT, 1);
     });
 }
 
@@ -2515,41 +1501,25 @@
 #[test]
 fn total_number_collections_bound_neg() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
 
         let origin1 = Origin::signed(1);
-
-        for _ in 0..10 {
 
-            assert_ok!(TemplateModule::create_collection(
-                origin1.clone(),
-                col_name1.clone(),
-                col_desc1.clone(),
-                token_prefix1.clone(),
-                mode.clone()
-            ));
+        for i in 0..default_collection_numbers_limit() {
+            create_test_collection(&CollectionMode::NFT, i + 1);
         }
 
+        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+
         // 11-th collection in chain. Expects error
         assert_noop!(TemplateModule::create_collection(
             origin1.clone(),
             col_name1.clone(),
             col_desc1.clone(),
             token_prefix1.clone(),
-            mode.clone()
+            CollectionMode::NFT
         ), "Total collections bound exceeded");
     });
 }
@@ -2558,43 +1528,13 @@
 #[test]
 fn owned_tokens_bound() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
-        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
-            collection_numbers_limit: 10,
-            account_token_ownership_limit: 10,
-            collections_admins_limit: 5,
-            custom_data_limit: 2048,
-            nft_sponsor_transfer_timeout: 15,
-            fungible_sponsor_transfer_timeout: 15,
-            refungible_sponsor_transfer_timeout: 15,          
-        }));
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
-        let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
-
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.clone().into());
+        create_test_item(collection_id, &data.into());
     });
 }
 
@@ -2602,11 +1542,6 @@
 #[test]
 fn owned_tokens_bound_neg() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
         assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
             collection_numbers_limit: 10,
             account_token_ownership_limit: 1,
@@ -2616,28 +1551,18 @@
             fungible_sponsor_transfer_timeout: 15,
             refungible_sponsor_transfer_timeout: 15,          
         }));
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec(),
-            1
-        ));
+        let data = default_nft_data();
+        create_test_item(collection_id, &data.clone().into());
 
         assert_noop!(TemplateModule::create_item(
             origin1.clone(),
             1,
-            [1, 2, 3].to_vec(),
-            1
+            1,
+            data.into()
         ), "Owned tokens by a single address bound exceeded");
     });
 }
@@ -2646,11 +1571,6 @@
 #[test]
 fn collection_admins_bound() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
         assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
             collection_numbers_limit: 10,
             account_token_ownership_limit: 10,
@@ -2660,18 +1580,13 @@
             fungible_sponsor_transfer_timeout: 15,
             refungible_sponsor_transfer_timeout: 15,          
         }));
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
-
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3));
+        
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3));
     });
 }
 
@@ -2679,11 +1594,6 @@
 #[test]
 fn collection_admins_bound_neg() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
-
         assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
             collection_numbers_limit: 10,
             account_token_ownership_limit: 1,
@@ -2693,78 +1603,167 @@
             fungible_sponsor_transfer_timeout: 15,
             refungible_sponsor_transfer_timeout: 15,          
         }));
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
 
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
-        assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3), "Number of collection admins bound exceeded");
+        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));
+        assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3), "Number of collection admins bound exceeded");
     });
 }
 
-// Custom data size. Positive test
+// NFT custom data size. Negative test const_data.
 #[test]
-fn custom_data_size_bound() {
+fn custom_data_size_nft_const_data_bound_neg() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
+            collection_numbers_limit: 10,
+            account_token_ownership_limit: 10,
+            collections_admins_limit: 5,
+            custom_data_limit: 2,
+            nft_sponsor_transfer_timeout: 15,
+            fungible_sponsor_transfer_timeout: 15,
+            refungible_sponsor_transfer_timeout: 15,          
+        }));
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
+        let origin1 = Origin::signed(1);
+        let too_big_const_data = CreateItemData::NFT(CreateNftData{
+            const_data: vec![1, 2, 3, 4],
+            variable_data: vec![]
+        });
+
+        assert_noop!(TemplateModule::create_item(
+            origin1.clone(),
+            collection_id,
+            1,
+            too_big_const_data
+        ), "const_data exceeded data limit.");
+    });
+}
+
+// NFT custom data size. Negative test variable_data.
+#[test]
+fn custom_data_size_nft_variable_data_bound_neg() {
+    new_test_ext().execute_with(|| {
         assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
             collection_numbers_limit: 10,
             account_token_ownership_limit: 10,
             collections_admins_limit: 5,
-            custom_data_limit: 2048,
+            custom_data_limit: 2,
             nft_sponsor_transfer_timeout: 15,
             fungible_sponsor_transfer_timeout: 15,
             refungible_sponsor_transfer_timeout: 15,          
         }));
 
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
+
         let origin1 = Origin::signed(1);
-        assert_ok!(TemplateModule::create_collection(
+        let too_big_const_data = CreateItemData::NFT(CreateNftData{
+            const_data: vec![],
+            variable_data: vec![1, 2, 3, 4]
+        });
+
+        assert_noop!(TemplateModule::create_item(
             origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ));
+            collection_id,
+            1,
+            too_big_const_data
+        ), "variable_data exceeded data limit.");
     });
 }
 
-// Custom data size. Negotive test
+// Re fungible custom data size. Negative test const_data.
 #[test]
-fn custom_data_size_bound_neg() {
+fn custom_data_size_re_fungible_const_data_bound_neg() {
     new_test_ext().execute_with(|| {
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-        let mode: CollectionMode = CollectionMode::NFT(2000);
+        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
+            collection_numbers_limit: 10,
+            account_token_ownership_limit: 10,
+            collections_admins_limit: 5,
+            custom_data_limit: 2,
+            nft_sponsor_transfer_timeout: 15,
+            fungible_sponsor_transfer_timeout: 15,
+            refungible_sponsor_transfer_timeout: 15,          
+        }));
+
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
 
+        let origin1 = Origin::signed(1);
+        let too_big_const_data = CreateItemData::NFT(CreateNftData{
+            const_data: vec![1, 2, 3, 4],
+            variable_data: vec![]
+        });
+
+        assert_noop!(TemplateModule::create_item(
+            origin1.clone(),
+            collection_id,
+            1,
+            too_big_const_data
+        ), "const_data exceeded data limit.");
+    });
+}
+
+// Re fungible custom data size. Negative test variable_data.
+#[test]
+fn custom_data_size_re_fungible_variable_data_bound_neg() {
+    new_test_ext().execute_with(|| {
         assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
             collection_numbers_limit: 10,
             account_token_ownership_limit: 10,
             collections_admins_limit: 5,
-            custom_data_limit: 200,
+            custom_data_limit: 2,
             nft_sponsor_transfer_timeout: 15,
             fungible_sponsor_transfer_timeout: 15,
             refungible_sponsor_transfer_timeout: 15,          
         }));
 
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
+
         let origin1 = Origin::signed(1);
-        assert_noop!(TemplateModule::create_collection(
+        let too_big_const_data = CreateItemData::NFT(CreateNftData{
+            const_data: vec![],
+            variable_data: vec![1, 2, 3, 4]
+        });
+
+        assert_noop!(TemplateModule::create_item(
             origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            mode
-        ), "Custom data size bound exceeded");
+            collection_id,
+            1,
+            too_big_const_data
+        ), "variable_data exceeded data limit.");
     });
 }
 // #endregion
+
+#[test]
+fn set_const_on_chain_schema() {
+    new_test_ext().execute_with(|| {
+        default_limits();
+
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
+
+        let origin1 = Origin::signed(1);
+        assert_ok!(TemplateModule::set_const_on_chain_schema(origin1, collection_id, b"test const on chain schema".to_vec()));
+
+        assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, b"test const on chain schema".to_vec());
+        assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, b"".to_vec());
+    });
+}
+
+#[test]
+fn set_variable_on_chain_schema() {
+    new_test_ext().execute_with(|| {
+        default_limits();
+        
+        let collection_id = create_test_collection(&CollectionMode::NFT, 1);
+
+        let origin1 = Origin::signed(1);
+        assert_ok!(TemplateModule::set_variable_on_chain_schema(origin1, collection_id, b"test variable on chain schema".to_vec()));
+
+        assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, b"".to_vec());
+        assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, b"test variable on chain schema".to_vec());
+    });
+}
\ No newline at end of file
modifiedruntime/src/nft_weights.rsdiffbeforeafterboth
--- a/runtime/src/nft_weights.rs
+++ b/runtime/src/nft_weights.rs
@@ -93,4 +93,19 @@
             .saturating_add(DbWeight::get().reads(2 as Weight))
             .saturating_add(DbWeight::get().writes(1 as Weight))
     }
+    fn set_const_on_chain_schema() -> Weight {
+        (11_100_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(1 as Weight))
+    }
+    fn set_variable_on_chain_schema() -> Weight {
+        (11_100_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(1 as Weight))
+    }
+    fn set_variable_meta_data() -> Weight {
+        (17_500_000 as Weight)
+            .saturating_add(DbWeight::get().reads(2 as Weight))
+            .saturating_add(DbWeight::get().writes(1 as Weight))
+    }
 }