git.delta.rocks / unique-network / refs/commits / 73335ba4b181

difftreelog

Merge pull request #10 from usetech-llc/feature/NFTPAR-96

Greg Zaitsev2020-11-26parents: #38074f1 #5f15b48.patch.diff
in: master
Feature/nftpar-96

3 files changed

modifiedpallets/nft/src/benchmarking.rsdiffbeforeafterboth
--- a/pallets/nft/src/benchmarking.rs
+++ b/pallets/nft/src/benchmarking.rs
@@ -165,7 +165,7 @@
             let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
             let mode: CollectionMode = CollectionMode::NFT;
             let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
-            let nft_data = CreateNftData {
+            let mut nft_data = CreateNftData {
                 const_data: vec![],
                 variable_data: vec![]
             };
@@ -173,7 +173,7 @@
                 nft_data.const_data.push(10);
                 nft_data.variable_data.push(10);
             }
-            let mut data = CreateItemData::NFT(nft_data);
+            let data = CreateItemData::NFT(nft_data);
             Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
 
         }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data)
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
10pub use frame_support::{10pub use frame_support::{
11 construct_runtime, decl_event, decl_module, decl_storage,11 construct_runtime, decl_event, decl_module, decl_storage,
12 dispatch::DispatchResult,12 dispatch::DispatchResult,
13 ensure, parameter_types, fail,13 ensure, fail, parameter_types,
14 traits::{14 traits::{
15 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,15 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,
16 Randomness, WithdrawReason,16 Randomness, WithdrawReason,
22 },22 },
23 IsSubType, StorageValue,23 IsSubType, StorageValue,
24};24};
25// use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};
2625
27use frame_system::{self as system, ensure_signed, ensure_root};26use frame_system::{self as system, ensure_signed, ensure_root};
28use sp_runtime::sp_std::prelude::Vec;27use sp_runtime::sp_std::prelude::Vec;
489 }488 }
490489
491 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.490 /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.
492 /// 491 ///
493 /// # Permissions492 /// # Permissions
494 /// 493 ///
495 /// * Collection Owner.494 /// * Collection Owner.
829 // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]828 // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]
830829
831 #[weight = T::WeightInfo::create_item(data.len())]830 #[weight = T::WeightInfo::create_item(data.len())]
832 pub fn create_item(origin, collection_id: u64, owner: T::AccountId, data: CreateItemData) -> DispatchResult {831 pub fn create_item(origin, collection_id: u64, owner: T::AccountId, data: CreateItemData) -> DispatchResult {
833832
834 let sender = ensure_signed(origin)?;833 let sender = ensure_signed(origin)?;
834
835 Self::collection_exists(collection_id)?;835 Self::collection_exists(collection_id)?;
836
836 let target_collection = <Collection<T>>::get(collection_id);837 let target_collection = <Collection<T>>::get(collection_id);
837838
838 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {839 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;
839 ensure!(target_collection.mint_mode == true, "Public minting is not allowed for this collection.");
840 Self::check_white_list(collection_id, &owner)?;840 Self::validate_create_item_args(&target_collection, &data)?;
841 Self::check_white_list(collection_id, &sender)?;841 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;
842 }842
843843 Ok(())
844 match target_collection.mode844 }
845 {845
846 /// This method creates multiple instances of NFT Collection created with CreateCollection method.
847 ///
848 /// # Permissions
849 ///
850 /// * Collection Owner.
851 /// * Collection Admin.
852 /// * Anyone if
853 /// * White List is enabled, and
854 /// * Address is added to white list, and
855 /// * MintPermission is enabled (see SetMintPermission method)
856 ///
857 /// # Arguments
858 ///
859 /// * collection_id: ID of the collection.
860 ///
861 /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].
862 ///
863 /// * owner: Address, initial owner of the NFT.
846 CollectionMode::NFT => {864 #[weight = T::WeightInfo::create_item(items_data.into_iter()
847 if let CreateItemData::NFT(data) = data {865 .map(|data| { data.len() })
848 // check sizes
849 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, "const_data exceeded data limit.");
850 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, "variable_data exceeded data limit.");866 .sum())]
851
852 // Create nft item
853 let item = NftItemType {
854 collection: collection_id,867 pub fn create_multiple_items(origin, collection_id: u64, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {
855 owner: owner,868
856 const_data: data.const_data.clone(),869 ensure!(items_data.len() > 0, "Length of items properties must be greater than 0.");
857 variable_data: data.variable_data.clone()
858 };
859
860 Self::add_nft_item(item)?;
861
862 } else {
863 fail!("Not NFT item data used to mint in NFT collection.");
864 }
865 },
866 CollectionMode::Fungible(_) => {
867 if let CreateItemData::Fungible(_) = data {870 let sender = ensure_signed(origin)?;
868 871
869 let item = FungibleItemType {
870 collection: collection_id,
871 owner: owner,
872 value: (10 as u128).pow(target_collection.decimal_points)
873 };
874
875 Self::add_fungible_item(item)?;872 Self::collection_exists(collection_id)?;
876 } else {
877 fail!("Not Fungible item data used to mint in Fungible collection.");
878 }
879 },
880 CollectionMode::ReFungible(_) => {
881 if let CreateItemData::ReFungible(data) = data {873 let target_collection = <Collection<T>>::get(collection_id);
882 874
883 // check sizes
884 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, "const_data exceeded data limit.");
885 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, "variable_data exceeded data limit.");875 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;
886 876
877 for data in &items_data {
887 let mut owner_list = Vec::new();878 Self::validate_create_item_args(&target_collection, data)?;
888 let value = (10 as u128).pow(target_collection.decimal_points);879 }
889 owner_list.push(Ownership {owner: owner.clone(), fraction: value});880 for data in &items_data {
890
891 let item = ReFungibleItemType {
892 collection: collection_id,881 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;
893 owner: owner_list,882 }
894 const_data: data.const_data.clone(),
895 variable_data: data.variable_data.clone()
896 };
897
898 Self::add_refungible_item(item)?;
899 } else {
900 fail!("Not Re Fungible item data used to mint in Re Fungible collection.");
901 }
902 },
903 _ => { ensure!(1 == 0,"Unexpected collection type."); }
904 };
905
906 // call event
907 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));
908883
909 Ok(())884 Ok(())
910 }885 }
911886
912 /// Destroys a concrete instance of NFT.887 /// Destroys a concrete instance of NFT.
913 /// 888 ///
13061281
1307impl<T: Trait> Module<T> {1282impl<T: Trait> Module<T> {
1283
1284 fn can_create_items_in_collection(collection_id: u64, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {
1285
1286 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
1287 ensure!(collection.mint_mode == true, "Public minting is not allowed for this collection");
1288 Self::check_white_list(collection_id, owner)?;
1289 Self::check_white_list(collection_id, sender)?;
1290 }
1291
1292 Ok(())
1293 }
1294
1295 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {
1296 match target_collection.mode
1297 {
1298 CollectionMode::NFT => {
1299 if let CreateItemData::NFT(data) = data {
1300 // check sizes
1301 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, "const_data exceeded data limit.");
1302 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, "variable_data exceeded data limit.");
1303 } else {
1304 fail!("Not NFT item data used to mint in NFT collection.");
1305 }
1306 },
1307 CollectionMode::Fungible(_) => {
1308 if let CreateItemData::Fungible(_) = data {
1309 } else {
1310 fail!("Not Fungible item data used to mint in Fungible collection.");
1311 }
1312 },
1313 CollectionMode::ReFungible(_) => {
1314 if let CreateItemData::ReFungible(data) = data {
1315
1316 // check sizes
1317 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, "const_data exceeded data limit.");
1318 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, "variable_data exceeded data limit.");
1319 } else {
1320 fail!("Not Re Fungible item data used to mint in Re Fungible collection.");
1321 }
1322 },
1323 _ => { fail!("Unexpected collection type."); }
1324 };
1325
1326 Ok(())
1327 }
1328
1329 fn create_item_no_validation(collection_id: u64, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {
1330 match data
1331 {
1332 CreateItemData::NFT(data) => {
1333 let item = NftItemType {
1334 collection: collection_id,
1335 owner,
1336 const_data: data.const_data,
1337 variable_data: data.variable_data
1338 };
1339
1340 Self::add_nft_item(item)?;
1341 },
1342 CreateItemData::Fungible(_) => {
1343 let item = FungibleItemType {
1344 collection: collection_id,
1345 owner,
1346 value: (10 as u128).pow(collection.decimal_points)
1347 };
1348
1349 Self::add_fungible_item(item)?;
1350 },
1351 CreateItemData::ReFungible(data) => {
1352 let mut owner_list = Vec::new();
1353 let value = (10 as u128).pow(collection.decimal_points);
1354 owner_list.push(Ownership {owner: owner.clone(), fraction: value});
1355
1356 let item = ReFungibleItemType {
1357 collection: collection_id,
1358 owner: owner_list,
1359 const_data: data.const_data,
1360 variable_data: data.variable_data
1361 };
1362
1363 Self::add_refungible_item(item)?;
1364 }
1365 };
1366
1367
1368 // call event
1369 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));
1370
1371 Ok(())
1372 }
1373
1308 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1374 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {
1309 let current_index = <ItemListIndex>::get(item.collection)1375 let current_index = <ItemListIndex>::get(item.collection)
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -87,6 +87,32 @@
     });
 }
 
