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

difftreelog

funfible item added

str-mv2020-08-06parent: #a55594d.patch.diff
in: master

3 files changed

modifiedREADME.mddiffbeforeafterboth
before · README.md
1![Docker build](https://github.com/usetech-llc/nft_parachain/workflows/Docker%20build/badge.svg)23# NFT Parachain45## Application Development67If you are building an application that operates NFT tokens, use [this document](doc/application_development.md).89## Building1011Building NFT chain requires special versions of Rust and toolchain. We don't use the most recent versions of everything so that we can keep the builds stable.12131. Install Rust:1415```bash16curl https://sh.rustup.rs -sSf | sh17sudo apt-get install libssl-dev pkg-config libclang-dev clang18```19202. Remove all installed toolchains with `rustup toolchain list` and `rustup toolchain uninstall <toolchain>`.21223. Install Rust Toolchain 1.44.0:2324```bash25rustup install 1.44.026```27284. Make it default (actual toochain version may be different, so do a `rustup toolchain list` first)29```bash30rustup toolchain list31rustup default 1.44.0-x86_64-unknown-linux-gnu32```33345. Install nightly toolchain and add wasm target for it:3536```bash37rustup toolchain install nightly-2020-05-0138rustup target add wasm32-unknown-unknown --toolchain nightly-2020-05-01-x86_64-unknown-linux-gnu39```40416. Build:42```bash43cargo build44```4546## Run4748You can start a development chain with:4950```bash51cargo run -- --dev52```5354Detailed logs may be shown by running the node with the following environment variables set: `RUST_LOG=debug RUST_BACKTRACE=1 cargo run -- --dev`.5556If you want to see the multi-node consensus algorithm in action locally, then you can create a local testnet with two validator nodes for Alice and Bob, who are the initial authorities of the genesis chain that have been endowed with testnet units. Give each node a name and expose them so they are listed on the Polkadot [telemetry site](https://telemetry.polkadot.io/#/Local%20Testnet). You'll need two terminal windows open.5758We'll start Alice's substrate node first on default TCP port 30333 with her chain database stored locally at `/tmp/alice`. The bootnode ID of her node is `QmQZ8TjTqeDj3ciwr93EJ95hxfDsb9pEYDizUAbWpigtQN`, which is generated from the `--node-key` value that we specify below:5960```bash61cargo run -- \62  --base-path /tmp/alice \63  --chain=local \64  --alice \65  --node-key 0000000000000000000000000000000000000000000000000000000000000001 \66  --telemetry-url ws://telemetry.polkadot.io:1024 \67  --validator68```6970In the second terminal, we'll start Bob's substrate node on a different TCP port of 30334, and with his chain database stored locally at `/tmp/bob`. We'll specify a value for the `--bootnodes` option that will connect his node to Alice's bootnode ID on TCP port 30333:7172```bash73cargo run -- \74  --base-path /tmp/bob \75  --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/QmQZ8TjTqeDj3ciwr93EJ95hxfDsb9pEYDizUAbWpigtQN \76  --chain=local \77  --bob \78  --port 30334 \79  --telemetry-url ws://telemetry.polkadot.io:1024 \80  --validator81```8283Additional CLI usage options are available and may be shown by running `cargo run -- --help`.848586## UI custom types87```88{89  "Schedule": {90    "version": "u32",91    "put_code_per_byte_cost": "Gas",92    "grow_mem_cost": "Gas",93    "regular_op_cost": "Gas",94    "return_data_per_byte_cost": "Gas",95    "event_data_per_byte_cost": "Gas",96    "event_per_topic_cost": "Gas",97    "event_base_cost": "Gas",98    "call_base_cost": "Gas",99    "instantiate_base_cost": "Gas",100    "dispatch_base_cost": "Gas",101    "sandbox_data_read_cost": "Gas",102    "sandbox_data_write_cost": "Gas",103    "transfer_cost": "Gas",104    "instantiate_cost": "Gas",105    "max_event_topics": "u32",106    "max_stack_height": "u32",107    "max_memory_pages": "u32",108    "max_table_size": "u32",109    "enable_println": "bool",110    "max_subject_len": "u32"111  },112  "CollectionMode": {113    "_enum": {114      "Invalid": null,115      "NFT": "u32",116      "Fungible": "u32",117      "ReFungible": "(u32, u32)"118    }119  },120  "NftItemType": {121    "Collection": "u64",122    "Owner": "AccountId",123    "Data": "Vec<u8>"124  },125  "CollectionType": {126    "Owner": "AccountId",127    "Mode": "CollectionMode",128    "Access": "u8",129    "DecimalPoints": "u32",130    "Name": "Vec<u16>",131    "Description": "Vec<u16>",132    "TokenPrefix": "Vec<u8>",133    "CustomDataSize": "u32",134    "OffchainSchema": "Vec<u8>",135    "Sponsor": "AccountId",136    "UnconfirmedSponsor": "AccountId"137  },138  "RawData": "Vec<u8>",139  "Address": "AccountId",140  "LookupSource": "AccountId",141  "Weight": "u64"142}143```
after · README.md
1![Docker build](https://github.com/usetech-llc/nft_parachain/workflows/Docker%20build/badge.svg)23# NFT Parachain45## Application Development67If you are building an application that operates NFT tokens, use [this document](doc/application_development.md).89## Building1011Building NFT chain requires special versions of Rust and toolchain. We don't use the most recent versions of everything so that we can keep the builds stable.12131. Install Rust:1415```bash16curl https://sh.rustup.rs -sSf | sh17sudo apt-get install libssl-dev pkg-config libclang-dev clang18```19202. Remove all installed toolchains with `rustup toolchain list` and `rustup toolchain uninstall <toolchain>`.21223. Install Rust Toolchain 1.44.0:2324```bash25rustup install 1.44.026```27284. Make it default (actual toochain version may be different, so do a `rustup toolchain list` first)29```bash30rustup toolchain list31rustup default 1.44.0-x86_64-unknown-linux-gnu32```33345. Install nightly toolchain and add wasm target for it:3536```bash37rustup toolchain install nightly-2020-05-0138rustup target add wasm32-unknown-unknown --toolchain nightly-2020-05-01-x86_64-unknown-linux-gnu39```40416. Build:42```bash43cargo build44```4546## Run4748You can start a development chain with:4950```bash51cargo run -- --dev52```5354Detailed logs may be shown by running the node with the following environment variables set: `RUST_LOG=debug RUST_BACKTRACE=1 cargo run -- --dev`.5556If you want to see the multi-node consensus algorithm in action locally, then you can create a local testnet with two validator nodes for Alice and Bob, who are the initial authorities of the genesis chain that have been endowed with testnet units. Give each node a name and expose them so they are listed on the Polkadot [telemetry site](https://telemetry.polkadot.io/#/Local%20Testnet). You'll need two terminal windows open.5758We'll start Alice's substrate node first on default TCP port 30333 with her chain database stored locally at `/tmp/alice`. The bootnode ID of her node is `QmQZ8TjTqeDj3ciwr93EJ95hxfDsb9pEYDizUAbWpigtQN`, which is generated from the `--node-key` value that we specify below:5960```bash61cargo run -- \62  --base-path /tmp/alice \63  --chain=local \64  --alice \65  --node-key 0000000000000000000000000000000000000000000000000000000000000001 \66  --telemetry-url ws://telemetry.polkadot.io:1024 \67  --validator68```6970In the second terminal, we'll start Bob's substrate node on a different TCP port of 30334, and with his chain database stored locally at `/tmp/bob`. We'll specify a value for the `--bootnodes` option that will connect his node to Alice's bootnode ID on TCP port 30333:7172```bash73cargo run -- \74  --base-path /tmp/bob \75  --bootnodes /ip4/127.0.0.1/tcp/30333/p2p/QmQZ8TjTqeDj3ciwr93EJ95hxfDsb9pEYDizUAbWpigtQN \76  --chain=local \77  --bob \78  --port 30334 \79  --telemetry-url ws://telemetry.polkadot.io:1024 \80  --validator81```8283Additional CLI usage options are available and may be shown by running `cargo run -- --help`.848586## UI custom types87```88{89  "Schedule": {90    "version": "u32",91    "put_code_per_byte_cost": "Gas",92    "grow_mem_cost": "Gas",93    "regular_op_cost": "Gas",94    "return_data_per_byte_cost": "Gas",95    "event_data_per_byte_cost": "Gas",96    "event_per_topic_cost": "Gas",97    "event_base_cost": "Gas",98    "call_base_cost": "Gas",99    "instantiate_base_cost": "Gas",100    "dispatch_base_cost": "Gas",101    "sandbox_data_read_cost": "Gas",102    "sandbox_data_write_cost": "Gas",103    "transfer_cost": "Gas",104    "instantiate_cost": "Gas",105    "max_event_topics": "u32",106    "max_stack_height": "u32",107    "max_memory_pages": "u32",108    "max_table_size": "u32",109    "enable_println": "bool",110    "max_subject_len": "u32"111  },112  "CollectionMode": {113    "_enum": {114      "Invalid": null,115      "NFT": "u32",116      "Fungible": "u32",117      "ReFungible": "(u32, u32)"118    }119  },120  "Ownership": {121    "Owner": "AccountId",122    "Fraction": "u128"123  },124  "FungibleItemType": {125    "Collection": "u64",126    "Owner": "AccountId",127    "Value": "u128"128  },129  "ReFungibleItemType": {130    "Collection": "u64",131    "Owner": "Vec<Ownership>",132    "Data": "Vec<u8>"133  },134  "NftItemType": {135    "Collection": "u64",136    "Owner": "AccountId",137    "Data": "Vec<u8>"138  },139  "CollectionType": {140    "Owner": "AccountId",141    "Mode": "CollectionMode",142    "Access": "u8",143    "DecimalPoints": "u32",144    "Name": "Vec<u16>",145    "Description": "Vec<u16>",146    "TokenPrefix": "Vec<u8>",147    "CustomDataSize": "u32",148    "OffchainSchema": "Vec<u8>",149    "Sponsor": "AccountId",150    "UnconfirmedSponsor": "AccountId"151  },152  "RawData": "Vec<u8>",153  "Address": "AccountId",154  "LookupSource": "AccountId",155  "Weight": "u64"156}157```
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -122,6 +122,13 @@
     pub data: Vec<u8>,
 }
 
+#[derive(Encode, Decode, Default, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Debug))]
+pub struct ApprovePermissions<AccountId> {
+    pub approved: AccountId,
+    pub amount: u64
+}
+
 pub trait Trait: system::Trait {
     type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
 
@@ -138,11 +145,13 @@
         pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;
         pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;
 
-        // Balance owner per collection map
+        /// Balance owner per collection map
         pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;
-        pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => Vec<T::AccountId>;
 
-        // Item collections
+        /// second parameter: item id + owner account id
+        pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;
+
+        /// Item collections
         pub NftItemList get(fn nft_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;
         pub FungibleItemList get(fn fungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;
         pub ReFungibleItemList get(fn refungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;
@@ -248,6 +257,7 @@
             let sender = ensure_signed(origin)?;
             Self::check_owner_permissions(collection_id, sender)?;
 
+            // TODO Items remove
             <AddressTokens<T>>::remove_prefix(collection_id);
             <ApprovedList<T>>::remove_prefix(collection_id);
             <Balance<T>>::remove_prefix(collection_id);
@@ -356,18 +366,18 @@
         pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-
-            // check size
             let target_collection = <Collection<T>>::get(collection_id);
-            ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");
-
             Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
 
             // TODO: implement other modes
             match target_collection.mode 
             {
                 CollectionMode::NFT(_) => {
-                // Create nft item
+
+                    // check size
+                    ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");
+
+                    // Create nft item
                     let item = NftItemType {
                         collection: collection_id,
                         owner: owner,
@@ -377,7 +387,24 @@
                     Self::add_nft_item(item)?;
     
                 },
+                CollectionMode::Fungible(_) => {
+
+                    // check size
+                    ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type");
+
+                    let item = FungibleItemType {
+                        collection: collection_id,
+                        owner: owner,
+                        value: (10 as u128).pow(target_collection.decimal_points)
+                    };
+    
+                    Self::add_fungible_item(item)?;
+                },
                 CollectionMode::ReFungible(_, _) => {
+
+                    // check size
+                    ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");
+
                     let mut owner_list = Vec::new();
                     let value = (10 as u128).pow(target_collection.decimal_points);
                     owner_list.push(Ownership {owner: owner, fraction: value});
@@ -413,6 +440,7 @@
             match target_collection.mode 
             {
                 CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,
+                CollectionMode::Fungible(_)  => Self::burn_fungible_item(collection_id, item_id)?,
                 CollectionMode::ReFungible(_, _)  => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,
                 _ => ()
             };
@@ -435,6 +463,7 @@
             match target_collection.mode 
             {
                 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,
+                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,
                 CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,
                 _ => ()
             };
@@ -447,26 +476,26 @@
 
             let sender = ensure_signed(origin)?;
 
-            let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);
-            if !item_owner
-            {
-                Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
-            }
+            // amount param stub
+            let amount = 100000000;
 
-            let list_exists = <ApprovedList<T>>::contains_key(collection_id, item_id);
+            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id), "Only item owner can call transfer method");
+
+            let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));
             if list_exists {
 
-                let mut list = <ApprovedList<T>>::get(collection_id, item_id);
-                let item_contains = list.contains(&approved.clone());
+                let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));
+                let item_contains = list.iter().any(|i| i.approved == approved);
 
                 if !item_contains {
-                    list.push(approved.clone());
+                    list.push(ApprovePermissions { approved: approved.clone(), amount: amount });
+                    <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);
                 }
             } else {
 
-                let mut itm = Vec::new();
-                itm.push(approved.clone());
-                <ApprovedList<T>>::insert(collection_id, item_id, itm);
+                let mut list = Vec::new();
+                list.push(ApprovePermissions { approved: approved.clone(), amount: amount });
+                <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);
             }
 
             Ok(())
