git.delta.rocks / unique-network / refs/commits / 1ddda31cdfab

difftreelog

Merge branch 'develop' into release/v2.0.0

Greg Zaitsev2021-02-09parents: #b1f8c2e #337b8d4.patch.diff
in: master

34 files changed

modifiedDockerfilediffbeforeafterboth
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,9 @@
 # ===== BUILD ======
 
-FROM phusion/baseimage:0.10.2 as builder
+FROM phusion/baseimage:18.04-1.0.0 as builder
 LABEL maintainer="gz@usetech.com"
 
-ENV WASM_TOOLCHAIN=nightly-2020-10-01
+ENV WASM_TOOLCHAIN=nightly-2021-01-27
 
 ARG PROFILE=release
 
@@ -37,7 +37,7 @@
 
 # ===== RUN ======
 
-FROM phusion/baseimage:0.10.2
+FROM phusion/baseimage:18.04-1.0.0
 ARG PROFILE=release
 
 COPY --from=builder /nft_parachain/target/$PROFILE/nft /usr/local/bin
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -54,6 +54,7 @@
 mod default_weights;
 
 pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;
+pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;
 pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;
 pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;
 
@@ -71,8 +72,7 @@
     NFT,
     // decimal points
     Fungible(DecimalPoints),
-    // decimal points
-    ReFungible(DecimalPoints),
+    ReFungible,
 }
 
 impl Default for CollectionMode {
@@ -87,7 +87,7 @@
             CollectionMode::Invalid => 0,
             CollectionMode::NFT => 1,
             CollectionMode::Fungible(_) => 2,
-            CollectionMode::ReFungible(_) => 3,
+            CollectionMode::ReFungible => 3,
         }
     }
 }
@@ -185,6 +185,8 @@
 
     // Timeouts for item types in passed blocks
     pub sponsor_transfer_timeout: u32,
+    pub owner_can_transfer: bool,
+    pub owner_can_destroy: bool,
 }
 
 impl Default for CollectionLimits {
@@ -193,7 +195,10 @@
             account_token_ownership_limit: 10_000_000, 
             token_limit: u32::max_value(),
             sponsored_data_size: u32::max_value(), 
-            sponsor_transfer_timeout: 14400 }
+            sponsor_transfer_timeout: 14400,
+            owner_can_transfer: true,
+            owner_can_destroy: true
+        }
     }
 }
 
@@ -266,6 +271,7 @@
 pub struct CreateReFungibleData {
     pub const_data: Vec<u8>,
     pub variable_data: Vec<u8>,
+    pub pieces: u128,
 }
 
 #[derive(Encode, Decode, Debug, Clone, PartialEq)]
@@ -377,7 +383,9 @@
         /// Collection limit bounds per collection exceeded
         CollectionLimitBoundsExceeded,
         /// Schema data size limit bound exceeded
-        SchemaDataLimitExceeded
+        SchemaDataLimitExceeded,
+        /// Maximum refungibility exceeded
+        WrongRefungiblePieces
 	}
 }
 
@@ -548,7 +556,6 @@
 
             let decimal_points = match mode {
                 CollectionMode::Fungible(points) => points,
-                CollectionMode::ReFungible(points) => points,
                 _ => 0
             };
 
@@ -590,7 +597,7 @@
                 sponsor_confirmed: false,
                 variable_on_chain_schema: Vec::new(),
                 const_on_chain_schema: Vec::new(),
-                limits: CollectionLimits::default(),
+                limits: CollectionLimits::default()
             };
 
             // Add new collection to map
@@ -933,7 +940,7 @@
 
             Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;
             Self::validate_create_item_args(&target_collection, &data)?;
-            Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;
+            Self::create_item_no_validation(collection_id, owner, data)?;
 
             Ok(())
         }
@@ -973,7 +980,7 @@
                 Self::validate_create_item_args(&target_collection, data)?;
             }
             for data in &items_data {
-                Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;
+                Self::create_item_no_validation(collection_id, owner.clone(), data.clone())?;
             }
 
             Ok(())
@@ -1012,7 +1019,7 @@
             {
                 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,
                 CollectionMode::Fungible(_)  => Self::burn_fungible_item(&sender, collection_id, value)?,
-                CollectionMode::ReFungible(_)  => Self::burn_refungible_item(collection_id, item_id, &sender)?,
+                CollectionMode::ReFungible  => Self::burn_refungible_item(collection_id, item_id, &sender)?,
                 _ => ()
             };
 
@@ -1154,7 +1161,7 @@
             {
                 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,
                 CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, value, &from, &recipient)?,
-                CollectionMode::ReFungible(_)  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,
+                CollectionMode::ReFungible  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,
                 _ => ()
             };
 
@@ -1211,7 +1218,7 @@
             match target_collection.mode
             {
                 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,
-                CollectionMode::ReFungible(_)  => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,
+                CollectionMode::ReFungible  => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,
                 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),
                 _ => fail!(Error::<T>::UnexpectedCollectionType)
             };
@@ -1551,7 +1558,7 @@
         {
             CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,
             CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,
-            CollectionMode::ReFungible(_)  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,
+            CollectionMode::ReFungible  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,
             _ => ()
         };
 
@@ -1603,12 +1610,16 @@
                     fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);
                 }
             },
-            CollectionMode::ReFungible(_) => {
+            CollectionMode::ReFungible => {
                 if let CreateItemData::ReFungible(data) = data {
 
                     // check sizes
                     ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);
                     ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);
+
+                    // Check refungibility limits
+                    ensure!(data.pieces <= MAX_REFUNGIBLE_PIECES, Error::<T>::WrongRefungiblePieces);
+                    ensure!(data.pieces > 0, Error::<T>::WrongRefungiblePieces);
                 } else {
                     fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);
                 }
@@ -1619,7 +1630,7 @@
         Ok(())
     }
 
