git.delta.rocks / unique-network / refs/commits / 72221d0d47e3

difftreelog

Merge pull request #6 from usetech-llc/feature/white_list_nft_62-64

usetech-llc2020-09-25parents: #8d30d14 #0053d9a.patch.diff
in: master
Feature/white list nft 62 64

4 files changed

modifiedREADME.mddiffbeforeafterboth
142 "enable_println": "bool",142 "enable_println": "bool",
143 "max_subject_len": "u32"143 "max_subject_len": "u32"
144 },144 },
145 "AccessMode": {
146 "_enum": [
147 "Normal",
148 "WhiteList"
149 ]
150 },
145 "CollectionMode": {151 "CollectionMode": {
146 "_enum": {152 "_enum": {
147 "Invalid": null,153 "Invalid": null,
181 "CollectionType": {187 "CollectionType": {
182 "Owner": "AccountId",188 "Owner": "AccountId",
183 "Mode": "CollectionMode",189 "Mode": "CollectionMode",
184 "Access": "u8",190 "Access": "AccessMode",
185 "DecimalPoints": "u32",191 "DecimalPoints": "u32",
186 "Name": "Vec<u16>",192 "Name": "Vec<u16>",
187 "Description": "Vec<u16>",193 "Description": "Vec<u16>",
188 "TokenPrefix": "Vec<u8>",194 "TokenPrefix": "Vec<u8>",
189 "CustomDataSize": "u32",195 "CustomDataSize": "u32",
196 "MintMode": "bool",
190 "OffchainSchema": "Vec<u8>",197 "OffchainSchema": "Vec<u8>",
191 "Sponsor": "AccountId",198 "Sponsor": "AccountId",
192 "UnconfirmedSponsor": "AccountId"199 "UnconfirmedSponsor": "AccountId"
196 "LookupSource": "AccountId",203 "LookupSource": "AccountId",
197 "Weight": "u64"204 "Weight": "u64"
198}205}
206
199```207```
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -97,6 +97,7 @@
     pub description: Vec<u16>, // 256 include null escape char
     pub token_prefix: Vec<u8>, // 16 include null escape char
     pub custom_data_size: u32,
+    pub mint_mode: bool,
     pub offchain_schema: Vec<u8>,
     pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender
     pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship
@@ -178,9 +179,6 @@
         pub NftItemList get(fn nft_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;
         pub FungibleItemList get(fn fungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;
         pub ReFungibleItemList get(fn refungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;
-
-        // Active vesting list
-        // pub VestingList get(fn vesting): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => VestingItem<T::AccountId, T::Moment>;
 
         /// Index list
         pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;
@@ -209,7 +207,7 @@
 
         fn on_initialize(now: T::BlockNumber) -> Weight {
 
-            if ChainVersion::get() == 0
+            if ChainVersion::get() < 2
             {
                 let value = NextCollectionID::get();
                 CreatedCollectionCount::put(value);
@@ -224,11 +222,11 @@
         // @param customDataSz size of custom data in each collection item
         // returns collection ID
         #[weight = 0]
-        pub fn create_collection(   origin,
-                                    collection_name: Vec<u16>,
-                                    collection_description: Vec<u16>,
-                                    token_prefix: Vec<u8>,
-                                    mode: CollectionMode) -> DispatchResult {
+        pub fn create_collection(origin,
+                                 collection_name: Vec<u16>,
+                                 collection_description: Vec<u16>,
+                                 token_prefix: Vec<u8>,
+                                 mode: CollectionMode) -> DispatchResult {
 
             // Anyone can create a collection
             let who = ensure_signed(origin)?;
@@ -271,6 +269,7 @@
                 owner: who.clone(),
                 name: name,
                 mode: mode.clone(),
+                mint_mode: false,
                 access: AccessMode::Normal,
                 description: description,
                 decimal_points: decimal_points,
@@ -309,6 +308,73 @@
         }
 
         #[weight = 0]
+        pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{
+
+            let sender = ensure_signed(origin)?;
+            Self::check_owner_or_admin_permissions(collection_id, sender)?;
+
+            let mut white_list_collection: Vec<T::AccountId>;
+            if <WhiteList<T>>::contains_key(collection_id) {
+                white_list_collection = <WhiteList<T>>::get(collection_id);
+                if !white_list_collection.contains(&address.clone())
+                {
+                    white_list_collection.push(address.clone());
+                }
+            }
+            else {
+                white_list_collection = Vec::new();
+                white_list_collection.push(address.clone());
+            }
+
+            <WhiteList<T>>::insert(collection_id, white_list_collection);
+            Ok(())
+        }
+
+        #[weight = 0]
+        pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{
+
+            let sender = ensure_signed(origin)?;
+            Self::check_owner_or_admin_permissions(collection_id, sender)?;
+
+            if <WhiteList<T>>::contains_key(collection_id) {
+                let mut white_list_collection = <WhiteList<T>>::get(collection_id);
+                if white_list_collection.contains(&address.clone())
+                {
+                    white_list_collection.retain(|i| *i != address.clone());
+                    <WhiteList<T>>::insert(collection_id, white_list_collection);
+                }
+            }
+
+            Ok(())
+        }
+
+        #[weight = 0]
+        pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult
+        {
+            let sender = ensure_signed(origin)?;
+
+            Self::check_owner_permissions(collection_id, sender)?;
+            let mut target_collection = <Collection<T>>::get(collection_id);
+            target_collection.access = mode;
+            <Collection<T>>::insert(collection_id, target_collection);
+
+            Ok(())
+        }
+
+        #[weight = 0]
+        pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult
+        {
+            let sender = ensure_signed(origin)?;
+
+            Self::check_owner_permissions(collection_id, sender)?;
+            let mut target_collection = <Collection<T>>::get(collection_id);
+            target_collection.mint_mode = mint_permission;
+            <Collection<T>>::insert(collection_id, target_collection);
+
+            Ok(())
+        }
+
+        #[weight = 0]
         pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
@@ -405,9 +471,14 @@
         pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
+            Self::collection_exists(collection_id)?;
             let target_collection = <Collection<T>>::get(collection_id);
-            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
 
+            if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
+                ensure!(target_collection.mint_mode == true, "Collection is not in mint mode");
+                Self::check_white_list(collection_id, owner.clone())?;
+            }
+
             match target_collection.mode
             {
                 CollectionMode::NFT(_) => {
@@ -469,10 +540,13 @@
         pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
+            Self::collection_exists(collection_id)?;
             let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);
             if !item_owner
             {
-                Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;
+                if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {  
+                    Self::check_white_list(collection_id, sender.clone())?;
+                }
             }
             let target_collection = <Collection<T>>::get(collection_id);
 
@@ -494,11 +568,10 @@
         pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id), "Only item owner can call transfer method");
-
+            Self::check_white_list(collection_id, sender.clone())?;
+            Self::check_white_list(collection_id, recipient.clone())?;
             let target_collection = <Collection<T>>::get(collection_id);
 
-            // TODO: implement other modes
             match target_collection.mode
             {
                 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,
@@ -518,7 +591,10 @@
             // amount param stub
             let amount = 100000000;
 
-            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id), "Only item owner can call transfer method");
+            let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);
+            if !item_owner {
+                Self::check_white_list(collection_id, approved.clone())?;
+            }
 
             let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));
             if list_exists {
@@ -545,22 +621,21 @@
 
             let sender = ensure_signed(origin)?;
             let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone()));
-            if approved_list_exists
-            {
-                let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));
-                let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());
-                ensure!(opt_item.is_some(), "No approve found");
-                ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");
 
-                // remove approve
-                let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))
-                    .into_iter().filter(|i| i.approved != sender.clone()).collect();
-                <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);
-            }
-            else
-            {
-                Self::check_owner_or_admin_permissions(collection_id, sender)?;
-            }
+            ensure!(approved_list_exists, "Only approved addresses can call this method");
+
+            Self::check_white_list(collection_id, from.clone())?;
+            Self::check_white_list(collection_id, recipient.clone())?;
+
+            let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));
+            let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());
+            ensure!(opt_item.is_some(), "No approve found");
+            ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");
+
+            // remove approve
+            let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))
+                .into_iter().filter(|i| i.approved != sender.clone()).collect();
+            <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);
 
             let target_collection = <Collection<T>>::get(collection_id);
 