@@ -475,16 +504,21 @@
         #[weight = 0]
         pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {
 
-            let mut approved: bool = false; 
             let sender = ensure_signed(origin)?;
-            let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, item_id);
+            let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone()));
             if approved_list_exists
             {
-                let list_itm = <ApprovedList<T>>::get(collection_id, item_id);
-                approved = list_itm.contains(&recipient.clone());
-            }
+                let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));
+                let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());
+                ensure!(opt_item.is_some(), "No approve found"); 
+                ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved"); 
 
-            if !approved
+                // remove approve
+                let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))
+                    .into_iter().filter(|i| i.approved != sender.clone()).collect();
+                <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);
+            }
+            else
             {
                 Self::check_owner_or_admin_permissions(collection_id, sender)?;
             }
@@ -494,8 +528,8 @@
             match target_collection.mode
             {
                 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,
-                CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, from, recipient)?,
-                // TODO: implement other modes
+                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,
+                CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,
                 _ => ()
             };
 
@@ -537,6 +571,121 @@
 
 impl<T: Trait> Module<T> {
 
+    fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {
+
+        let current_index = <ItemListIndex>::get(item.collection)
+        .checked_add(1)
+        .expect("Item list index id error");
+        let itemcopy = item.clone();
+        let owner = item.owner.clone();
+        let value = item.value as u64;
+
+        Self::add_token_index(item.collection, current_index, owner.clone())?;
+
+        <ItemListIndex>::insert(item.collection, current_index);
+        <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);  
+        
+        // Update balance
+       let new_balance = <Balance<T>>::get(item.collection, owner.clone()).checked_add(value).unwrap();
+       <Balance<T>>::insert(item.collection, owner.clone(), new_balance);
+
+        Ok(())
+    }
+
+    fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {
+
+        let current_index = <ItemListIndex>::get(item.collection)
+        .checked_add(1)
+        .expect("Item list index id error");
+        let itemcopy = item.clone();
+
+        let value = item.owner.first().unwrap().fraction as u64;
+        let owner = item.owner.first().unwrap().owner.clone();
+
+        Self::add_token_index(item.collection, current_index, owner.clone())?;
+
+        <ItemListIndex>::insert(item.collection, current_index);
+        <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);  
+        
+        // Update balance
+       let new_balance = <Balance<T>>::get(item.collection, owner.clone()).checked_add(value).unwrap();
+       <Balance<T>>::insert(item.collection, owner.clone(), new_balance);
+
+        Ok(())
+    }
+
+    fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {
+
+        let current_index = <ItemListIndex>::get(item.collection)
+        .checked_add(1)
+        .expect("Item list index id error");
+
+        let item_owner = item.owner.clone();
+        let collection_id = item.collection.clone();
+        Self::add_token_index(collection_id, current_index, item.owner.clone())?;
+
+        <ItemListIndex>::insert(collection_id, current_index);
+        <NftItemList<T>>::insert(collection_id, current_index, item);
+
+        // Update balance
+        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone()).checked_add(1).unwrap();
+        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);
+
+        Ok(())
+    }
+
+    fn burn_refungible_item(collection_id: u64, item_id: u64, owner: T::AccountId) -> DispatchResult {
+  
+        let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);
+        let item = collection.owner.iter().filter(|&i| i.owner == owner).next().unwrap();
+        Self::remove_token_index(collection_id, item_id, owner.clone())?;
+
+        // remove approve list
+        <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));
+
+        // update balance
+        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(item.fraction as u64).unwrap();
+        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);
+
+
+        <ReFungibleItemList<T>>::remove(collection_id, item_id);
+
+        Ok(())
+    }
+
+    fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {
+  
+        let item = <NftItemList<T>>::get(collection_id, item_id);
+        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;
+
+        // remove approve list
+        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));
+
+        // update balance
+        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(1).unwrap();
+        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);
+        <NftItemList<T>>::remove(collection_id, item_id);
+
+        Ok(())
+    }
+
+    fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {
+  
+        let item = <FungibleItemList<T>>::get(collection_id, item_id);
+        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;
+
+        // remove approve list
+        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));
+
+        // update balance
+        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(item.value as u64).unwrap();
+        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);
+
+        <FungibleItemList<T>>::remove(collection_id, item_id);
+
+        Ok(())        
+    }
+
     fn collection_exists(collection_id: u64) -> DispatchResult{
         ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");
         Ok(())
@@ -582,50 +731,90 @@
         }
     }
 