-    fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {
+    fn create_item_no_validation(collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {
         match data
         {
             CreateItemData::NFT(data) => {
@@ -1636,8 +1647,7 @@
             },
             CreateItemData::ReFungible(data) => {
                 let mut owner_list = Vec::new();
-                let value = (10 as u128).pow(collection.decimal_points as u32);
-                owner_list.push(Ownership {owner: owner.clone(), fraction: value});
+                owner_list.push(Ownership {owner: owner.clone(), fraction: data.pieces});
 
                 let item = ReFungibleItemType {
                     owner: owner_list,
@@ -1866,7 +1876,7 @@
             CollectionMode::Fungible(_) => {
                 <FungibleItemList<T>>::contains_key(collection_id, &subject)
             }
-            CollectionMode::ReFungible(_) => {
+            CollectionMode::ReFungible => {
                 <ReFungibleItemList<T>>::get(collection_id, item_id)
                     .owner
                     .iter()
@@ -1895,7 +1905,7 @@
         {
             CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),
             CollectionMode::Fungible(_)  => <FungibleItemList<T>>::contains_key(collection_id, owner),
-            CollectionMode::ReFungible(_)  => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),
+            CollectionMode::ReFungible  => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),
             _ => false
         };
 
@@ -2421,7 +2431,7 @@
 
                             sponsored
                         }
-                        CollectionMode::ReFungible(_) => {
+                        CollectionMode::ReFungible => {
     
                             // get correct limit
                             let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
before · pallets/nft/src/tests.rs
1// Tests to be written here2use super::*;3use crate::mock::*;4use crate::{AccessMode, CollectionMode,5    Ownership, ChainLimits, CreateItemData, CreateNftData, CreateFungibleData, CreateReFungibleData,6    CollectionId, TokenId, MAX_DECIMAL_POINTS};7use frame_support::{assert_noop, assert_ok};8use frame_system::{ RawOrigin };910fn default_collection_numbers_limit() -> u32 {11    1012}1314fn default_limits() {15    assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits {16            collection_numbers_limit: default_collection_numbers_limit(),17            account_token_ownership_limit: 10,18            collections_admins_limit: 5,19            custom_data_limit: 2048,20            nft_sponsor_transfer_timeout: 15,21            fungible_sponsor_transfer_timeout: 15,22            refungible_sponsor_transfer_timeout: 15,23            const_on_chain_schema_limit: 1024,24            offchain_schema_limit: 1024,25            variable_on_chain_schema_limit: 1024,26        }));27}2829fn default_nft_data() -> CreateNftData {30    CreateNftData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] }31}3233fn default_fungible_data () -> CreateFungibleData {34    CreateFungibleData { value: 5 }35}3637fn default_re_fungible_data () -> CreateReFungibleData {38    CreateReFungibleData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] }39}4041fn create_test_collection_for_owner(mode: &CollectionMode, owner: u64, id: CollectionId) -> CollectionId {42    let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();43    let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();44    let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();4546    let origin1 = Origin::signed(owner);47    assert_ok!(TemplateModule::create_collection(48            origin1.clone(),49            col_name1.clone(),50            col_desc1.clone(),51            token_prefix1.clone(),52            mode.clone()53        ));5455    let saved_col_name: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();56    let saved_description: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();57    let saved_prefix: Vec<u8> = b"token_prefix1\0".to_vec();58    assert_eq!(TemplateModule::collection(id).owner, owner);59    assert_eq!(TemplateModule::collection(id).name, saved_col_name);60    assert_eq!(TemplateModule::collection(id).mode, *mode);61    assert_eq!(TemplateModule::collection(id).description, saved_description);62    assert_eq!(TemplateModule::collection(id).token_prefix, saved_prefix);63    id64}6566fn create_test_collection(mode: &CollectionMode, id: CollectionId) -> CollectionId {67    create_test_collection_for_owner(&mode, 1, id)68}6970fn create_test_item(collection_id: CollectionId, data: &CreateItemData) {71    let origin1 = Origin::signed(1);72    assert_ok!(TemplateModule::create_item(73            origin1.clone(),74            collection_id,75            1,76            data.clone()77        ));7879}8081// Use cases tests region82// #region8384#[test]85fn set_version_schema() {86    new_test_ext().execute_with(|| {87        default_limits();88        let origin1 = Origin::signed(1);89        let collection_id = create_test_collection(&CollectionMode::NFT, 1);90        91        assert_ok!(TemplateModule::set_schema_version(origin1, collection_id, SchemaVersion::Unique));92        assert_eq!(TemplateModule::collection(collection_id).schema_version, SchemaVersion::Unique);93    });94}9596#[test]97fn create_fungible_collection_fails_with_large_decimal_numbers() {98    new_test_ext().execute_with(|| {99        default_limits();100101        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();102        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();103        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();104105        let origin1 = Origin::signed(1);106        assert_noop!(TemplateModule::create_collection(107            origin1,108            col_name1,109            col_desc1,110            token_prefix1,111            CollectionMode::Fungible(MAX_DECIMAL_POINTS + 1)112        ), Error::<Test>::CollectionDecimalPointLimitExceeded);113    });    114}115116#[test]117fn create_re_fungible_collection_fails_with_large_decimal_numbers() {118    new_test_ext().execute_with(|| {119        default_limits();120121        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();122        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();123        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();124125        let origin1 = Origin::signed(1);126        assert_noop!(TemplateModule::create_collection(127            origin1,128            col_name1,129            col_desc1,130            token_prefix1,131            CollectionMode::ReFungible(MAX_DECIMAL_POINTS + 1)132        ), Error::<Test>::CollectionDecimalPointLimitExceeded);133    });134}135136#[test]137fn create_nft_item() {138    new_test_ext().execute_with(|| {139        default_limits();140        let collection_id = create_test_collection(&CollectionMode::NFT, 1);141        142        let data = default_nft_data();143        create_test_item(collection_id, &data.clone().into());144        assert_eq!(TemplateModule::nft_item_id(collection_id, 1).const_data, data.const_data);145        assert_eq!(TemplateModule::nft_item_id(collection_id, 1).variable_data, data.variable_data);146    });147}148149// Use cases tests region150// #region151#[test]152fn create_nft_multiple_items() {153    new_test_ext().execute_with(|| {154        default_limits();155        156        create_test_collection(&CollectionMode::NFT, 1);157158        let origin1 = Origin::signed(1);159160        let items_data = vec![default_nft_data(), default_nft_data(), default_nft_data()];161162        assert_ok!(TemplateModule::create_multiple_items(163            origin1.clone(),164            1,165            1,166            items_data.clone().into_iter().map(|d| { d.into() }).collect()167        ));168        for (index, data) in items_data.iter().enumerate() {169            assert_eq!(TemplateModule::nft_item_id(1, (index + 1) as TokenId).const_data.to_vec(), data.const_data);170            assert_eq!(TemplateModule::nft_item_id(1, (index + 1) as TokenId).variable_data.to_vec(), data.variable_data);171        }172    });173}174175#[test]176fn create_refungible_item() {177    new_test_ext().execute_with(|| {178        default_limits();179        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);180181        let data = default_re_fungible_data();182        create_test_item(collection_id, &data.clone().into());183        assert_eq!(184            TemplateModule::refungible_item_id(collection_id, 1).const_data,185            data.const_data186        );187        assert_eq!(188            TemplateModule::refungible_item_id(collection_id, 1).variable_data,189            data.variable_data190        );191        assert_eq!(192            TemplateModule::refungible_item_id(collection_id, 1).owner[0],193            Ownership {194                owner: 1,195                fraction: 1000196            }197        );198    });199}200201#[test]202fn create_multiple_refungible_items() {203    new_test_ext().execute_with(|| {204        default_limits();205        206        create_test_collection(&CollectionMode::ReFungible(3), 1);207208        let origin1 = Origin::signed(1);209210        let items_data = vec![default_re_fungible_data(), default_re_fungible_data(), default_re_fungible_data()];211212        assert_ok!(TemplateModule::create_multiple_items(213            origin1.clone(),214            1,215            1,216            items_data.clone().into_iter().map(|d| { d.into() }).collect()217        ));218        for (index, data) in items_data.iter().enumerate() {219220            let item = TemplateModule::refungible_item_id(1, (index + 1) as TokenId);221            assert_eq!(item.const_data.to_vec(), data.const_data);222            assert_eq!(item.variable_data.to_vec(), data.variable_data);223            assert_eq!(224                item.owner[0],225                Ownership {226                    owner: 1,227                    fraction: 1000228                }229            );230        }231    });232}233234#[test]235fn create_fungible_item() {236    new_test_ext().execute_with(|| {237        default_limits();238        239        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);240241        let data = default_fungible_data();242        create_test_item(collection_id, &data.into());243244        assert_eq!(TemplateModule::fungible_item_id(collection_id, 1).value, 5);245    });246}247248//#[test]249// fn create_multiple_fungible_items() {250//     new_test_ext().execute_with(|| {251//         default_limits();252253//         create_test_collection(&CollectionMode::Fungible(3), 1);254255//         let origin1 = Origin::signed(1);256257//         let items_data = vec![default_fungible_data(), default_fungible_data(), default_fungible_data()];258259//         assert_ok!(TemplateModule::create_multiple_items(260//             origin1.clone(),261//             1,262//             1,263//             items_data.clone().into_iter().map(|d| { d.into() }).collect()264//         ));265        266//         for (index, _) in items_data.iter().enumerate() {267//             assert_eq!(TemplateModule::fungible_item_id(1, (index + 1) as TokenId).value, 5);268//         }269//         assert_eq!(TemplateModule::balance_count(1, 1), 3000);270//         assert_eq!(TemplateModule::address_tokens(1, 1), [1, 2, 3]);271//     });272// }273274#[test]275fn transfer_fungible_item() {276    new_test_ext().execute_with(|| {277        default_limits();278        279        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);280281        let origin1 = Origin::signed(1);282        let origin2 = Origin::signed(2);283284        let data = default_fungible_data();285        create_test_item(collection_id, &data.into());286287        assert_eq!(TemplateModule::fungible_item_id(1, 1).value, 5);288        assert_eq!(TemplateModule::balance_count(1, 1), 5);289290        // change owner scenario291        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 5));292        assert_eq!(TemplateModule::fungible_item_id(1, 1).value, 0);293        assert_eq!(TemplateModule::balance_count(1, 1), 0);294        assert_eq!(TemplateModule::balance_count(1, 2), 5);295296        // split item scenario297        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 3));298        assert_eq!(TemplateModule::balance_count(1, 2), 2);299        assert_eq!(TemplateModule::balance_count(1, 3), 3);300301        // split item and new owner has account scenario302        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 1));303        assert_eq!(TemplateModule::fungible_item_id(1, 2).value, 1);304        assert_eq!(TemplateModule::fungible_item_id(1, 3).value, 4);305        assert_eq!(TemplateModule::balance_count(1, 2), 1);306        assert_eq!(TemplateModule::balance_count(1, 3), 4);307    });308}309310#[test]311fn transfer_refungible_item() {312    new_test_ext().execute_with(|| {313        default_limits();314        315        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);316317        let data = default_re_fungible_data();318        create_test_item(collection_id, &data.clone().into());319320        let origin1 = Origin::signed(1);321        let origin2 = Origin::signed(2);322        assert_eq!(323            TemplateModule::refungible_item_id(collection_id, 1).const_data,324            data.const_data325        );326        assert_eq!(327            TemplateModule::refungible_item_id(collection_id, 1).variable_data,328            data.variable_data329        );330        assert_eq!(331            TemplateModule::refungible_item_id(collection_id, 1).owner[0],332            Ownership {333                owner: 1,334                fraction: 1000335            }336        );337        assert_eq!(TemplateModule::balance_count(1, 1), 1000);338        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);339340        // change owner scenario341        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));342        assert_eq!(343            TemplateModule::refungible_item_id(1, 1).owner[0],344            Ownership {345                owner: 2,346                fraction: 1000347            }348        );349        assert_eq!(TemplateModule::balance_count(1, 1), 0);350        assert_eq!(TemplateModule::balance_count(1, 2), 1000);351        // assert_eq!(TemplateModule::address_tokens(1, 1), []);352        assert_eq!(TemplateModule::address_tokens(1, 2), [1]);353354        // split item scenario355        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 500));356        assert_eq!(357            TemplateModule::refungible_item_id(1, 1).owner[0],358            Ownership {359                owner: 2,360                fraction: 500361            }362        );363        assert_eq!(364            TemplateModule::refungible_item_id(1, 1).owner[1],365            Ownership {366                owner: 3,367                fraction: 500368            }369        );370        assert_eq!(TemplateModule::balance_count(1, 2), 500);371        assert_eq!(TemplateModule::balance_count(1, 3), 500);372        assert_eq!(TemplateModule::address_tokens(1, 2), [1]);373        assert_eq!(TemplateModule::address_tokens(1, 3), [1]);374375        // split item and new owner has account scenario376        assert_ok!(TemplateModule::transfer(origin2.clone(), 3, 1, 1, 200));377        assert_eq!(378            TemplateModule::refungible_item_id(1, 1).owner[0],379            Ownership {380                owner: 2,381                fraction: 300382            }383        );384        assert_eq!(385            TemplateModule::refungible_item_id(1, 1).owner[1],386            Ownership {387                owner: 3,388                fraction: 700389            }390        );391        assert_eq!(TemplateModule::balance_count(1, 2), 300);392        assert_eq!(TemplateModule::balance_count(1, 3), 700);393        assert_eq!(TemplateModule::address_tokens(1, 2), [1]);394        assert_eq!(TemplateModule::address_tokens(1, 3), [1]);395    });396}397398#[test]399fn transfer_nft_item() {400    new_test_ext().execute_with(|| {401        default_limits();402        403        let collection_id = create_test_collection(&CollectionMode::NFT, 1);404405        let data = default_nft_data();406        create_test_item(collection_id, &data.into());407        assert_eq!(TemplateModule::balance_count(1, 1), 1);408        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);409410        let origin1 = Origin::signed(1);411        // default scenario412        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));413        assert_eq!(TemplateModule::nft_item_id(1, 1).owner, 2);414        assert_eq!(TemplateModule::balance_count(1, 1), 0);415        assert_eq!(TemplateModule::balance_count(1, 2), 1);416        // assert_eq!(TemplateModule::address_tokens(1, 1), []);417        assert_eq!(TemplateModule::address_tokens(1, 2), [1]);418    });419}420421#[test]422fn nft_approve_and_transfer_from() {423    new_test_ext().execute_with(|| {424        default_limits();425        426        let collection_id = create_test_collection(&CollectionMode::NFT, 1);427428        let data = default_nft_data();429        create_test_item(collection_id, &data.into());430431        let origin1 = Origin::signed(1);432        let origin2 = Origin::signed(2);433434        assert_eq!(TemplateModule::balance_count(1, 1), 1);435        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);436437        // neg transfer438        assert_noop!(TemplateModule::transfer_from(439            origin2.clone(),440            1,441            2,442            1,443            1,444            1), Error::<Test>::NoPermission);445446        // do approve447        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));448        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);449        assert_eq!(450            TemplateModule::approved(1, (1, 1, 2)),451            5452        );453454        assert_ok!(TemplateModule::transfer_from(455            origin2.clone(),456            1,457            3,458            1,459            1,460            1461        ));462        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 4);463    });464}465466#[test]467fn nft_approve_and_transfer_from_white_list() {468    new_test_ext().execute_with(|| {469        default_limits();470        471        let collection_id = create_test_collection(&CollectionMode::NFT, 1);472473        let origin1 = Origin::signed(1);474        let origin2 = Origin::signed(2);475476        let data = default_nft_data();477        create_test_item(collection_id, &data.clone().into());478479        assert_eq!(TemplateModule::nft_item_id(1, 1).const_data, data.const_data);480        assert_eq!(TemplateModule::balance_count(1, 1), 1);481        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);482483        assert_ok!(TemplateModule::set_mint_permission(484            origin1.clone(),485            1,486            true487        ));488        assert_ok!(TemplateModule::set_public_access_mode(489            origin1.clone(),490            1,491            AccessMode::WhiteList492        ));493        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));494        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));495        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));496497        // do approve498        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));499        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);500        assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1, 5));501        assert_eq!(TemplateModule::approved(1, (1, 1, 3)), 5);502503        assert_ok!(TemplateModule::transfer_from(504            origin2.clone(),505            1,506            3,507            1,508            1,509            1510        ));511        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 4);512    });513}514515#[test]516fn refungible_approve_and_transfer_from() {517    new_test_ext().execute_with(|| {518        default_limits();519        520        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);521        522        let origin1 = Origin::signed(1);523        let origin2 = Origin::signed(2);524525        let data = default_re_fungible_data();526        create_test_item(collection_id, &data.into());527528        assert_eq!(TemplateModule::balance_count(1, 1), 1000);529        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);530531        assert_ok!(TemplateModule::set_mint_permission(532            origin1.clone(),533            1,534            true535        ));536        assert_ok!(TemplateModule::set_public_access_mode(537            origin1.clone(),538            1,539            AccessMode::WhiteList540        ));541        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));542        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));543        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));544545        // do approve546        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1000));547        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1000);548549        assert_ok!(TemplateModule::transfer_from(550            origin2.clone(),551            1,552            3,553            1,554            1,555            100556        ));557        assert_eq!(TemplateModule::balance_count(1, 1), 900);558        assert_eq!(TemplateModule::balance_count(1, 3), 100);559        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);560        assert_eq!(TemplateModule::address_tokens(1, 3), [1]);561562        assert_eq!(563            TemplateModule::approved(1, (1, 1, 2)),564            900565        );566    });567}568569#[test]570fn fungible_approve_and_transfer_from() {571    new_test_ext().execute_with(|| {572        default_limits();573        574        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);575        576        let data = default_fungible_data();577        create_test_item(collection_id, &data.into());578579        let origin1 = Origin::signed(1);580        let origin2 = Origin::signed(2);581582        assert_eq!(TemplateModule::balance_count(1, 1), 5);583584        assert_ok!(TemplateModule::set_mint_permission(585            origin1.clone(),586            1,587            true588        ));589        assert_ok!(TemplateModule::set_public_access_mode(590            origin1.clone(),591            1,592            AccessMode::WhiteList593        ));594        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));595        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));596        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));597598        // do approve599        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 5));600        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 5);601        assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1, 5));602        assert_eq!(TemplateModule::approved(1, (1, 1, 3)), 5);603        assert_eq!(604            TemplateModule::approved(1, (1, 1, 2)),605            5606        );607608        assert_ok!(TemplateModule::transfer_from(609            origin2.clone(),610            1,611            3,612            1,613            1,614            4615        ));616        assert_eq!(TemplateModule::balance_count(1, 1), 1);617        assert_eq!(TemplateModule::balance_count(1, 3), 4);618619        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1);620621        assert_noop!(TemplateModule::transfer_from(622            origin2.clone(),623            1,624            3,625            1,626            1,627            4628        ), Error::<Test>::TokenValueNotEnough);629    });630}631632#[test]633fn change_collection_owner() {634    new_test_ext().execute_with(|| {635        default_limits();636        637        let collection_id = create_test_collection(&CollectionMode::NFT, 1);638        639        let origin1 = Origin::signed(1);640        assert_ok!(TemplateModule::change_collection_owner(641            origin1.clone(),642            collection_id,643            2644        ));645        assert_eq!(TemplateModule::collection(collection_id).owner, 2);646    });647}648649#[test]650fn destroy_collection() {651    new_test_ext().execute_with(|| {652        default_limits();653        654        let collection_id = create_test_collection(&CollectionMode::NFT, 1);655        656        let origin1 = Origin::signed(1);657        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));658    });659}660661#[test]662fn burn_nft_item() {663    new_test_ext().execute_with(|| {664        default_limits();665        666        let collection_id = create_test_collection(&CollectionMode::NFT, 1);667668        let origin1 = Origin::signed(1);669        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));670        671        let data = default_nft_data();672        create_test_item(collection_id, &data.into());673674        // check balance (collection with id = 1, user id = 1)675        assert_eq!(TemplateModule::balance_count(1, 1), 1);676677        // burn item678        assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 5));679        assert_noop!(680            TemplateModule::burn_item(origin1.clone(), 1, 1, 5),681            Error::<Test>::TokenNotFound682        );683684        assert_eq!(TemplateModule::balance_count(1, 1), 0);685    });686}687688#[test]689fn burn_fungible_item() {690    new_test_ext().execute_with(|| {691        default_limits();692        693        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);694        695        let origin1 = Origin::signed(1);696        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));697        698        let data = default_fungible_data();699        create_test_item(collection_id, &data.into());700701        // check balance (collection with id = 1, user id = 1)702        assert_eq!(TemplateModule::balance_count(1, 1), 5);703704        // burn item705        assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 5));706        assert_noop!(707            TemplateModule::burn_item(origin1.clone(), 1, 1, 5),708            Error::<Test>::TokenNotFound709        );710711        assert_eq!(TemplateModule::balance_count(1, 1), 0);712    });713}714715#[test]716fn burn_refungible_item() {717    new_test_ext().execute_with(|| {718        default_limits();719        720        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);721        let origin1 = Origin::signed(1);722723        assert_ok!(TemplateModule::set_mint_permission(724            origin1.clone(),725            collection_id,726            true727        ));728        assert_ok!(TemplateModule::set_public_access_mode(729            origin1.clone(),730            collection_id,731            AccessMode::WhiteList732        ));733        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));734735        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));736        737        let data = default_re_fungible_data();738        create_test_item(collection_id, &data.into());739740        // check balance (collection with id = 1, user id = 2)741        assert_eq!(TemplateModule::balance_count(1, 1), 1000);742743        // burn item744        assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 1000));745        assert_noop!(746            TemplateModule::burn_item(origin1.clone(), 1, 1, 1000),747            Error::<Test>::TokenNotFound748        );749750        assert_eq!(TemplateModule::balance_count(1, 1), 0);751    });752}753754#[test]755fn add_collection_admin() {756    new_test_ext().execute_with(|| {757        default_limits();758        759        let collection1_id = create_test_collection_for_owner(&CollectionMode::NFT, 1, 1);760        create_test_collection_for_owner(&CollectionMode::NFT, 2, 2);761        create_test_collection_for_owner(&CollectionMode::NFT, 3, 3);762        763        let origin1 = Origin::signed(1);764765        // collection admin766        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 2));767        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 3));768769        assert_eq!(TemplateModule::admin_list_collection(collection1_id).contains(&2), true);770        assert_eq!(TemplateModule::admin_list_collection(collection1_id).contains(&3), true);771    });772}773774#[test]775fn remove_collection_admin() {776    new_test_ext().execute_with(|| {777        default_limits();778        779        let collection1_id = create_test_collection_for_owner(&CollectionMode::NFT, 1, 1);780        create_test_collection_for_owner(&CollectionMode::NFT, 2, 2);781        create_test_collection_for_owner(&CollectionMode::NFT, 3, 3);782783        let origin1 = Origin::signed(1);784        let origin2 = Origin::signed(2);785786        // collection admin787        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 2));788        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection1_id, 3));789790        assert_eq!(TemplateModule::admin_list_collection(1).contains(&2), true);791        assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), true);792793        // remove admin794        assert_ok!(TemplateModule::remove_collection_admin(795            origin2.clone(),796            1,797            3798        ));799        assert_eq!(TemplateModule::admin_list_collection(1).contains(&3), false);800    });801}802803#[test]804fn balance_of() {805    new_test_ext().execute_with(|| {806        default_limits();807        808        let nft_collection_id = create_test_collection(&CollectionMode::NFT, 1);809        let fungible_collection_id = create_test_collection(&CollectionMode::Fungible(3), 2);810        let re_fungible_collection_id = create_test_collection(&CollectionMode::ReFungible(3), 3);811        812        // check balance before813        assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 0);814        assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 0);815        assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 0);816817        let nft_data = default_nft_data();818        create_test_item(nft_collection_id, &nft_data.into());819        820        let fungible_data = default_fungible_data();821        create_test_item(fungible_collection_id, &fungible_data.into());822        823        let re_fungible_data = default_re_fungible_data();824        create_test_item(re_fungible_collection_id, &re_fungible_data.into());825826        // check balance (collection with id = 1, user id = 1)827        assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 1);828        assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 5);829        assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 1000);830        assert_eq!(TemplateModule::nft_item_id(nft_collection_id, 1).owner, 1);831        assert_eq!(TemplateModule::fungible_item_id(fungible_collection_id, 1).value, 5);832        assert_eq!(TemplateModule::refungible_item_id(re_fungible_collection_id, 1).owner[0].owner, 1);833    });834}835836#[test]837fn approve() {838    new_test_ext().execute_with(|| {839        default_limits();840        841        let collection_id = create_test_collection(&CollectionMode::NFT, 1);842        843        let data = default_nft_data();844        create_test_item(collection_id, &data.into());845846        let origin1 = Origin::signed(1);847        848        // approve849        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1));850        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1);851    });852}853854#[test]855fn transfer_from() {856    new_test_ext().execute_with(|| {857        default_limits();858        859        let collection_id = create_test_collection(&CollectionMode::NFT, 1);860        let origin1 = Origin::signed(1);861        let origin2 = Origin::signed(2);862863        let data = default_nft_data();864        create_test_item(collection_id, &data.into());865866        // approve867        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1));868        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1);869870        assert_ok!(TemplateModule::set_mint_permission(871            origin1.clone(),872            1,873            true874        ));875        assert_ok!(TemplateModule::set_public_access_mode(876            origin1.clone(),877            1,878            AccessMode::WhiteList879        ));880        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));881        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));882        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));883884        assert_ok!(TemplateModule::transfer_from(885            origin2.clone(),886            1,887            2,888            1,889            1,890            1891        ));892893        // after transfer894        assert_eq!(TemplateModule::balance_count(1, 1), 0);895        assert_eq!(TemplateModule::balance_count(1, 2), 1);896    });897}898899// #endregion900901// Coverage tests region902// #region903904#[test]905fn owner_can_add_address_to_white_list() {906    new_test_ext().execute_with(|| {907        default_limits();908        909        let collection_id = create_test_collection(&CollectionMode::NFT, 1);910911        let origin1 = Origin::signed(1);912        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));913        assert_eq!(TemplateModule::white_list(collection_id, 2), true);914    });915}916917#[test]918fn admin_can_add_address_to_white_list() {919    new_test_ext().execute_with(|| {920        default_limits();921        922        let collection_id = create_test_collection(&CollectionMode::NFT, 1);923        let origin1 = Origin::signed(1);924        let origin2 = Origin::signed(2);925926        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));927        assert_ok!(TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3));928        assert_eq!(TemplateModule::white_list(collection_id, 3), true);929    });930}931932#[test]933fn nonprivileged_user_cannot_add_address_to_white_list() {934    new_test_ext().execute_with(|| {935        default_limits();936        937        let collection_id = create_test_collection(&CollectionMode::NFT, 1);938939        let origin2 = Origin::signed(2);940        assert_noop!(941            TemplateModule::add_to_white_list(origin2.clone(), collection_id, 3),942            Error::<Test>::NoPermission943        );944    });945}946947#[test]948fn nobody_can_add_address_to_white_list_of_nonexisting_collection() {949    new_test_ext().execute_with(|| {950        default_limits();951952        let origin1 = Origin::signed(1);953954        assert_noop!(955            TemplateModule::add_to_white_list(origin1.clone(), 1, 2),956            Error::<Test>::CollectionNotFound957        );958    });959}960961#[test]962fn nobody_can_add_address_to_white_list_of_deleted_collection() {963    new_test_ext().execute_with(|| {964        default_limits();965        966        let collection_id = create_test_collection(&CollectionMode::NFT, 1);967968        let origin1 = Origin::signed(1);969        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));970        assert_noop!(971            TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2),972            Error::<Test>::CollectionNotFound973        );974    });975}976977// If address is already added to white list, nothing happens978#[test]979fn address_is_already_added_to_white_list() {980    new_test_ext().execute_with(|| {981        default_limits();982        983        let collection_id = create_test_collection(&CollectionMode::NFT, 1);984        let origin1 = Origin::signed(1);985        986        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));987        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));988        assert_eq!(TemplateModule::white_list(collection_id, 2), true);989    });990}991992#[test]993fn owner_can_remove_address_from_white_list() {994    new_test_ext().execute_with(|| {995        default_limits();996        997        let collection_id = create_test_collection(&CollectionMode::NFT, 1);998999        let origin1 = Origin::signed(1);1000        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));1001        assert_ok!(TemplateModule::remove_from_white_list(1002            origin1.clone(),1003            collection_id,1004            21005        ));1006        assert_eq!(TemplateModule::white_list(collection_id, 2), false);1007    });1008}10091010#[test]1011fn admin_can_remove_address_from_white_list() {1012    new_test_ext().execute_with(|| {1013        default_limits();1014        1015        let collection_id = create_test_collection(&CollectionMode::NFT, 1);1016        let origin1 = Origin::signed(1);1017        let origin2 = Origin::signed(2);10181019        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));10201021        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 3));1022        assert_ok!(TemplateModule::remove_from_white_list(1023            origin2.clone(),1024            collection_id,1025            31026        ));1027        assert_eq!(TemplateModule::white_list(collection_id, 3), false);1028    });1029}10301031#[test]1032fn nonprivileged_user_cannot_remove_address_from_white_list() {1033    new_test_ext().execute_with(|| {1034        default_limits();1035        1036        let collection_id = create_test_collection(&CollectionMode::NFT, 1);1037        let origin1 = Origin::signed(1);1038        let origin2 = Origin::signed(2);10391040        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));1041        assert_noop!(1042            TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),1043            Error::<Test>::NoPermission1044        );1045        assert_eq!(TemplateModule::white_list(collection_id, 2), true);1046    });1047}10481049#[test]1050fn nobody_can_remove_address_from_white_list_of_nonexisting_collection() {1051    new_test_ext().execute_with(|| {1052        default_limits();1053        let origin1 = Origin::signed(1);10541055        assert_noop!(1056            TemplateModule::remove_from_white_list(origin1.clone(), 1, 2),1057            Error::<Test>::CollectionNotFound1058        );1059    });1060}10611062#[test]1063fn nobody_can_remove_address_from_white_list_of_deleted_collection() {1064    new_test_ext().execute_with(|| {1065        default_limits();1066        1067        let collection_id = create_test_collection(&CollectionMode::NFT, 1);1068        let origin1 = Origin::signed(1);1069        let origin2 = Origin::signed(2);10701071        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));1072        assert_ok!(TemplateModule::destroy_collection(origin1.clone(), collection_id));1073        assert_noop!(1074            TemplateModule::remove_from_white_list(origin2.clone(), collection_id, 2),1075            Error::<Test>::CollectionNotFound1076        );1077        assert_eq!(TemplateModule::white_list(collection_id, 2), false);1078    });1079}10801081// If address is already removed from white list, nothing happens1082#[test]1083fn address_is_already_removed_from_white_list() {1084    new_test_ext().execute_with(|| {1085        default_limits();1086        1087        let collection_id = create_test_collection(&CollectionMode::NFT, 1);1088        let origin1 = Origin::signed(1);10891090        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));1091        assert_ok!(TemplateModule::remove_from_white_list(1092            origin1.clone(),1093            collection_id,1094            21095        ));1096        assert_ok!(TemplateModule::remove_from_white_list(1097            origin1.clone(),1098            collection_id,1099            21100        ));1101        assert_eq!(TemplateModule::white_list(collection_id, 2), false);1102    });1103}11041105// If Public Access mode is set to WhiteList, tokens can’t be transferred from a non-whitelisted address with transfer or transferFrom (2 tests)1106#[test]1107fn white_list_test_1() {1108    new_test_ext().execute_with(|| {1109        default_limits();1110        1111        let collection_id = create_test_collection(&CollectionMode::NFT, 1);11121113        let origin1 = Origin::signed(1);1114        1115        let data = default_nft_data();1116        create_test_item(collection_id, &data.into());11171118        assert_ok!(TemplateModule::set_public_access_mode(1119            origin1.clone(),1120            collection_id,1121            AccessMode::WhiteList1122        ));1123        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));11241125        assert_noop!(1126            TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),1127            Error::<Test>::AddresNotInWhiteList1128        );1129    });1130}11311132#[test]1133fn white_list_test_2() {1134    new_test_ext().execute_with(|| {1135        default_limits();1136        1137        let collection_id = create_test_collection(&CollectionMode::NFT, 1);1138        let origin1 = Origin::signed(1);1139        1140        let data = default_nft_data();1141        create_test_item(collection_id, &data.into());11421143        assert_ok!(TemplateModule::set_public_access_mode(1144            origin1.clone(),1145            collection_id,1146            AccessMode::WhiteList1147        ));1148        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));1149        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));11501151        // do approve1152        assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1, 1));1153        assert_eq!(TemplateModule::approved(1, (1, 1, 1)), 1);11541155        assert_ok!(TemplateModule::remove_from_white_list(1156            origin1.clone(),1157            1,1158            11159        ));11601161        assert_noop!(1162            TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1),1163            Error::<Test>::AddresNotInWhiteList1164        );1165    });1166}11671168// If Public Access mode is set to WhiteList, tokens can’t be transferred to a non-whitelisted address with transfer or transferFrom (2 tests)1169#[test]1170fn white_list_test_3() {1171    new_test_ext().execute_with(|| {1172        default_limits();1173        1174        let collection_id = create_test_collection(&CollectionMode::NFT, 1);11751176        let origin1 = Origin::signed(1);1177        1178        let data = default_nft_data();1179        create_test_item(collection_id, &data.into());11801181        assert_ok!(TemplateModule::set_public_access_mode(1182            origin1.clone(),1183            collection_id,1184            AccessMode::WhiteList1185        ));1186        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));11871188        assert_noop!(1189            TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1),1190            Error::<Test>::AddresNotInWhiteList1191        );1192    });1193}11941195#[test]1196fn white_list_test_4() {1197    new_test_ext().execute_with(|| {1198        default_limits();1199        1200        let collection_id = create_test_collection(&CollectionMode::NFT, 1);12011202        let origin1 = Origin::signed(1);12031204        let data = default_nft_data();1205        create_test_item(collection_id, &data.into());12061207        assert_ok!(TemplateModule::set_public_access_mode(1208            origin1.clone(),1209            collection_id,1210            AccessMode::WhiteList1211        ));1212        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));1213        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));12141215        // do approve1216        assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1, 1));1217        assert_eq!(TemplateModule::approved(1, (1, 1, 1)), 1);12181219        assert_ok!(TemplateModule::remove_from_white_list(1220            origin1.clone(),1221            collection_id,1222            21223        ));12241225        assert_noop!(1226            TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1),1227            Error::<Test>::AddresNotInWhiteList1228        );1229    });1230}12311232// If Public Access mode is set to WhiteList, tokens can’t be destroyed by a non-whitelisted address (even if it owned them before enabling WhiteList mode)1233#[test]1234fn white_list_test_5() {1235    new_test_ext().execute_with(|| {1236        default_limits();1237        1238        let collection_id = create_test_collection(&CollectionMode::NFT, 1);12391240        let origin1 = Origin::signed(1);12411242        let data = default_nft_data();1243        create_test_item(collection_id, &data.into());12441245        assert_ok!(TemplateModule::set_public_access_mode(1246            origin1.clone(),1247            collection_id,1248            AccessMode::WhiteList1249        ));1250        assert_noop!(1251            TemplateModule::burn_item(origin1.clone(), 1, 1, 5),1252            Error::<Test>::AddresNotInWhiteList1253        );1254    });1255}12561257// If Public Access mode is set to WhiteList, token transfers can’t be Approved by a non-whitelisted address (see Approve method).1258#[test]1259fn white_list_test_6() {1260    new_test_ext().execute_with(|| {1261        default_limits();1262        1263        let collection_id = create_test_collection(&CollectionMode::NFT, 1);12641265        let origin1 = Origin::signed(1);12661267        let data = default_nft_data();1268        create_test_item(collection_id, &data.into());12691270        assert_ok!(TemplateModule::set_public_access_mode(1271            origin1.clone(),1272            collection_id,1273            AccessMode::WhiteList1274        ));12751276        // do approve1277        assert_noop!(1278            TemplateModule::approve(origin1.clone(), 1, 1, 1, 5),1279            Error::<Test>::AddresNotInWhiteList1280        );1281    });1282}12831284// If Public Access mode is set to WhiteList, tokens can be transferred from a whitelisted address with transfer or transferFrom (2 tests) and1285//          tokens can be transferred from a whitelisted address with transfer or transferFrom (2 tests)1286#[test]1287fn white_list_test_7() {1288    new_test_ext().execute_with(|| {1289        default_limits();1290        1291        let collection_id = create_test_collection(&CollectionMode::NFT, 1);12921293        let data = default_nft_data();1294        create_test_item(collection_id, &data.into());1295        1296        let origin1 = Origin::signed(1);12971298        assert_ok!(TemplateModule::set_public_access_mode(1299            origin1.clone(),1300            collection_id,1301            AccessMode::WhiteList1302        ));1303        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));1304        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));13051306        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1));1307    });1308}13091310#[test]1311fn white_list_test_8() {1312    new_test_ext().execute_with(|| {1313        default_limits();1314        1315        let collection_id = create_test_collection(&CollectionMode::NFT, 1);13161317        let data = default_nft_data();1318        create_test_item(collection_id, &data.into());1319        1320        let origin1 = Origin::signed(1);13211322        assert_ok!(TemplateModule::set_public_access_mode(1323            origin1.clone(),1324            collection_id,1325            AccessMode::WhiteList1326        ));1327        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 1));1328        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));13291330        // do approve1331        assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1, 5));1332        assert_eq!(TemplateModule::approved(1, (1, 1, 1)), 5);13331334        assert_ok!(TemplateModule::transfer_from(1335            origin1.clone(),1336            1,1337            2,1338            1,1339            1,1340            11341        ));1342    });1343}13441345// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens can be created by owner.1346#[test]1347fn white_list_test_9() {1348    new_test_ext().execute_with(|| {1349        default_limits();1350        1351        let collection_id = create_test_collection(&CollectionMode::NFT, 1);1352        let origin1 = Origin::signed(1);13531354        assert_ok!(TemplateModule::set_public_access_mode(1355            origin1.clone(),1356            collection_id,1357            AccessMode::WhiteList1358        ));1359        assert_ok!(TemplateModule::set_mint_permission(1360            origin1.clone(),1361            collection_id,1362            false1363        ));13641365        let data = default_nft_data();1366        create_test_item(collection_id, &data.into());1367    });1368}13691370// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens can be created by admin.1371#[test]1372fn white_list_test_10() {1373    new_test_ext().execute_with(|| {1374        default_limits();1375        1376        let collection_id = create_test_collection(&CollectionMode::NFT, 1);13771378        let origin1 = Origin::signed(1);1379        let origin2 = Origin::signed(2);13801381        assert_ok!(TemplateModule::set_public_access_mode(1382            origin1.clone(),1383            collection_id,1384            AccessMode::WhiteList1385        ));1386        assert_ok!(TemplateModule::set_mint_permission(1387            origin1.clone(),1388            collection_id,1389            false1390        ));13911392        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));13931394        assert_ok!(TemplateModule::create_item(1395            origin2.clone(),1396            collection_id,1397            2,1398            default_nft_data().into()1399        ));1400    });1401}14021403// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens cannot be created by non-privileged and white listed address.1404#[test]1405fn white_list_test_11() {1406    new_test_ext().execute_with(|| {1407        default_limits();1408        1409        let collection_id = create_test_collection(&CollectionMode::NFT, 1);14101411        let origin1 = Origin::signed(1);1412        let origin2 = Origin::signed(2);14131414        assert_ok!(TemplateModule::set_public_access_mode(1415            origin1.clone(),1416            collection_id,1417            AccessMode::WhiteList1418        ));1419        assert_ok!(TemplateModule::set_mint_permission(1420            origin1.clone(),1421            collection_id,1422            false1423        ));1424        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));14251426        assert_noop!(1427            TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),1428            Error::<Test>::PublicMintingNotAllowed1429        );1430    });1431}14321433// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens cannot be created by non-privileged and non-white listed address.1434#[test]1435fn white_list_test_12() {1436    new_test_ext().execute_with(|| {1437        default_limits();1438        1439        let collection_id = create_test_collection(&CollectionMode::NFT, 1);14401441        let origin1 = Origin::signed(1);1442        let origin2 = Origin::signed(2);14431444        assert_ok!(TemplateModule::set_public_access_mode(1445            origin1.clone(),1446            collection_id,1447            AccessMode::WhiteList1448        ));1449        assert_ok!(TemplateModule::set_mint_permission(1450            origin1.clone(),1451            collection_id,1452            false1453        ));14541455        assert_noop!(1456            TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),1457            Error::<Test>::PublicMintingNotAllowed1458        );1459    });1460}14611462// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens can be created by owner.1463#[test]1464fn white_list_test_13() {1465    new_test_ext().execute_with(|| {1466        default_limits();1467        1468        let collection_id = create_test_collection(&CollectionMode::NFT, 1);14691470        let origin1 = Origin::signed(1);14711472        assert_ok!(TemplateModule::set_public_access_mode(1473            origin1.clone(),1474            collection_id,1475            AccessMode::WhiteList1476        ));1477        assert_ok!(TemplateModule::set_mint_permission(1478            origin1.clone(),1479            collection_id,1480            true1481        ));14821483        let data = default_nft_data();1484        create_test_item(collection_id, &data.into());1485    });1486}14871488// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens can be created by admin.1489#[test]1490fn white_list_test_14() {1491    new_test_ext().execute_with(|| {1492        default_limits();1493        1494        let collection_id = create_test_collection(&CollectionMode::NFT, 1);14951496        let origin1 = Origin::signed(1);1497        let origin2 = Origin::signed(2);14981499        assert_ok!(TemplateModule::set_public_access_mode(1500            origin1.clone(),1501            collection_id,1502            AccessMode::WhiteList1503        ));1504        assert_ok!(TemplateModule::set_mint_permission(1505            origin1.clone(),1506            collection_id,1507            true1508        ));15091510        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));15111512        assert_ok!(TemplateModule::create_item(1513            origin2.clone(),1514            1,1515            2,1516            default_nft_data().into()1517        ));1518    });1519}15201521// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens cannot be created by non-privileged and non-white listed address.1522#[test]1523fn white_list_test_15() {1524    new_test_ext().execute_with(|| {1525        default_limits();1526        1527        let collection_id = create_test_collection(&CollectionMode::NFT, 1);15281529        let origin1 = Origin::signed(1);1530        let origin2 = Origin::signed(2);15311532        assert_ok!(TemplateModule::set_public_access_mode(1533            origin1.clone(),1534            collection_id,1535            AccessMode::WhiteList1536        ));1537        assert_ok!(TemplateModule::set_mint_permission(1538            origin1.clone(),1539            collection_id,1540            true1541        ));15421543        assert_noop!(1544            TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),1545            Error::<Test>::AddresNotInWhiteList1546        );1547    });1548}15491550// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens can be created by non-privileged and white listed address.1551#[test]1552fn white_list_test_16() {1553    new_test_ext().execute_with(|| {1554        default_limits();1555        1556        let collection_id = create_test_collection(&CollectionMode::NFT, 1);15571558        let origin1 = Origin::signed(1);1559        let origin2 = Origin::signed(2);15601561        assert_ok!(TemplateModule::set_public_access_mode(1562            origin1.clone(),1563            collection_id,1564            AccessMode::WhiteList1565        ));1566        assert_ok!(TemplateModule::set_mint_permission(1567            origin1.clone(),1568            collection_id,1569            true1570        ));1571        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), collection_id, 2));15721573        assert_ok!(TemplateModule::create_item(1574            origin2.clone(),1575            1,1576            2,1577            default_nft_data().into()1578        ));1579    });1580}15811582// Total number of collections. Positive test1583#[test]1584fn total_number_collections_bound() {1585    new_test_ext().execute_with(|| {1586        default_limits();1587        1588        create_test_collection(&CollectionMode::NFT, 1);1589    });1590}15911592// Total number of collections. Negotive test1593#[test]1594fn total_number_collections_bound_neg() {1595    new_test_ext().execute_with(|| {1596        default_limits();15971598        let origin1 = Origin::signed(1);15991600        for i in 0..default_collection_numbers_limit() {1601            create_test_collection(&CollectionMode::NFT, i + 1);1602        }16031604        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();1605        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();1606        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();16071608        // 11-th collection in chain. Expects error1609        assert_noop!(TemplateModule::create_collection(1610            origin1.clone(),1611            col_name1.clone(),1612            col_desc1.clone(),1613            token_prefix1.clone(),1614            CollectionMode::NFT1615        ), Error::<Test>::TotalCollectionsLimitExceeded);1616    });1617}16181619// Owned tokens by a single address. Positive test1620#[test]1621fn owned_tokens_bound() {1622    new_test_ext().execute_with(|| {1623        default_limits();1624        1625        let collection_id = create_test_collection(&CollectionMode::NFT, 1);16261627        let data = default_nft_data();1628        create_test_item(collection_id, &data.clone().into());1629        create_test_item(collection_id, &data.into());1630    });1631}16321633// Owned tokens by a single address. Negotive test1634#[test]1635fn owned_tokens_bound_neg() {1636    new_test_ext().execute_with(|| {1637        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1638            collection_numbers_limit: 10,1639            account_token_ownership_limit: 1,1640            collections_admins_limit: 5,1641            custom_data_limit: 2048,1642            nft_sponsor_transfer_timeout: 15,1643            fungible_sponsor_transfer_timeout: 15,1644            refungible_sponsor_transfer_timeout: 15,1645            const_on_chain_schema_limit: 1024,1646            offchain_schema_limit: 1024,1647            variable_on_chain_schema_limit: 1024,1648        }));1649        1650        let collection_id = create_test_collection(&CollectionMode::NFT, 1);16511652        let origin1 = Origin::signed(1);1653        let data = default_nft_data();1654        create_test_item(collection_id, &data.clone().into());16551656        assert_noop!(TemplateModule::create_item(1657            origin1.clone(),1658            1,1659            1,1660            data.into()1661        ),  Error::<Test>::AddressOwnershipLimitExceeded);1662    });1663}16641665// Number of collection admins. Positive test1666#[test]1667fn collection_admins_bound() {1668    new_test_ext().execute_with(|| {1669        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1670            collection_numbers_limit: 10,1671            account_token_ownership_limit: 10,1672            collections_admins_limit: 2,1673            custom_data_limit: 2048,1674            nft_sponsor_transfer_timeout: 15,1675            fungible_sponsor_transfer_timeout: 15,1676            refungible_sponsor_transfer_timeout: 15,1677            const_on_chain_schema_limit: 1024,1678            offchain_schema_limit: 1024,1679            variable_on_chain_schema_limit: 1024,1680        }));1681        1682        let collection_id = create_test_collection(&CollectionMode::NFT, 1);16831684        let origin1 = Origin::signed(1);1685        1686        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));1687        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3));1688    });1689}16901691// Number of collection admins. Negotive test1692#[test]1693fn collection_admins_bound_neg() {1694    new_test_ext().execute_with(|| {1695        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1696            collection_numbers_limit: 10,1697            account_token_ownership_limit: 1,1698            collections_admins_limit: 1,1699            custom_data_limit: 2048,1700            nft_sponsor_transfer_timeout: 15,1701            fungible_sponsor_transfer_timeout: 15,1702            refungible_sponsor_transfer_timeout: 15,1703            const_on_chain_schema_limit: 1024,1704            offchain_schema_limit: 1024,1705            variable_on_chain_schema_limit: 1024,1706        }));1707        1708        let collection_id = create_test_collection(&CollectionMode::NFT, 1);17091710        let origin1 = Origin::signed(1);17111712        assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 2));1713        assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), collection_id, 3), Error::<Test>::CollectionAdminsLimitExceeded);1714    });1715}17161717// NFT custom data size. Negative test const_data.1718#[test]1719fn custom_data_size_nft_const_data_bound_neg() {1720    new_test_ext().execute_with(|| {1721        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1722            collection_numbers_limit: 10,1723            account_token_ownership_limit: 10,1724            collections_admins_limit: 5,1725            custom_data_limit: 2,1726            nft_sponsor_transfer_timeout: 15,1727            fungible_sponsor_transfer_timeout: 15,1728            refungible_sponsor_transfer_timeout: 15,1729            const_on_chain_schema_limit: 1024,1730            offchain_schema_limit: 1024,1731            variable_on_chain_schema_limit: 1024,1732        }));1733        1734        let collection_id = create_test_collection(&CollectionMode::NFT, 1);17351736        let origin1 = Origin::signed(1);1737        let too_big_const_data = CreateItemData::NFT(CreateNftData{1738            const_data: vec![1, 2, 3, 4],1739            variable_data: vec![]1740        });17411742        assert_noop!(TemplateModule::create_item(1743            origin1.clone(),1744            collection_id,1745            1,1746            too_big_const_data1747        ), Error::<Test>::TokenConstDataLimitExceeded);1748    });1749}17501751// NFT custom data size. Negative test variable_data.1752#[test]1753fn custom_data_size_nft_variable_data_bound_neg() {1754    new_test_ext().execute_with(|| {1755        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1756            collection_numbers_limit: 10,1757            account_token_ownership_limit: 10,1758            collections_admins_limit: 5,1759            custom_data_limit: 2,1760            nft_sponsor_transfer_timeout: 15,1761            fungible_sponsor_transfer_timeout: 15,1762            refungible_sponsor_transfer_timeout: 15,1763            const_on_chain_schema_limit: 1024,1764            offchain_schema_limit: 1024,1765            variable_on_chain_schema_limit: 1024,1766        }));17671768        let collection_id = create_test_collection(&CollectionMode::NFT, 1);17691770        let origin1 = Origin::signed(1);1771        let too_big_const_data = CreateItemData::NFT(CreateNftData{1772            const_data: vec![],1773            variable_data: vec![1, 2, 3, 4]1774        });17751776        assert_noop!(TemplateModule::create_item(1777            origin1.clone(),1778            collection_id,1779            1,1780            too_big_const_data1781        ), Error::<Test>::TokenVariableDataLimitExceeded);1782    });1783}17841785// Re fungible custom data size. Negative test const_data.1786#[test]1787fn custom_data_size_re_fungible_const_data_bound_neg() {1788    new_test_ext().execute_with(|| {1789        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1790            collection_numbers_limit: 10,1791            account_token_ownership_limit: 10,1792            collections_admins_limit: 5,1793            custom_data_limit: 2,1794            nft_sponsor_transfer_timeout: 15,1795            fungible_sponsor_transfer_timeout: 15,1796            refungible_sponsor_transfer_timeout: 15,1797            const_on_chain_schema_limit: 1024,1798            offchain_schema_limit: 1024,1799            variable_on_chain_schema_limit: 1024,1800        }));18011802        let collection_id = create_test_collection(&CollectionMode::NFT, 1);18031804        let origin1 = Origin::signed(1);1805        let too_big_const_data = CreateItemData::NFT(CreateNftData{1806            const_data: vec![1, 2, 3, 4],1807            variable_data: vec![]1808        });18091810        assert_noop!(TemplateModule::create_item(1811            origin1.clone(),1812            collection_id,1813            1,1814            too_big_const_data1815        ), Error::<Test>::TokenConstDataLimitExceeded);1816    });1817}18181819// Re fungible custom data size. Negative test variable_data.1820#[test]1821fn custom_data_size_re_fungible_variable_data_bound_neg() {1822    new_test_ext().execute_with(|| {1823        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1824            collection_numbers_limit: 10,1825            account_token_ownership_limit: 10,1826            collections_admins_limit: 5,1827            custom_data_limit: 2,1828            nft_sponsor_transfer_timeout: 15,1829            fungible_sponsor_transfer_timeout: 15,1830            refungible_sponsor_transfer_timeout: 15,1831            const_on_chain_schema_limit: 1024,1832            offchain_schema_limit: 1024,1833            variable_on_chain_schema_limit: 1024,1834        }));18351836        let collection_id = create_test_collection(&CollectionMode::NFT, 1);18371838        let origin1 = Origin::signed(1);1839        let too_big_const_data = CreateItemData::NFT(CreateNftData{1840            const_data: vec![],1841            variable_data: vec![1, 2, 3, 4]1842        });18431844        assert_noop!(TemplateModule::create_item(1845            origin1.clone(),1846            collection_id,1847            1,1848            too_big_const_data1849        ), Error::<Test>::TokenVariableDataLimitExceeded);1850    });1851}1852// #endregion18531854#[test]1855fn set_const_on_chain_schema() {1856    new_test_ext().execute_with(|| {1857        default_limits();18581859        let collection_id = create_test_collection(&CollectionMode::NFT, 1);18601861        let origin1 = Origin::signed(1);1862        assert_ok!(TemplateModule::set_const_on_chain_schema(origin1, collection_id, b"test const on chain schema".to_vec()));18631864        assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, b"test const on chain schema".to_vec());1865        assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, b"".to_vec());1866    });1867}18681869#[test]1870fn set_variable_on_chain_schema() {1871    new_test_ext().execute_with(|| {1872        default_limits();1873        1874        let collection_id = create_test_collection(&CollectionMode::NFT, 1);18751876        let origin1 = Origin::signed(1);1877        assert_ok!(TemplateModule::set_variable_on_chain_schema(origin1, collection_id, b"test variable on chain schema".to_vec()));18781879        assert_eq!(TemplateModule::collection(collection_id).const_on_chain_schema, b"".to_vec());1880        assert_eq!(TemplateModule::collection(collection_id).variable_on_chain_schema, b"test variable on chain schema".to_vec());1881    });1882}18831884#[test]1885fn set_variable_meta_data_on_nft_token_stores_variable_meta_data() {1886    new_test_ext().execute_with(|| {1887        default_limits();18881889        let collection_id = create_test_collection(&CollectionMode::NFT, 1);18901891        let origin1 = Origin::signed(1);1892        1893        let data = default_nft_data();1894        create_test_item(1, &data.into());1895        1896        let variable_data = b"test set_variable_meta_data method.".to_vec();1897        assert_ok!(TemplateModule::set_variable_meta_data(origin1, collection_id, 1, variable_data.clone()));18981899        assert_eq!(TemplateModule::nft_item_id(collection_id, 1).variable_data, variable_data);1900    });1901}19021903#[test]1904fn set_variable_meta_data_on_re_fungible_token_stores_variable_meta_data() {1905    new_test_ext().execute_with(|| {1906        default_limits();19071908        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);19091910        let origin1 = Origin::signed(1);19111912        let data = default_re_fungible_data();1913        create_test_item(1, &data.into());19141915        let variable_data = b"test set_variable_meta_data method.".to_vec();1916        assert_ok!(TemplateModule::set_variable_meta_data(origin1, collection_id, 1, variable_data.clone()));19171918        assert_eq!(TemplateModule::refungible_item_id(collection_id, 1).variable_data, variable_data);1919    });1920}192119221923#[test]1924fn set_variable_meta_data_on_fungible_token_fails() {1925    new_test_ext().execute_with(|| {1926        default_limits();19271928        let collection_id = create_test_collection(&CollectionMode::Fungible(3), 1);19291930        let origin1 = Origin::signed(1);19311932        let data = default_fungible_data();1933        create_test_item(1, &data.into());19341935        let variable_data = b"test set_variable_meta_data method.".to_vec();1936        assert_noop!(TemplateModule::set_variable_meta_data(origin1, collection_id, 1, variable_data.clone()), Error::<Test>::CantStoreMetadataInFungibleTokens);1937    });1938}19391940#[test]1941fn set_variable_meta_data_on_nft_token_fails_for_big_data() {1942    new_test_ext().execute_with(|| {1943        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1944            collection_numbers_limit: default_collection_numbers_limit(),1945            account_token_ownership_limit: 10,1946            collections_admins_limit: 5,1947            custom_data_limit: 10,1948            nft_sponsor_transfer_timeout: 15,1949            fungible_sponsor_transfer_timeout: 15,1950            refungible_sponsor_transfer_timeout: 15,1951            const_on_chain_schema_limit: 1024,1952            offchain_schema_limit: 1024,1953            variable_on_chain_schema_limit: 1024,1954        }));19551956        let collection_id = create_test_collection(&CollectionMode::NFT, 1);19571958        let origin1 = Origin::signed(1);19591960        let data = default_nft_data();1961        create_test_item(1, &data.into());19621963        let variable_data = b"test set_variable_meta_data method, bigger than limits.".to_vec();1964        assert_noop!(TemplateModule::set_variable_meta_data(origin1, collection_id, 1, variable_data), Error::<Test>::TokenVariableDataLimitExceeded);1965    });1966}19671968#[test]1969fn set_variable_meta_data_on_re_fungible_token_fails_for_big_data() {1970    new_test_ext().execute_with(|| {1971        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 1972            collection_numbers_limit: default_collection_numbers_limit(),1973            account_token_ownership_limit: 10,1974            collections_admins_limit: 5,1975            custom_data_limit: 10,1976            nft_sponsor_transfer_timeout: 15,1977            fungible_sponsor_transfer_timeout: 15,1978            refungible_sponsor_transfer_timeout: 15,1979            const_on_chain_schema_limit: 1024,1980            offchain_schema_limit: 1024,1981            variable_on_chain_schema_limit: 1024,1982        }));198319841985        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);19861987        let origin1 = Origin::signed(1);19881989        let data = default_re_fungible_data();1990        create_test_item(1, &data.into());19911992        let variable_data = b"test set_variable_meta_data method, bigger than limits.".to_vec();1993        assert_noop!(TemplateModule::set_variable_meta_data(origin1, collection_id, 1, variable_data), Error::<Test>::TokenVariableDataLimitExceeded);1994    });1995}
modifiedruntime_types.jsondiffbeforeafterboth
--- a/runtime_types.json
+++ b/runtime_types.json
@@ -1,27 +1,4 @@
 {
-    "Schedule": {
-      "version": "u32",
-      "put_code_per_byte_cost": "Gas",
-      "grow_mem_cost": "Gas",
-      "regular_op_cost": "Gas",
-      "return_data_per_byte_cost": "Gas",
-      "event_data_per_byte_cost": "Gas",
-      "event_per_topic_cost": "Gas",
-      "event_base_cost": "Gas",
-      "call_base_cost": "Gas",
-      "instantiate_base_cost": "Gas",
-      "dispatch_base_cost": "Gas",
-      "sandbox_data_read_cost": "Gas",
-      "sandbox_data_write_cost": "Gas",
-      "transfer_cost": "Gas",
-      "instantiate_cost": "Gas",
-      "max_event_topics": "u32",
-      "max_stack_height": "u32",
-      "max_memory_pages": "u32",
-      "max_table_size": "u32",
-      "enable_println": "bool",
-      "max_subject_len": "u32"
-    },
     "AccessMode": {
       "_enum": [
         "Normal",
@@ -34,7 +11,7 @@
         "Invalid": null,
         "NFT": null,
         "Fungible": "DecimalPoints",
-        "ReFungible": "DecimalPoints"
+        "ReFungible": null
       }
     },
     "Ownership": {
@@ -84,7 +61,8 @@
     },
     "CreateReFungibleData": {
       "const_data": "Vec<u8>",
-      "variable_data": "Vec<u8>" 
+      "variable_data": "Vec<u8>",
+      "pieces": "u128"
     },
     "CreateItemData": {
       "_enum": {
@@ -117,15 +95,8 @@
       "AccountTokenOwnershipLimit": "u32",
       "SponsoredMintSize": "u32",
       "TokenLimit": "u32",
-      "SponsorTimeout": "u32"
-    },
-    "AccountInfo": "AccountInfoWithProviders",
-    "AccountInfoWithProviders": {
-      "nonce": "Index",
-      "consumers": "RefCount",
-      "providers": "RefCount",
-      "data": "AccountData"
+      "SponsorTimeout": "u32",
+      "OwnerCanTransfer": "bool",
+      "OwnerCanDestroy": "bool"
     }
-
-  }
-  
\ No newline at end of file
+}
\ No newline at end of file
modifiedtests/src/addCollectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/addCollectionAdmin.test.ts
+++ b/tests/src/addCollectionAdmin.test.ts
@@ -1,4 +1,9 @@
-import { ApiPromise } from '@polkadot/api';
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
+import { ApiPromise } from '@polkadot/api';
 import BN from 'bn.js';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
@@ -98,7 +103,7 @@
     });
   });
 
-  it('Add an admin to a collection that has reached the maximum number of admins limit', async () => {
+  it.only('Add an admin to a collection that has reached the maximum number of admins limit', async () => {
     await usingApi(async (api: ApiPromise) => {
       const Alice = privateKey('//Alice');
       const accounts = [
@@ -112,18 +117,18 @@
       ];
       const collectionId = await createCollectionExpectSuccess();
 
-      const chainLimit = await api.query.nft.chainLimit() as unknown as { collections_admins_limit: BN };
-      const chainLimitNumber = chainLimit.collections_admins_limit.toNumber();
-      expect(chainLimitNumber).to.be.equal(5);
+      const chainLimit = await api.query.nft.chainLimit() as unknown as { CollectionAdminsLimit: BN };
+      const chainAdminLimit = chainLimit.CollectionAdminsLimit.toNumber();
+      expect(chainAdminLimit).to.be.equal(5);
 
-      for (let i = 0; i < chainLimitNumber; i++) {
+      for (let i = 0; i < chainAdminLimit; i++) {
         const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, accounts[i]);
         await submitTransactionAsync(Alice, changeAdminTx);
         const adminListAfterAddAdmin: any = (await api.query.nft.adminList(collectionId));
         expect(adminListAfterAddAdmin).to.be.contains(accounts[i]);
       }
 
-      const tx = api.tx.nft.addCollectionAdmin(collectionId, accounts[chainLimitNumber]);
+      const tx = api.tx.nft.addCollectionAdmin(collectionId, accounts[chainAdminLimit]);
       await expect(submitTransactionExpectFailAsync(Alice, tx)).to.be.rejected;
     });
   });
modifiedtests/src/addToContractWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/addToContractWhiteList.test.ts
+++ b/tests/src/addToContractWhiteList.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import chai from "chai";
 import chaiAsPromised from 'chai-as-promised';
 import usingApi, { submitTransactionAsync, submitTransactionExpectFailAsync } from "./substrate/substrate-api";
modifiedtests/src/addToWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/addToWhiteList.test.ts
+++ b/tests/src/addToWhiteList.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { IKeyringPair } from '@polkadot/types/types';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
modifiedtests/src/approve.test.tsdiffbeforeafterboth
--- a/tests/src/approve.test.ts
+++ b/tests/src/approve.test.ts
@@ -34,7 +34,7 @@
       await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob);
       // reFungible
       const reFungibleCollectionId =
-        await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob);
     });