@@ -675,11 +750,7 @@
         Ok(())
     }
 
-    fn burn_refungible_item(
-        collection_id: u64,
-        item_id: u64,
-        owner: T::AccountId,
-    ) -> DispatchResult {
+    fn burn_refungible_item(collection_id: u64, item_id: u64, owner: T::AccountId) -> DispatchResult {
         ensure!(
             <ReFungibleItemList<T>>::contains_key(collection_id, item_id),
             "Item does not exists"
@@ -770,25 +841,27 @@
         Ok(())
     }
 
-    fn check_owner_or_admin_permissions(
-        collection_id: u64,
-        subject: T::AccountId,
-    ) -> DispatchResult {
-        Self::collection_exists(collection_id)?;
+    fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {
 
         let target_collection = <Collection<T>>::get(collection_id);
-        let is_owner = subject == target_collection.owner;
-
-        let no_perm_mes = "You do not have permissions to modify this collection";
+        let mut result: bool = subject == target_collection.owner;
         let exists = <AdminList<T>>::contains_key(collection_id);
 
-        if !is_owner {
-            ensure!(exists, no_perm_mes);
-            ensure!(
-                <AdminList<T>>::get(collection_id).contains(&subject),
-                no_perm_mes
-            );
+        if !result & exists {
+            if <AdminList<T>>::get(collection_id).contains(&subject) {
+                result = true
+            }
         }
+
+        result
+    }
+
+    fn check_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {
+        
+        Self::collection_exists(collection_id)?;
+        let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());
+
+        ensure!(result, "You do not have permissions to modify this collection");
         Ok(())
     }
 
@@ -812,6 +885,16 @@
         }
     }
 
+    fn check_white_list(collection_id: u64, address: T::AccountId) -> DispatchResult {
+
+        let mes = "Address is not in white list";
+        ensure!(<WhiteList<T>>::contains_key(collection_id), mes);
+        let wl = <WhiteList<T>>::get(collection_id);
+        ensure!(wl.contains(&address.clone()), mes);
+
+        Ok(())
+    }
+
     fn transfer_fungible(
         collection_id: u64,
         item_id: u64,
@@ -819,6 +902,12 @@
         owner: T::AccountId,
         new_owner: T::AccountId,
     ) -> DispatchResult {
+
+        ensure!(
+            <FungibleItemList<T>>::contains_key(collection_id, item_id),
+            "Item not exists"
+        );
+
         let full_item = <FungibleItemList<T>>::get(collection_id, item_id);
         let amount = full_item.value;
 
@@ -903,6 +992,12 @@
         owner: T::AccountId,
         new_owner: T::AccountId,
     ) -> DispatchResult {
+
+        ensure!(
+            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),
+            "Item not exists"
+        );
+
         let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);
         let item = full_item
             .owner