-    fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {
+    fn transfer_fungible(collection_id: u64, item_id: u64, value: u64, owner: T::AccountId, new_owner: T::AccountId) -> DispatchResult {
+        let full_item = <FungibleItemList<T>>::get(collection_id, item_id);
+        let amount = full_item.value;
+
+        ensure!(amount >= value.into(),"Item balance not enouth");
+
+        // update balance
+        let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone()).checked_sub(value).unwrap();
+        <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);
+
+        let mut new_owner_account_id = 0;
+        let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());
+        if new_owner_items.len() > 0 {
+            new_owner_account_id = new_owner_items[0];
+        }
+
+        let val64 = value.into();
 
-        let current_index = <ItemListIndex>::get(item.collection)
-        .checked_add(1)
-        .expect("Item list index id error");
+        // transfer
+        if amount == val64 && new_owner_account_id == 0
+        {
+            // change owner
+            // new owner do not have account
+            let mut new_full_item = full_item.clone();
+            new_full_item.owner = new_owner.clone();
+            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);
 
-        let value = item.owner.first().unwrap().fraction as u64;
-        let owner = item.owner.first().unwrap().owner.clone();
+            // update balance
+            let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone()).checked_add(value).unwrap();
+            <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);
 
-        Self::add_token_index(item.collection, current_index, owner.clone())?;
+            // update index collection
+            Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;
+        }
+        else
+        {
+            let mut new_full_item = full_item.clone();
+            new_full_item.value -= val64;
 
-        <ItemListIndex>::insert(item.collection, current_index);
-        <ReFungibleItemList<T>>::insert(item.collection, current_index, item);  
-        
-        // Update balance
-        let new_balance = <Balance<T>>::get(item.collection, owner.clone()).checked_add(value).unwrap();
-        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);
+            // separate amount
+            if new_owner_account_id > 0 {
+
+                // new owner has account
+                let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);
+                item.value += val64;
+
+                // update balance
+                let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone()).checked_add(value).unwrap();
+                <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);
 