@@ -56,7 +56,7 @@
       await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 0);
       // reFungible
       const reFungibleCollectionId =
-        await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 1);
       await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 0);
@@ -95,7 +95,7 @@
       await approveExpectFail(fungibleCollectionId, 1, Alice, Bob);
       // reFungible
       const reFungibleCollectionId =
-        await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       await destroyCollectionExpectSuccess(reFungibleCollectionId);
       await approveExpectFail(reFungibleCollectionId, 1, Alice, Bob);
     });
@@ -113,7 +113,7 @@
       await approveExpectFail(fungibleCollectionId, 2, Alice, Bob);
       // reFungible
       const reFungibleCollectionId =
-        await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       await approveExpectFail(reFungibleCollectionId, 2, Alice, Bob);
     });
   });
@@ -132,7 +132,7 @@
       await approveExpectFail(fungibleCollectionId, newFungibleTokenId, Bob, Alice);
       // reFungible
       const reFungibleCollectionId =
-        await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, Bob, Alice);
     });
modifiedtests/src/burnItem.test.tsdiffbeforeafterboth
--- a/tests/src/burnItem.test.ts
+++ b/tests/src/burnItem.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';
 import { Keyring } from "@polkadot/api";
 import { IKeyringPair } from "@polkadot/types/types";