+// Use cases tests region
+// #region
+#[test]
+fn create_nft_multiple_items() {
+    new_test_ext().execute_with(|| {
+        default_limits();
+        
+        create_test_collection(&CollectionMode::NFT, 1);
+
+        let origin1 = Origin::signed(1);
+
+        let items_data = vec![default_nft_data(), default_nft_data(), default_nft_data()];
+
+        assert_ok!(TemplateModule::create_multiple_items(
+            origin1.clone(),
+            1,
+            1,
+            items_data.clone().into_iter().map(|d| { d.into() }).collect()
+        ));
+        for (index, data) in items_data.iter().enumerate() {
+            assert_eq!(TemplateModule::nft_item_id(1, (index + 1) as u64).const_data.to_vec(), data.const_data);
+            assert_eq!(TemplateModule::nft_item_id(1, (index + 1) as u64).variable_data.to_vec(), data.variable_data);
+        }
+    });
+}
+
 #[test]
 fn create_refungible_item() {
     new_test_ext().execute_with(|| {
@@ -114,6 +140,39 @@
 }
 
 #[test]
+fn create_multiple_refungible_items() {
+    new_test_ext().execute_with(|| {
+        default_limits();
+        
+        create_test_collection(&CollectionMode::ReFungible(3), 1);
+
+        let origin1 = Origin::signed(1);
+
+        let items_data = vec![default_re_fungible_data(), default_re_fungible_data(), default_re_fungible_data()];
+
+        assert_ok!(TemplateModule::create_multiple_items(
+            origin1.clone(),
+            1,
+            1,
+            items_data.clone().into_iter().map(|d| { d.into() }).collect()
+        ));
+        for (index, data) in items_data.iter().enumerate() {
+
+            let item = TemplateModule::refungible_item_id(1, (index + 1) as u64);
+            assert_eq!(item.const_data.to_vec(), data.const_data);
+            assert_eq!(item.variable_data.to_vec(), data.variable_data);
+            assert_eq!(
+                item.owner[0],
+                Ownership {
+                    owner: 1,
+                    fraction: 1000
+                }
+            );
+        }
+    });
+}
+
+#[test]
 fn create_fungible_item() {
     new_test_ext().execute_with(|| {
         default_limits();
@@ -124,12 +183,36 @@
         create_test_item(collection_id, &data.into());
 
         assert_eq!(TemplateModule::fungible_item_id(collection_id, 1).owner, 1);
-        assert_eq!(TemplateModule::balance_count(1, 1), 1000);
-        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
     });
 }
 
 #[test]
+fn create_multiple_fungible_items() {
+    new_test_ext().execute_with(|| {
+        default_limits();
+
+        create_test_collection(&CollectionMode::Fungible(3), 1);
+
+        let origin1 = Origin::signed(1);
+
+        let items_data = vec![default_fungible_data(), default_fungible_data(), default_fungible_data()];
+
+        assert_ok!(TemplateModule::create_multiple_items(
+            origin1.clone(),
+            1,
+            1,
+            items_data.clone().into_iter().map(|d| { d.into() }).collect()
+        ));
+        
+        for (index, _) in items_data.iter().enumerate() {
+            assert_eq!(TemplateModule::fungible_item_id(1, (index + 1) as u64).owner, 1);
+        }
+        assert_eq!(TemplateModule::balance_count(1, 1), 3000);
+        assert_eq!(TemplateModule::address_tokens(1, 1), [1, 2, 3]);
+    });
+}
+
+#[test]
 fn transfer_fungible_item() {
     new_test_ext().execute_with(|| {
         default_limits();
@@ -1333,7 +1416,7 @@
 
         assert_noop!(
             TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),
-            "Public minting is not allowed for this collection."
+            "Public minting is not allowed for this collection"
         );
     });
 }
@@ -1362,7 +1445,7 @@
 
         assert_noop!(
             TemplateModule::create_item(origin2.clone(), 1, 2, default_nft_data().into()),
-            "Public minting is not allowed for this collection."
+            "Public minting is not allowed for this collection"
         );
     });
 }