-        Ok(())
-    }
+                <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);
+            }
+            else
+            {
+                // new owner do not have account
+                let item = FungibleItemType {
+                    collection: collection_id,
+                    owner: new_owner.clone(),
+                    value: val64
+                };
 
-    fn burn_refungible_item(collection_id: u64, item_id: u64, owner: T::AccountId) -> DispatchResult {
-  
-        let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);
-        let item = collection.owner.iter().filter(|&i| i.owner == owner).next().unwrap();
-        Self::remove_token_index(collection_id, item_id, owner)?;
+                Self::add_fungible_item(item)?;
+            }
 
-        // update balance
-        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(item.fraction as u64).unwrap();
-        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);
+            if amount == val64{
+                Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;
+        
+                // remove approve list
+                <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));
+                <FungibleItemList<T>>::remove(collection_id, item_id);
+            }
 
-        // TODO
-        <ReFungibleItemList<T>>::remove(collection_id, item_id);
+            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);
+        }
 
         Ok(())
     }
 
     fn transfer_refungible(collection_id: u64, item_id: u64, value: u64, owner: T::AccountId, new_owner: T::AccountId) -> DispatchResult {
-
         let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);
         let item = full_item.owner.iter().filter(|i| i.owner == owner).next().unwrap();
         let amount = item.fraction;
 
-        ensure!(amount < value.into(),"Item balance not enouth");
+        ensure!(amount >= value.into(),"Item balance not enouth");
 
         // update balance
         let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(value).unwrap();
@@ -636,9 +825,10 @@
 
         let old_owner = item.owner.clone();
         let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);
+        let val64 = value.into();
 
         // transfer