@@ -70,7 +75,7 @@
   });
   it('Burn item in ReFungible collection', async () => {
     const createMode = 'ReFungible';
-    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 2 }});
+    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode }});
     const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
 
     await usingApi(async (api) => {
@@ -91,7 +96,7 @@
 
   it('Burn owned portion of item in ReFungible collection', async () => {
     const createMode = 'ReFungible';
-    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 2 }});
+    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
     const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
 
     await usingApi(async (api) => {
@@ -107,7 +112,7 @@
       const tx = api.tx.nft.burnItem(collectionId, tokenId, 0);
       const events2 = await submitTransactionAsync(bob, tx);
       const result2 = getGenericResult(events2);
-  
+
       // Get balances 
       const balance: any = (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON();
       // console.log(balance);
modifiedtests/src/change-collection-owner.test.tsdiffbeforeafterboth
--- a/tests/src/change-collection-owner.test.ts
+++ b/tests/src/change-collection-owner.test.ts
@@ -1,4 +1,9 @@
-import chai from 'chai';
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
+import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
 import privateKey from './substrate/privateKey';
 import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from "./substrate/substrate-api";
modifiedtests/src/confirmSponsorship.test.tsdiffbeforeafterboth
--- a/tests/src/confirmSponsorship.test.ts
+++ b/tests/src/confirmSponsorship.test.ts
@@ -115,7 +115,7 @@
   });
 
   it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async () => {
-    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0 }});
+    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
     await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
 