@@ -983,6 +1078,12 @@
         sender: T::AccountId,
         new_owner: T::AccountId,
     ) -> DispatchResult {
+    
+        ensure!(
+            <NftItemList<T>>::contains_key(collection_id, item_id),
+            "Item not exists"
+        );
+
         let mut item = <NftItemList<T>>::get(collection_id, item_id);
 
         ensure!(
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -1,6 +1,6 @@
 // Tests to be written here
 use crate::mock::*;
-use crate::{ApprovePermissions, CollectionMode, Ownership};
+use crate::{ApprovePermissions, CollectionMode, AccessMode, Ownership};
 use frame_support::{assert_noop, assert_ok};
 
 #[test]
@@ -321,10 +321,11 @@
         assert_eq!(TemplateModule::balance_count(1, 1), 1);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
 
-        assert_noop!(
-            TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),
-            "You do not have permissions to modify this collection"
-        );
+        assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+        assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
 
         // do approve
         assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
@@ -390,10 +391,11 @@
         assert_eq!(TemplateModule::balance_count(1, 1), 1000);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
 
-        assert_noop!(
-            TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),
-            "You do not have permissions to modify this collection"
-        );
+        assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+        assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
 
         // do approve
         assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
@@ -461,10 +463,11 @@
         assert_eq!(TemplateModule::balance_count(1, 1), 1000);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
 
-        assert_noop!(
-            TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),
-            "You do not have permissions to modify this collection"
-        );
+        assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+        assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
 
         // do approve
         assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
@@ -573,7 +576,6 @@
         let mode: CollectionMode = CollectionMode::NFT(2000);
 
         let origin1 = Origin::signed(1);
-        let origin2 = Origin::signed(2);
         assert_ok!(TemplateModule::create_collection(
             origin1.clone(),
             col_name1.clone(),
@@ -583,7 +585,7 @@
         ));
         assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
         assert_ok!(TemplateModule::create_item(
-            origin2.clone(),
+            origin1.clone(),
             1,
             [1, 2, 3].to_vec(),
             1
@@ -614,7 +616,6 @@
         let mode: CollectionMode = CollectionMode::Fungible(3);
 
         let origin1 = Origin::signed(1);
-        let origin2 = Origin::signed(2);
         assert_ok!(TemplateModule::create_collection(
             origin1.clone(),
             col_name1.clone(),
@@ -624,7 +625,7 @@
         ));
         assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
         assert_ok!(TemplateModule::create_item(
-            origin2.clone(),
+            origin1.clone(),
             1,
             [].to_vec(),
             1
@@ -661,6 +662,11 @@
             token_prefix1.clone(),
             mode
         ));
+        
+        assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+        assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
+
         assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
         assert_ok!(TemplateModule::create_item(
             origin2.clone(),
@@ -928,6 +934,13 @@
         // approve
         assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
         assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);
+
+        assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+        assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+        assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
+
         assert_ok!(TemplateModule::transfer_from(
             origin2.clone(),
             1,
modifiedruntime/src/lib.rsdiffbeforeafterboth
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -111,7 +111,7 @@
     spec_name: create_runtime_str!("nft"),
     impl_name: create_runtime_str!("nft"),
     authoring_version: 1,
-    spec_version: 1,
+    spec_version: 2,
     impl_version: 1,
     apis: RUNTIME_API_VERSIONS,
     transaction_version: 1,