-        if amount == value.into() && !new_owner_has_account
+        if amount == val64 && !new_owner_has_account
         {
             // change owner
             // new owner do not have account
@@ -652,17 +842,17 @@
         else
         {
             let mut new_full_item = full_item.clone();
-            new_full_item.owner.iter_mut().find(|i| i.owner == owner).unwrap().fraction -= amount;
+            new_full_item.owner.iter_mut().find(|i| i.owner == owner).unwrap().fraction -= val64;
 
             // separate amount
             if new_owner_has_account {
                 // new owner has account
-                new_full_item.owner.iter_mut().find(|i| i.owner == new_owner).unwrap().fraction += amount;
+                new_full_item.owner.iter_mut().find(|i| i.owner == new_owner).unwrap().fraction += val64;
             }
             else
             {
                 // new owner do not have account
-                new_full_item.owner.push(Ownership { owner: new_owner.clone(), fraction: amount});
+                new_full_item.owner.push(Ownership { owner: new_owner.clone(), fraction: val64});
                 Self::add_token_index(collection_id, item_id, new_owner.clone())?;
             }
 
@@ -671,38 +861,7 @@
 
         Ok(())
     }
-    
-    fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {
-
-        let current_index = <ItemListIndex>::get(item.collection)
-        .checked_add(1)
-        .expect("Item list index id error");
-
-        Self::add_token_index(item.collection, current_index, item.owner.clone())?;
-
-        <ItemListIndex>::insert(item.collection, current_index);
-        <NftItemList<T>>::insert(item.collection, current_index, item);
 
-        // Update balance
-        let new_balance = <Balance<T>>::get(item.collection, item.owner.clone()).checked_add(1).unwrap();
-        <Balance<T>>::insert(item.collection_id, item.owner.clone(), new_balance);
-
-        Ok(())
-    }
-
-    fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {
-  
-        let item = <NftItemList<T>>::get(collection_id, item_id);
-        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;
-
-        // update balance
-        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone()).checked_sub(1).unwrap();
-        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);
-        <NftItemList<T>>::remove(collection_id, item_id);
-
-        Ok(())
-    }
-
     fn transfer_nft(collection_id: u64, item_id: u64, sender: T::AccountId, new_owner: T::AccountId) -> DispatchResult {
 
         let mut item = <NftItemList<T>>::get(collection_id, item_id);
@@ -722,12 +881,10 @@
         <NftItemList<T>>::insert(collection_id, item_id, item);
 
         // update index collection
-        Self::move_token_index(collection_id, item_id, old_owner, new_owner.clone())?;
+        Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;
 
         // reset approved list
-        let itm: Vec<T::AccountId> = Vec::new();
-        <ApprovedList<T>>::insert(collection_id, item_id, itm);
-
+        <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));
         Ok(())
     }
 
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -1,566 +1,943 @@
 // Tests to be written here
 use crate::mock::*;
+use crate::{CollectionMode, Ownership, ApprovePermissions};
 use frame_support::{assert_noop, assert_ok};
 
 #[test]
-fn create_collection_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);
 
-        let size = 1024;
         let origin1 = Origin::signed(1);
         assert_ok!(TemplateModule::create_collection(
             origin1.clone(),
             col_name1.clone(),
             col_desc1.clone(),
             token_prefix1.clone(),
-            size
+            mode
         ));
         assert_eq!(TemplateModule::collection(1).owner, 1);
-    });
-}
 
-#[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 size = 1024;
-        let origin1 = Origin::signed(1);
-
-        assert_ok!(TemplateModule::create_collection(
-            origin1.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
-        ));
-        assert_ok!(TemplateModule::change_collection_owner(
-            origin1.clone(),
-            1,
-            2
-        ));
-        assert_eq!(TemplateModule::collection(1).owner, 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());
     });
 }
 
 #[test]
-fn destroy_collection() {
+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);
 
-        let size = 1024;
         let origin1 = Origin::signed(1);
-
         assert_ok!(TemplateModule::create_collection(
             origin1.clone(),
             col_name1.clone(),
             col_desc1.clone(),
             token_prefix1.clone(),
-            size
+            mode
         ));
-        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));
+        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 });
     });
 }
 
 #[test]
-fn create_item() {
+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);
 
-        let size = 1024;
         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(),
-            size
-        ));
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::create_item(
-            origin2.clone(),
-            1,
-            [1, 1, 1].to_vec()
+            mode
         ));
+        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        // check balance (collection with id = 1, user id = 2)
-        assert_eq!(TemplateModule::balance_count((1, 2)), 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]);
     });
 }
 
 #[test]
-fn burn_item() {
+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);
 
-        let size = 1024;
         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(),
-            size
+            mode
         ));
-        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
-        assert_ok!(TemplateModule::create_item(
-            origin2.clone(),
-            1,
-            [1, 1, 1].to_vec()
-        ));
+        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        // check balance (collection with id = 1, user id = 2)
-        assert_eq!(TemplateModule::balance_count((1, 2)), 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]);
 
-        // burn item
-        assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));
-        assert_noop!(
-            TemplateModule::burn_item(origin1.clone(), 1, 1),
-            "Item does not exists"
-        );
+        // change owner scenario
+        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));
+        assert_eq!(TemplateModule::fungible_item_id(1,1).owner, 2);
+        assert_eq!(TemplateModule::fungible_item_id(1,1).value, 1000);
+        assert_eq!(TemplateModule::balance_count(1,1), 0);
+        assert_eq!(TemplateModule::balance_count(1,2), 1000);
+        assert_eq!(TemplateModule::address_tokens(1,1), []);
+        assert_eq!(TemplateModule::address_tokens(1,2), [1]);
+
+        // split item scenario
+        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 500));
+        assert_eq!(TemplateModule::fungible_item_id(1,1).owner, 2);
+        assert_eq!(TemplateModule::fungible_item_id(1,2).owner, 3);
+        assert_eq!(TemplateModule::balance_count(1,2), 500);
+        assert_eq!(TemplateModule::balance_count(1,3), 500);
+        assert_eq!(TemplateModule::address_tokens(1,2), [1]);
+        assert_eq!(TemplateModule::address_tokens(1,3), [2]);
 
-        assert_eq!(TemplateModule::balance_count((1, 1)), 0);
+        // split item and new owner has account scenario
+        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 200));
+        assert_eq!(TemplateModule::fungible_item_id(1,1).value, 300);
+        assert_eq!(TemplateModule::fungible_item_id(1,2).value, 700);
+        assert_eq!(TemplateModule::balance_count(1,2), 300);
+        assert_eq!(TemplateModule::balance_count(1,3), 700);
+        assert_eq!(TemplateModule::address_tokens(1,2), [1]);
+        assert_eq!(TemplateModule::address_tokens(1,3), [2]);
     });
 }
 
 #[test]
-fn add_collection_admin() {
+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);
 
-        let size = 1024;
         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(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin2.clone(),
             col_name1.clone(),
             col_desc1.clone(),
             token_prefix1.clone(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin3.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
+            mode
         ));
-
         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::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 });
+        assert_eq!(TemplateModule::balance_count(1,1), 1000);
+        assert_eq!(TemplateModule::address_tokens(1,1), [1]);
 