@@ -247,7 +247,7 @@
   });
 
   it('ReFungible: Sponsoring is rate limited', async () => {
-    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0 }});
+    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
     await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
 
modifiedtests/src/contracts.test.tsdiffbeforeafterboth
--- a/tests/src/contracts.test.ts
+++ b/tests/src/contracts.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import chai from "chai";
 import chaiAsPromised from 'chai-as-promised';
 import usingApi, { submitTransactionAsync, submitTransactionExpectFailAsync } from "./substrate/substrate-api";
modifiedtests/src/createCollection.test.tsdiffbeforeafterboth
--- a/tests/src/createCollection.test.ts
+++ b/tests/src/createCollection.test.ts
@@ -28,7 +28,7 @@
     await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
   });
   it('Create new ReFungible collection', async () => {
-    await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+    await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
   });
 });
 
modifiedtests/src/createItem.test.tsdiffbeforeafterboth
--- a/tests/src/createItem.test.ts
+++ b/tests/src/createItem.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { default as usingApi } from './substrate/substrate-api';
 import { Keyring } from "@polkadot/api";
 import { IKeyringPair } from "@polkadot/types/types";
@@ -28,7 +33,7 @@
   });
   it('Create new item in ReFungible collection', async () => {
     const createMode = 'ReFungible';
-    const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}});
+    const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
     await createItemExpectSuccess(alice, newCollectionID, createMode);
   });
 });