-        assert_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);
-        assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);
+        // change owner scenario
+        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));
+        assert_eq!(TemplateModule::refungible_item_id(1,1).owner[0], Ownership { owner: 2, fraction: 1000 });
+        assert_eq!(TemplateModule::balance_count(1,1), 0);
+        assert_eq!(TemplateModule::balance_count(1,2), 1000);
+        assert_eq!(TemplateModule::address_tokens(1,1), []);
+        assert_eq!(TemplateModule::address_tokens(1,2), [1]);
+
+        // split item scenario
+        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 500));
+        assert_eq!(TemplateModule::refungible_item_id(1,1).owner[0], Ownership { owner: 2, fraction: 500 });
+        assert_eq!(TemplateModule::refungible_item_id(1,1).owner[1], Ownership { owner: 3, fraction: 500 });
+        assert_eq!(TemplateModule::balance_count(1,2), 500);
+        assert_eq!(TemplateModule::balance_count(1,3), 500);
+        assert_eq!(TemplateModule::address_tokens(1,2), [1]);
+        assert_eq!(TemplateModule::address_tokens(1,3), [1]);
+
+        // split item and new owner has account scenario
+        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 200));
+        assert_eq!(TemplateModule::refungible_item_id(1,1).owner[0], Ownership { owner: 2, fraction: 300 });
+        assert_eq!(TemplateModule::refungible_item_id(1,1).owner[1], Ownership { owner: 3, fraction: 700 });
+        assert_eq!(TemplateModule::balance_count(1,2), 300);
+        assert_eq!(TemplateModule::balance_count(1,3), 700);
+        assert_eq!(TemplateModule::address_tokens(1,2), [1]);
+        assert_eq!(TemplateModule::address_tokens(1,3), [1]);
     });
 }
 
+
 #[test]
-fn remove_collection_admin() {
+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);
 
-        let size = 1024;
         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(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin2.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin3.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
+            mode
         ));
-
         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_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);
-        assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);
+        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]);
 
-        // remove admin
-        assert_ok!(TemplateModule::remove_collection_admin(
-            origin2.clone(),
-            1,
-            3
-        ));
-        assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), false);
+        // default scenario
+        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));
+        assert_eq!(TemplateModule::nft_item_id(1,1).owner, 2);
+        assert_eq!(TemplateModule::balance_count(1,1), 0);
+        assert_eq!(TemplateModule::balance_count(1,2), 1);
+        assert_eq!(TemplateModule::address_tokens(1,1), []);
+        assert_eq!(TemplateModule::address_tokens(1,2), [1]); 
     });
 }
 
 #[test]
-fn balance_of() {
+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);
 
-        let size = 1024;
         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(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin2.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
+            mode
         ));
-        assert_ok!(TemplateModule::create_collection(
-            origin3.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
-        ));
+        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-        assert_eq!(TemplateModule::collection(2).owner, 2);
-        assert_eq!(TemplateModule::collection(3).owner, 3);
 
-        // check balance before
-        assert_eq!(TemplateModule::balance_count((1, 1)), 0);
+        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]);
 
-        // create item
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 1, 1].to_vec()
-        ));
+        assert_noop!(
+            TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),
+            "You do not have permissions to modify this collection"
+        );
 
-        // check balance (collection with id = 1, user id = 2)
-        assert_eq!(TemplateModule::balance_count((1, 1)), 1);
-        assert_eq!(TemplateModule::item_id((1, 1)).owner, 1);
+        // do approve
+        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
+        assert_eq!(TemplateModule::approved(1,(1,1)).len(), 1);
+        assert_ok!(TemplateModule::approve(origin1.clone(), 10, 1, 1));
+        assert_eq!(TemplateModule::approved(1,(1,1)).len(), 2);
+        assert_eq!(TemplateModule::approved(1,(1,1))[0], ApprovePermissions { approved: 2, amount: 100000000});
+
+        assert_ok!(TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1));
+        assert_eq!(TemplateModule::approved(1,(1,1)).len(), 0);
     });
 }
 
 #[test]
-fn transfer() {
+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);
 
-        let size = 1024;
         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(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin2.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin3.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
+            mode
         ));
+        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-        assert_eq!(TemplateModule::collection(2).owner, 2);
-        assert_eq!(TemplateModule::collection(3).owner, 3);
+        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 });
+        assert_eq!(TemplateModule::balance_count(1,1), 1000);
+        assert_eq!(TemplateModule::address_tokens(1,1), [1]);
+
+        assert_noop!(
+            TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),
+            "You do not have permissions to modify this collection"
+        );
 
-        // create item
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 1, 1].to_vec()
-        ));
+        // do approve
+        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
+        assert_eq!(TemplateModule::approved(1,(1,1)).len(), 1);
+        assert_ok!(TemplateModule::approve(origin1.clone(), 10, 1, 1));
+        assert_eq!(TemplateModule::approved(1,(1,1)).len(), 2);
+        assert_eq!(TemplateModule::approved(1,(1,1))[0], ApprovePermissions { approved: 2, amount: 100000000});
 
-        // transfer
-        assert_ok!(TemplateModule::transfer(origin1.clone(), 1, 1, 2));
-        assert_eq!(TemplateModule::item_id((1, 1)).owner, 2);
+        assert_ok!(TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 100));
+        assert_eq!(TemplateModule::balance_count(1,1), 900);
+        assert_eq!(TemplateModule::balance_count(1,3), 100);
+        assert_eq!(TemplateModule::address_tokens(1,1), [1]);
+        assert_eq!(TemplateModule::address_tokens(1,3), [1]);
 
-        // balance_of check
-        assert_eq!(TemplateModule::balance_count((1, 1)), 0);
-        assert_eq!(TemplateModule::balance_count((1, 2)), 1);
+        assert_eq!(TemplateModule::approved(1,(1,1)).len(), 1);
+        assert_eq!(TemplateModule::approved(1,(1,1))[0], ApprovePermissions { approved: 10, amount: 100000000});
     });
 }
 
 #[test]
-fn approve() {
+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);
 
-        let size = 1024;
         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(),
-            size
+            mode
         ));
-        assert_ok!(TemplateModule::create_collection(
-            origin2.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin3.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
-        ));
+        assert_eq!(TemplateModule::collection(1).owner, 1);
 
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-        assert_eq!(TemplateModule::collection(2).owner, 2);
-        assert_eq!(TemplateModule::collection(3).owner, 3);
+        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]);
+
+        assert_noop!(
+            TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),
+            "You do not have permissions to modify this collection"
+        );
+
+        // do approve
+        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
+        assert_eq!(TemplateModule::approved(1,(1,1)).len(), 1);
+        assert_ok!(TemplateModule::approve(origin1.clone(), 10, 1, 1));
+        assert_eq!(TemplateModule::approved(1,(1,1)).len(), 2);
+        assert_eq!(TemplateModule::approved(1,(1,1))[0], ApprovePermissions { approved: 2, amount: 100000000});
+
+        assert_ok!(TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 100));
+        assert_eq!(TemplateModule::balance_count(1,1), 900);
+        assert_eq!(TemplateModule::balance_count(1,3), 100);
+        assert_eq!(TemplateModule::address_tokens(1,1), [1]);
+        assert_eq!(TemplateModule::address_tokens(1,3), [2]);
 
-        // create item
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 1, 1].to_vec()
-        ));
+        assert_eq!(TemplateModule::approved(1,(1,1)).len(), 1);
+        assert_eq!(TemplateModule::approved(1,(1,1))[0], ApprovePermissions { approved: 10, amount: 100000000});
 
-        // approve
         assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
-        assert_eq!(TemplateModule::approved((1, 1)).contains(&2), true);
+        assert_ok!(TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 900));
+        assert_eq!(TemplateModule::balance_count(1,1), 0);
+        assert_eq!(TemplateModule::balance_count(1,3), 1000);
+        assert_eq!(TemplateModule::address_tokens(1,1), []);
+        assert_eq!(TemplateModule::address_tokens(1,3), [2]);
+
+        assert_eq!(TemplateModule::approved(1,(1,1)).len(), 0);
     });
 }
 
-#[test]
-fn get_approved() {
-    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 size = 1024;
-        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(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin2.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin3.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
-        ));
 
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-        assert_eq!(TemplateModule::collection(2).owner, 2);
-        assert_eq!(TemplateModule::collection(3).owner, 3);
 
-        // create item
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 1, 1].to_vec()
-        ));
 
-        // approve
-        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
-        assert_eq!(TemplateModule::approved((1, 1)).contains(&2), true);
-    });
-}
 
-#[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 size = 1024;
-        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(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin2.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin3.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
-        ));
 
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-        assert_eq!(TemplateModule::collection(2).owner, 2);
-        assert_eq!(TemplateModule::collection(3).owner, 3);
 
-        // create item
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 1, 1].to_vec()
-        ));
 
-        // approve
-        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
-        assert_ok!(TemplateModule::transfer_from(origin1.clone(), 1, 1, 2));
-    });
-}
 
-#[test]
-fn index_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 size = 1024;
-        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(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin2.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
-        ));
-        assert_ok!(TemplateModule::create_collection(
-            origin3.clone(),
-            col_name1.clone(),
-            col_desc1.clone(),
-            token_prefix1.clone(),
-            size
-        ));
 