modifiedtests/src/createMultipleItems.test.tsdiffbeforeafterboth
--- a/tests/src/createMultipleItems.test.ts
+++ b/tests/src/createMultipleItems.test.ts
@@ -56,14 +56,14 @@
 
   it('Create  0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
     await usingApi(async (api: ApiPromise) => {
-      const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+      const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const itemsListIndexBefore = await api.query.nft.itemListIndex(collectionId) as unknown as BN;
       expect(itemsListIndexBefore.toNumber()).to.be.equal(0);
       const Alice = privateKey('//Alice');
       const args = [
-        { Refungible: ['0x31', '0x31'] },
-        { Refungible: ['0x32', '0x32'] },
-        { Refungible: ['0x33', '0x33'] },
+        {refungible: {const_data: [0x31], variable_data: [0x31], pieces: 1}},
+        {refungible: {const_data: [0x32], variable_data: [0x32], pieces: 1}},
+        {refungible: {const_data: [0x33], variable_data: [0x33], pieces: 1}},
       ];
       const createMultipleItemsTx = await api.tx.nft
         .createMultipleItems(collectionId, Alice.address, args);
@@ -137,7 +137,7 @@
 
       // ReFungible
       const collectionIdReFungible =
-        await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const argsReFungible = [
         { ReFungible: ['1'.repeat(2049), '1'.repeat(2049)] },
         { ReFungible: ['2'.repeat(2049), '2'.repeat(2049)] },
modifiedtests/src/destroyCollection.test.tsdiffbeforeafterboth
--- a/tests/src/destroyCollection.test.ts
+++ b/tests/src/destroyCollection.test.ts
@@ -1,12 +1,14 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
-import { default as usingApi, submitTransactionAsync } from "./substrate/substrate-api";
-import { createCollectionExpectSuccess, createCollectionExpectFailure, destroyCollectionExpectSuccess, destroyCollectionExpectFailure } from "./util/helpers";
-import type { AccountId, EventRecord } from '@polkadot/types/interfaces';
-import privateKey from './substrate/privateKey';
+import { default as usingApi } from "./substrate/substrate-api";
+import { createCollectionExpectSuccess, destroyCollectionExpectSuccess, destroyCollectionExpectFailure } from "./util/helpers";
 
 chai.use(chaiAsPromised);
-const expect = chai.expect;
 
 describe('integration test: ext. destroyCollection():', () => {
   it('NFT collection can be destroyed', async () => {
@@ -18,7 +20,7 @@
     await destroyCollectionExpectSuccess(collectionId);
   });
   it('ReFungible collection can be destroyed', async () => {
-    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await destroyCollectionExpectSuccess(collectionId);
   });
 });
modifiedtests/src/enableContractSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/enableContractSponsoring.test.ts
+++ b/tests/src/enableContractSponsoring.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { IKeyringPair } from '@polkadot/types/types';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
modifiedtests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/removeCollectionAdmin.test.ts
+++ b/tests/src/removeCollectionAdmin.test.ts
@@ -1,5 +1,9 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { ApiPromise } from '@polkadot/api';
-import BN from 'bn.js';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
 import privateKey from './substrate/privateKey';
addedtests/src/removeFromContractWhiteList.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/removeFromContractWhiteList.test.ts
@@ -0,0 +1,72 @@
+import privateKey from "./substrate/privateKey";
+import usingApi from "./substrate/substrate-api";
+import { deployFlipper, toggleFlipValueExpectFailure, toggleFlipValueExpectSuccess } from "./util/contracthelpers";
+import { addToContractWhiteListExpectSuccess, isWhitelistedInContract, removeFromContractWhiteListExpectFailure, removeFromContractWhiteListExpectSuccess, toggleContractWhitelistExpectSuccess } from "./util/helpers";
+import { IKeyringPair } from '@polkadot/types/types';
+import { expect } from "chai";
+
+describe('Integration Test removeFromContractWhiteList', () => {
+    let bob: IKeyringPair;
+
+    before(() => {
+        bob = privateKey('//Bob');
+    });
+
+    it('user is no longer whitelisted after removal', async () => {
+        await usingApi(async (api) => {
+            const [flipper, deployer] = await deployFlipper(api);
+
+            await addToContractWhiteListExpectSuccess(deployer, flipper.address, bob.address);
+            await removeFromContractWhiteListExpectSuccess(deployer, flipper.address, bob.address);
+
+            expect(await isWhitelistedInContract(flipper.address, bob.address)).to.be.false;
+        });
+    });
+
+    it('user can\'t execute contract after removal', async () => {
+        await usingApi(async (api) => {
+            const [flipper, deployer] = await deployFlipper(api);
+            await toggleContractWhitelistExpectSuccess(deployer, flipper.address, true);
+
+            await addToContractWhiteListExpectSuccess(deployer, flipper.address, bob.address);
+            await toggleFlipValueExpectSuccess(bob, flipper);
+
+            await removeFromContractWhiteListExpectSuccess(deployer, flipper.address, bob.address);
+            await toggleFlipValueExpectFailure(bob, flipper);
+        });
+    });
+
+    it('can be called twice', async () => {
+        await usingApi(async (api) => {
+            const [flipper, deployer] = await deployFlipper(api);
+
+            await addToContractWhiteListExpectSuccess(deployer, flipper.address, bob.address);
+            await removeFromContractWhiteListExpectSuccess(deployer, flipper.address, bob.address);
+            await removeFromContractWhiteListExpectSuccess(deployer, flipper.address, bob.address);
+        });
+    });
+});
+
+describe('Negative Integration Test removeFromContractWhiteList', () => {
+    let alice: IKeyringPair;
+    let bob: IKeyringPair;
+
+    before(() => {
+        alice = privateKey('//Alice');
+        bob = privateKey('//Bob');
+    });
+
+    it('fails when called with non-contract address', async () => {
+        await usingApi(async () => {
+            await removeFromContractWhiteListExpectFailure(alice, alice.address, bob.address);
+        });
+    });
+
+    it('fails when executed by non owner', async () => {
+        await usingApi(async (api) => {
+            const [flipper, _] = await deployFlipper(api);
+
+            await removeFromContractWhiteListExpectFailure(alice, flipper.address, bob.address);
+        });
+    });
+});
modifiedtests/src/removeFromWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/removeFromWhiteList.test.ts
+++ b/tests/src/removeFromWhiteList.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
 import { default as usingApi } from './substrate/substrate-api';
modifiedtests/src/setCollectionLimits.test.tsdiffbeforeafterboth
--- a/tests/src/setCollectionLimits.test.ts
+++ b/tests/src/setCollectionLimits.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 // https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
 import { ApiPromise, Keyring } from '@polkadot/api';
 import { IKeyringPair } from '@polkadot/types/types';
modifiedtests/src/setCollectionSponsor.test.tsdiffbeforeafterboth
--- a/tests/src/setCollectionSponsor.test.ts
+++ b/tests/src/setCollectionSponsor.test.ts
@@ -9,7 +9,6 @@
 import { createCollectionExpectSuccess, setCollectionSponsorExpectSuccess, destroyCollectionExpectSuccess, setCollectionSponsorExpectFailure } from "./util/helpers";
 import { Keyring } from "@polkadot/api";
 import { IKeyringPair } from "@polkadot/types/types";
-import type { AccountId } from '@polkadot/types/interfaces';
 
 chai.use(chaiAsPromised);
 const expect = chai.expect;
@@ -34,7 +33,7 @@
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
   });
   it('Set ReFungible collection sponsor', async () => {
-    const collectionId = await createCollectionExpectSuccess({ mode: {type: 'ReFungible', decimalPoints: 0} });
+    const collectionId = await createCollectionExpectSuccess({ mode: {type: 'ReFungible'} });
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
   });
 
modifiedtests/src/setConstOnChainSchema.test.tsdiffbeforeafterboth
--- a/tests/src/setConstOnChainSchema.test.ts
+++ b/tests/src/setConstOnChainSchema.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { Keyring } from '@polkadot/api';
 import { IKeyringPair } from '@polkadot/types/types';
 import chai from 'chai';
modifiedtests/src/setContractSponsoringRateLimit.test.tsdiffbeforeafterboth
--- a/tests/src/setContractSponsoringRateLimit.test.ts
+++ b/tests/src/setContractSponsoringRateLimit.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { IKeyringPair } from '@polkadot/types/types';
 import privateKey from './substrate/privateKey';
 import usingApi from './substrate/substrate-api';
modifiedtests/src/setMintPermission.test.tsdiffbeforeafterboth
--- a/tests/src/setMintPermission.test.ts
+++ b/tests/src/setMintPermission.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { IKeyringPair } from '@polkadot/types/types';
 import privateKey from './substrate/privateKey';
 import usingApi from './substrate/substrate-api';
modifiedtests/src/setPublicAccessMode.test.tsdiffbeforeafterboth
--- a/tests/src/setPublicAccessMode.test.ts
+++ b/tests/src/setPublicAccessMode.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 // https://unique-network.readthedocs.io/en/latest/jsapi.html#setschemaversion
 import { ApiPromise, Keyring } from '@polkadot/api';
 import { IKeyringPair } from '@polkadot/types/types';
modifiedtests/src/setSchemaVersion.test.tsdiffbeforeafterboth
--- a/tests/src/setSchemaVersion.test.ts
+++ b/tests/src/setSchemaVersion.test.ts
@@ -1,7 +1,11 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 // https://unique-network.readthedocs.io/en/latest/jsapi.html#setschemaversion
 import { ApiPromise, Keyring } from '@polkadot/api';
 import { IKeyringPair } from '@polkadot/types/types';
-import BN from 'bn.js';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
 import usingApi, {submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api';
modifiedtests/src/setVariableMetaData.test.tsdiffbeforeafterboth
--- a/tests/src/setVariableMetaData.test.ts
+++ b/tests/src/setVariableMetaData.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { IKeyringPair } from '@polkadot/types/types';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
modifiedtests/src/setVariableOnChainSchema.test.tsdiffbeforeafterboth
--- a/tests/src/setVariableOnChainSchema.test.ts
+++ b/tests/src/setVariableOnChainSchema.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { Keyring } from '@polkadot/api';
 import { IKeyringPair } from '@polkadot/types/types';
 import chai from 'chai';
modifiedtests/src/toggleContractWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/toggleContractWhiteList.test.ts
+++ b/tests/src/toggleContractWhiteList.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import chai from "chai";
 import chaiAsPromised from 'chai-as-promised';
 import usingApi, { submitTransactionAsync, submitTransactionExpectFailAsync } from "./substrate/substrate-api";
modifiedtests/src/transfer.test.tsdiffbeforeafterboth
--- a/tests/src/transfer.test.ts
+++ b/tests/src/transfer.test.ts
@@ -63,7 +63,7 @@
     });
   });
 
-  it('Create collection, balance transfers and check balance', async () => {
+  it('User can transfer owned token', async () => {
     await usingApi(async (api) => {
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
@@ -77,10 +77,10 @@
       await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');
       // reFungible
       const reFungibleCollectionId = await
-        createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await transferExpectSuccess(reFungibleCollectionId,
-        newReFungibleTokenId, Alice, Bob, 1, 'ReFungible');
+        newReFungibleTokenId, Alice, Bob, 100, 'ReFungible');
     });
   });
 });
@@ -119,7 +119,7 @@
     await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');
     // reFungible
     const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
     await destroyCollectionExpectSuccess(reFungibleCollectionId);
     await transferExpectFail(reFungibleCollectionId,
@@ -134,7 +134,7 @@
     await transferExpectFail(fungibleCollectionId, 2, Alice, Bob, 1, 'Fungible');
     // reFungible
     const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await transferExpectFail(reFungibleCollectionId,
       2, Alice, Bob, 1, 'ReFungible');
   });
@@ -151,7 +151,7 @@
     await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');
     // reFungible
     const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
     await burnItemExpectSuccess(Alice, reFungibleCollectionId, newReFungibleTokenId, 1);
     await transferExpectFail(reFungibleCollectionId,
@@ -168,7 +168,7 @@
     await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Charlie, Bob, 1, 'Fungible');
     // reFungible
     const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
     await transferExpectFail(reFungibleCollectionId,
       newReFungibleTokenId, Charlie, Bob, 1, 'ReFungible');