-        assert_eq!(TemplateModule::collection(1).owner, 1);
-        assert_eq!(TemplateModule::collection(2).owner, 2);
-        assert_eq!(TemplateModule::collection(3).owner, 3);
-        // create items
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 1, 1].to_vec()
-        ));
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 1, 2].to_vec()
-        ));
-        assert_ok!(TemplateModule::create_item(
-            origin1.clone(),
-            1,
-            [1, 2, 3].to_vec()
-        ));
-        assert_eq!(TemplateModule::address_tokens((1, 1)).len(), 3);
-        // burn one
-        assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 2));
-        assert_eq!(TemplateModule::address_tokens((1, 1)).len(), 2);
-        // burn another one
-        assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 3));
-        assert_eq!(TemplateModule::address_tokens((1, 1))[0], 1);
-    });
-}
+// #[test]
+// fn create_collection_test() {
+//     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 size = 1024;
+//         let origin1 = Origin::signed(1);
+//         assert_ok!(TemplateModule::create_collection(
+//             origin1.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+//         assert_eq!(TemplateModule::collection(1).owner, 1);
+//     });
+// }
+
+// #[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 size = 1024;
+//         let origin1 = Origin::signed(1);
+
+//         assert_ok!(TemplateModule::create_collection(
+//             origin1.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::change_collection_owner(
+//             origin1.clone(),
+//             1,
+//             2
+//         ));
+//         assert_eq!(TemplateModule::collection(1).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 size = 1024;
+//         let origin1 = Origin::signed(1);
+
+//         assert_ok!(TemplateModule::create_collection(
+//             origin1.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));
+//     });
+// }
+
+// #[test]
+// fn create_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 size = 1024;
+//         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(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
+//         assert_ok!(TemplateModule::create_item(
+//             origin2.clone(),
+//             1,
+//             [1, 1, 1].to_vec()
+//         ));
+
+//         // check balance (collection with id = 1, user id = 2)
+//         assert_eq!(TemplateModule::balance_count((1, 2)), 1);
+//     });
+// }
+
+// #[test]
+// fn burn_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 size = 1024;
+//         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(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
+//         assert_ok!(TemplateModule::create_item(
+//             origin2.clone(),
+//             1,
+//             [1, 1, 1].to_vec()
+//         ));
+
+//         // check balance (collection with id = 1, user id = 2)
+//         assert_eq!(TemplateModule::balance_count((1, 2)), 1);
+
+//         // burn item
+//         assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1));
+//         assert_noop!(
+//             TemplateModule::burn_item(origin1.clone(), 1, 1),
+//             "Item does not exists"
+//         );
+
+//         assert_eq!(TemplateModule::balance_count((1, 1)), 0);
+//     });
+// }
+
+// #[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 size = 1024;
+//         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(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin2.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin3.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+
+//         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_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);
+//         assert_eq!(TemplateModule::admin_list_collection(1).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 size = 1024;
+//         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(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin2.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin3.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+
+//         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_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);
+//         assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);
+
+//         // remove admin
+//         assert_ok!(TemplateModule::remove_collection_admin(
+//             origin2.clone(),
+//             1,
+//             3
+//         ));
+//         assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), false);
+//     });
+// }
+
+// #[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 size = 1024;
+//         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(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin2.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin3.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+
+//         assert_eq!(TemplateModule::collection(1).owner, 1);
+//         assert_eq!(TemplateModule::collection(2).owner, 2);
+//         assert_eq!(TemplateModule::collection(3).owner, 3);
+
+//         // check balance before
+//         assert_eq!(TemplateModule::balance_count((1, 1)), 0);
+
+//         // create item
+//         assert_ok!(TemplateModule::create_item(
+//             origin1.clone(),
+//             1,
+//             [1, 1, 1].to_vec()
+//         ));
+
+//         // check balance (collection with id = 1, user id = 2)
+//         assert_eq!(TemplateModule::balance_count((1, 1)), 1);
+//         assert_eq!(TemplateModule::item_id((1, 1)).owner, 1);
+//     });
+// }
+
+// #[test]
+// fn transfer() {
+//     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 size = 1024;
+//         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(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin2.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin3.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+
+//         assert_eq!(TemplateModule::collection(1).owner, 1);
+//         assert_eq!(TemplateModule::collection(2).owner, 2);
+//         assert_eq!(TemplateModule::collection(3).owner, 3);
+
+//         // create item
+//         assert_ok!(TemplateModule::create_item(
+//             origin1.clone(),
+//             1,
+//             [1, 1, 1].to_vec()
+//         ));
+
+//         // transfer
+//         assert_ok!(TemplateModule::transfer(origin1.clone(), 1, 1, 2));
+//         assert_eq!(TemplateModule::item_id((1, 1)).owner, 2);
+
+//         // balance_of check
+//         assert_eq!(TemplateModule::balance_count((1, 1)), 0);
+//         assert_eq!(TemplateModule::balance_count((1, 2)), 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 size = 1024;
+//         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(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin2.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin3.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+
+//         assert_eq!(TemplateModule::collection(1).owner, 1);
+//         assert_eq!(TemplateModule::collection(2).owner, 2);
+//         assert_eq!(TemplateModule::collection(3).owner, 3);
+
+//         // create item
+//         assert_ok!(TemplateModule::create_item(
+//             origin1.clone(),
+//             1,
+//             [1, 1, 1].to_vec()
+//         ));
+
+//         // approve
+//         assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
+//         assert_eq!(TemplateModule::approved((1, 1)).contains(&2), true);
+//     });
+// }
+
+// #[test]
+// fn get_approved() {
+//     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 size = 1024;
+//         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(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin2.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin3.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+
+//         assert_eq!(TemplateModule::collection(1).owner, 1);
+//         assert_eq!(TemplateModule::collection(2).owner, 2);
+//         assert_eq!(TemplateModule::collection(3).owner, 3);
+
+//         // create item
+//         assert_ok!(TemplateModule::create_item(
+//             origin1.clone(),
+//             1,
+//             [1, 1, 1].to_vec()
+//         ));
+
+//         // approve
+//         assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
+//         assert_eq!(TemplateModule::approved((1, 1)).contains(&2), true);
+//     });
+// }
+
+// #[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 size = 1024;
+//         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(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin2.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin3.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+
+//         assert_eq!(TemplateModule::collection(1).owner, 1);
+//         assert_eq!(TemplateModule::collection(2).owner, 2);
+//         assert_eq!(TemplateModule::collection(3).owner, 3);
+
+//         // create item
+//         assert_ok!(TemplateModule::create_item(
+//             origin1.clone(),
+//             1,
+//             [1, 1, 1].to_vec()
+//         ));
+
+//         // approve
+//         assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
+//         assert_ok!(TemplateModule::transfer_from(origin1.clone(), 1, 1, 2));
+//     });
+// }
+
+// #[test]
+// fn index_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 size = 1024;
+//         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(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin2.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+//         assert_ok!(TemplateModule::create_collection(
+//             origin3.clone(),
+//             col_name1.clone(),
+//             col_desc1.clone(),
+//             token_prefix1.clone(),
+//             size
+//         ));
+
+//         assert_eq!(TemplateModule::collection(1).owner, 1);
+//         assert_eq!(TemplateModule::collection(2).owner, 2);
+//         assert_eq!(TemplateModule::collection(3).owner, 3);
+//         // create items
+//         assert_ok!(TemplateModule::create_item(
+//             origin1.clone(),
+//             1,
+//             [1, 1, 1].to_vec()
+//         ));
+//         assert_ok!(TemplateModule::create_item(
+//             origin1.clone(),
+//             1,
+//             [1, 1, 2].to_vec()
+//         ));
+//         assert_ok!(TemplateModule::create_item(
+//             origin1.clone(),
+//             1,
+//             [1, 2, 3].to_vec()
+//         ));
+//         assert_eq!(TemplateModule::address_tokens((1, 1)).len(), 3);
+//         // burn one
+//         assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 2));
+//         assert_eq!(TemplateModule::address_tokens((1, 1)).len(), 2);
+//         // burn another one
+//         assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 3));
+//         assert_eq!(TemplateModule::address_tokens((1, 1))[0], 1);
+//     });
+// }