modifiedtests/src/transferFrom.test.tsdiffbeforeafterboth
--- a/tests/src/transferFrom.test.ts
+++ b/tests/src/transferFrom.test.ts
@@ -25,7 +25,7 @@
     await usingApi(async (api: ApiPromise) => {
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
-      const Charlie = privateKey('//CHARLIE');
+      const Charlie = privateKey('//Charlie');
       // nft
       const nftCollectionId = await createCollectionExpectSuccess();
       const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
@@ -40,11 +40,11 @@
       await transferFromExpectSuccess(fungibleCollectionId, newFungibleTokenId, Bob, Alice, Charlie, 1, 'Fungible');
       // reFungible
       const reFungibleCollectionId = await
-        createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
-      await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob);
+      await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 100);
       await transferFromExpectSuccess(reFungibleCollectionId,
-        newReFungibleTokenId, Bob, Alice, Charlie, 1, 'ReFungible');
+        newReFungibleTokenId, Bob, Alice, Charlie, 100, 'ReFungible');
     });
   });
 });
@@ -54,7 +54,7 @@
     await usingApi(async (api: ApiPromise) => {
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
-      const Charlie = privateKey('//CHARLIE');
+      const Charlie = privateKey('//Charlie');
       // nft
       const nftCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;
       await approveExpectFail(nftCollectionCount + 1, 1, Alice, Bob);
@@ -96,7 +96,7 @@
     await usingApi(async (api: ApiPromise) => {
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
-      const Charlie = privateKey('//CHARLIE');
+      const Charlie = privateKey('//Charlie');
       // nft
       const nftCollectionId = await createCollectionExpectSuccess();
       const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
@@ -109,7 +109,7 @@
       await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, Bob, Alice, Charlie, 1);
       // reFungible
       const reFungibleCollectionId = await
-        createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await transferFromExpectFail(reFungibleCollectionId,
         newReFungibleTokenId, Bob, Alice, Charlie, 1);
@@ -120,7 +120,7 @@
     await usingApi(async (api: ApiPromise) => {
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
-      const Charlie = privateKey('//CHARLIE');
+      const Charlie = privateKey('//Charlie');
       // nft
       const nftCollectionId = await createCollectionExpectSuccess();
       const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
@@ -135,7 +135,7 @@
       await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, Bob, Alice, Charlie, 2);
       // reFungible
       const reFungibleCollectionId = await
-        createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob);
       await transferFromExpectFail(reFungibleCollectionId,
@@ -147,8 +147,8 @@
     await usingApi(async (api: ApiPromise) => {
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
-      const Charlie = privateKey('//CHARLIE');
-      const Dave = privateKey('//DAVE');
+      const Charlie = privateKey('//Charlie');
+      const Dave = privateKey('//Dave');
       // nft
       const nftCollectionId = await createCollectionExpectSuccess();
       const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
@@ -174,7 +174,7 @@
       }
       // reFungible
       const reFungibleCollectionId = await
-        createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       try {
         await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, Dave, Bob);
modifiedtests/src/types.tsdiffbeforeafterboth
--- a/tests/src/types.ts
+++ b/tests/src/types.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import BN from 'bn.js';
 
 export interface ICollectionInterface {
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -124,23 +124,8 @@
 
 interface ReFungible {
   type: 'ReFungible';
-  decimalPoints: number;
-}
-
-interface Nft {
-  type: 'NFT'
-}
-
-interface Fungible {
-  type: 'Fungible',
-  decimalPoints: number
 }
 
-interface ReFungible {
-  type: 'ReFungible',
-  decimalPoints: number
-}
-
 type CollectionMode = Nft | Fungible | ReFungible | Invalid;
 
 export type CreateCollectionParams = {
@@ -174,7 +159,7 @@
     } else if (mode.type === 'Fungible') {
       modeprm = {fungible: mode.decimalPoints};
     } else if (mode.type === 'ReFungible') {
-      modeprm = {refungible: mode.decimalPoints};
+      modeprm = {refungible: null};
     } else if (mode.type === 'Invalid') {
       modeprm = {invalid: null};
     }
@@ -216,7 +201,7 @@
   } else if (mode.type === 'Fungible') {
     modeprm = {fungible: mode.decimalPoints};
   } else if (mode.type === 'ReFungible') {
-    modeprm = {refungible: mode.decimalPoints};
+    modeprm = {refungible: null};
   } else if (mode.type === 'Invalid') {
     modeprm = {invalid: null};
   }
@@ -424,6 +409,54 @@
   });
 }
 
+export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enabled: boolean) {
+  await usingApi(async (api) => {
+    const tx = api.tx.nft.toggleContractWhiteList(contractAddress, true);
+    const events = await submitTransactionAsync(sender, tx);
+    const result = getGenericResult(events);
+
+    expect(result.success).to.be.true;
+  });
+}
+
+export async function isWhitelistedInContract(contractAddress: AccountId | string, user: string) {
+  let whitelisted: boolean = false;
+  await usingApi(async (api) => {
+    whitelisted = (await api.query.nft.contractWhiteList(contractAddress, user)).toJSON() as boolean;
+  });
+  return whitelisted;
+}
+
+export async function addToContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: string) {
+  await usingApi(async (api) => {
+    const tx = api.tx.nft.addToContractWhiteList(contractAddress, user);
+    const events = await submitTransactionAsync(sender, tx);
+    const result = getGenericResult(events);
+
+    expect(result.success).to.be.true;
+  });
+}
+
+export async function removeFromContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: string) {
+  await usingApi(async (api) => {
+    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress, user);
+    const events = await submitTransactionAsync(sender, tx);
+    const result = getGenericResult(events);
+
+    expect(result.success).to.be.true;
+  });
+}
+
+export async function removeFromContractWhiteListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: string) {
+  await usingApi(async (api) => {
+    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress, user);
+    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
+    const result = getGenericResult(events);
+
+    expect(result.success).to.be.false;
+  });
+}
+
 export async function setVariableMetaDataExpectSuccess(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {
   await usingApi(async (api) => {
     const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));
@@ -620,6 +653,9 @@
     if (createMode === 'Fungible') {
       const createData = {fungible: {value: 10}};
       tx = api.tx.nft.createItem(collectionId, owner, createData);
+    } else if (createMode === 'ReFungible') {
+      const createData = {refungible: {const_data: [], variable_data: [], pieces: 100}};
+      tx = api.tx.nft.createItem(collectionId, owner, createData);
     } else {
       tx = api.tx.nft.createItem(collectionId, owner, createMode);
     }