git.delta.rocks / unique-network / refs/commits / 31f605387c25

difftreelog

NFTPAR-96: Batch Minting.

sotmorskiy2020-10-16parent: #0dbd5dd.patch.diff
in: master

2 files changed

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,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,
744 /// 744 ///
745 /// * owner: Address, initial owner of the NFT.745 /// * owner: Address, initial owner of the NFT.
746 #[weight = 0]746 #[weight = 0]
747 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {747 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {
748748
749 let sender = ensure_signed(origin)?;749 let sender = ensure_signed(origin)?;
750
750 Self::collection_exists(collection_id)?;751 Self::collection_exists(collection_id)?;
752
751 let target_collection = <Collection<T>>::get(collection_id);753 let target_collection = <Collection<T>>::get(collection_id);
752754
753 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {755 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;
754 ensure!(target_collection.mint_mode == true, "Public minting is not allowed for this collection");
755 Self::check_white_list(collection_id, &owner)?;756 Self::validate_create_item_args(&target_collection, &properties)?;
756 Self::check_white_list(collection_id, &sender)?;757 Self::create_item_no_validation(collection_id, &target_collection, &properties, &owner)?;
757 }758
758
759 match target_collection.mode
760 {
761 CollectionMode::NFT(_) => {
762
763 // check size
764 ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");759 Ok(())
765760 }
766 // Create nft item761
762 /// This method creates multiple instances of NFT Collection created with CreateCollection method.
763 ///
764 /// # Permissions
765 ///
766 /// * Collection Owner.
767 /// * Collection Admin.
768 /// * Anyone if
769 /// * White List is enabled, and
770 /// * Address is added to white list, and
771 /// * MintPermission is enabled (see SetMintPermission method)
772 ///
773 /// # Arguments
774 ///
775 /// * collection_id: ID of the collection.
776 ///
777 /// * properties: Array items properties. Each property is an array of bytes itself, see [create_item].
778 ///
779 /// * owner: Address, initial owner of the NFT.
767 let item = NftItemType {780 #[weight = 0]
768 collection: collection_id,781 pub fn create_multiple_items(origin, collection_id: u64, properties: Vec<Vec<u8>>, owner: T::AccountId) -> DispatchResult {
769 owner: owner,782
770 data: properties.clone(),
771 };
772
773 Self::add_nft_item(item)?;
774
775 },
776 CollectionMode::Fungible(_) => {
777
778 // check size
779 ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type");783 ensure!(properties.len() > 0, "Length of items properties must be greater than 0.");
780
781 let item = FungibleItemType {784 let sender = ensure_signed(origin)?;
782 collection: collection_id,
783 owner: owner,
784 value: (10 as u128).pow(target_collection.decimal_points)
785 };
786785
787 Self::add_fungible_item(item)?;786 Self::collection_exists(collection_id)?;
788 },
789 CollectionMode::ReFungible(_, _) => {
790
791 // check size
792 ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");
793
794 let mut owner_list = Vec::new();787 let target_collection = <Collection<T>>::get(collection_id);
788
795 let value = (10 as u128).pow(target_collection.decimal_points);789 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;
796 owner_list.push(Ownership {owner: owner.clone(), fraction: value});790
797
798 let item = ReFungibleItemType {
799 collection: collection_id,
800 owner: owner_list,
801 data: properties.clone()791 for prop in &properties {
802 };
803
804 Self::add_refungible_item(item)?;792 Self::validate_create_item_args(&target_collection, prop)?;
805 },793 }
806 _ => { ensure!(1 == 0,"just error"); }794 for prop in &properties {
807
808 };
809
810 // call event
811 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));795 Self::create_item_no_validation(collection_id, &target_collection, prop, &owner)?;
796 }
812797
813 Ok(())798 Ok(())
814 }799 }
815800
816 /// Destroys a concrete instance of NFT.801 /// Destroys a concrete instance of NFT.
817 /// 802 ///
10791064
1080impl<T: Trait> Module<T> {1065impl<T: Trait> Module<T> {
1066
1067 fn can_create_items_in_collection(collection_id: u64, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {
1068
1069 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
1070 ensure!(collection.mint_mode == true, "Public minting is not allowed for this collection");
1071 Self::check_white_list(collection_id, owner)?;
1072 Self::check_white_list(collection_id, sender)?;
1073 }
1074
1075 Ok(())
1076 }
1077
1078 fn validate_create_item_args(collection: &CollectionType<T::AccountId>, properties: &Vec<u8>) -> DispatchResult {
1079
1080 match collection.mode
1081 {
1082 CollectionMode::NFT(_) => {
1083
1084 // check size
1085 ensure!(collection.custom_data_size >= properties.len() as u32, "Size of item is too large")
1086 },
1087 CollectionMode::Fungible(_) => {
1088
1089 // check size
1090 ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type")
1091 },
1092 CollectionMode::ReFungible(_, _) => {
1093
1094 // check size
1095 ensure!(collection.custom_data_size >= properties.len() as u32, "Size of item is too large")
1096 },
1097 _ => {
1098 fail!("Unexpected collection mode")
1099 }
1100 }
1101
1102 Ok(())
1103 }
1104
1105 fn create_item_no_validation(collection_id: u64, collection: &CollectionType<T::AccountId>, properties: &Vec<u8>, owner: &T::AccountId) -> DispatchResult {
1106 match collection.mode
1107 {
1108 CollectionMode::NFT(_) => {
1109
1110 // Create nft item
1111 let item = NftItemType {
1112 collection: collection_id,
1113 owner: owner.clone(),
1114 data: properties.clone(),
1115 };
1116
1117 Self::add_nft_item(item)?;
1118
1119 },
1120 CollectionMode::Fungible(_) => {
1121
1122 let item = FungibleItemType {
1123 collection: collection_id,
1124 owner: owner.clone(),
1125 value: (10 as u128).pow(collection.decimal_points)
1126 };
1127
1128 Self::add_fungible_item(item)?;
1129 },
1130 CollectionMode::ReFungible(_, _) => {
1131
1132 let mut owner_list = Vec::new();
1133 let value = (10 as u128).pow(collection.decimal_points);
1134 owner_list.push(Ownership {owner: owner.clone(), fraction: value});
1135
1136 let item = ReFungibleItemType {
1137 collection: collection_id,
1138 owner: owner_list,
1139 data: properties.clone()
1140 };
1141
1142 Self::add_refungible_item(item)?;
1143 },
1144 _ => { ensure!(1 == 0,"just error"); }
1145
1146 };
1147
1148 // call event
1149 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));
1150
1151 Ok(())
1152 }
1153
1081 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1154 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {
1082 let current_index = <ItemListIndex>::get(item.collection)1155 let current_index = <ItemListIndex>::get(item.collection)
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -44,7 +44,51 @@
     });
 }
 
+// Use cases tests region
+// #region
 #[test]
+fn create_nft_multiple_items() {
+    new_test_ext().execute_with(|| {
+        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+        let mode: CollectionMode = CollectionMode::NFT(2000);
+
+        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
+            collection_numbers_limit: 10,
+            account_token_ownership_limit: 10,
+            collections_admins_limit: 5,
+            custom_data_limit: 2048,
+            nft_sponsor_transfer_timeout: 15,
+            fungible_sponsor_transfer_timeout: 15,
+            refungible_sponsor_transfer_timeout: 15,          
+        }));
+
+        let origin1 = Origin::signed(1);
+        assert_ok!(TemplateModule::create_collection(
+            origin1.clone(),
+            col_name1.clone(),
+            col_desc1.clone(),
+            token_prefix1.clone(),
+            mode
+        ));
+        assert_eq!(TemplateModule::collection(1).owner, 1);
+
+        let properties = [[1, 2, 3].to_vec(), [3, 2, 1].to_vec(), [3, 3, 3].to_vec()].to_vec();
+
+        assert_ok!(TemplateModule::create_multiple_items(
+            origin1.clone(),
+            1,
+            properties.clone(),
+            1
+        ));
+        for (index, data) in properties.iter().enumerate() {
+            assert_eq!(TemplateModule::nft_item_id(1, (index + 1) as u64).data, *data);
+        }
+    });
+}
+
+#[test]
 fn create_refungible_item() {
     new_test_ext().execute_with(|| {
         let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
@@ -93,6 +137,57 @@
 }
 
 #[test]
+fn create_multiple_refungible_items() {
+    new_test_ext().execute_with(|| {
+        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+        let mode: CollectionMode = CollectionMode::ReFungible(2000, 3);
+
+        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
+            collection_numbers_limit: 10,
+            account_token_ownership_limit: 10,
+            collections_admins_limit: 5,
+            custom_data_limit: 2048,
+            nft_sponsor_transfer_timeout: 15,
+            fungible_sponsor_transfer_timeout: 15,
+            refungible_sponsor_transfer_timeout: 15,          
+        }));
+
+        let origin1 = Origin::signed(1);
+        assert_ok!(TemplateModule::create_collection(
+            origin1.clone(),
+            col_name1.clone(),
+            col_desc1.clone(),
+            token_prefix1.clone(),
+            mode
+        ));
+        assert_eq!(TemplateModule::collection(1).owner, 1);
+
+        let properties = [[1, 2, 3].to_vec(), [3, 2, 1].to_vec(), [3, 3, 3].to_vec()].to_vec();
+
+        assert_ok!(TemplateModule::create_multiple_items(
+            origin1.clone(),
+            1,
+            properties.clone(),
+            1
+        ));
+        for (index, data) in properties.iter().enumerate() {
+
+            let item = TemplateModule::refungible_item_id(1, (index + 1) as u64);
+            assert_eq!(item.data, *data);
+            assert_eq!(
+                item.owner[0],
+                Ownership {
+                    owner: 1,
+                    fraction: 1000
+                }
+            );
+        }
+    });
+}
+
+#[test]
 fn create_fungible_item() {
     new_test_ext().execute_with(|| {
         let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
@@ -127,12 +222,55 @@
             1
         ));
         assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);
-        assert_eq!(TemplateModule::balance_count(1, 1), 1000);
-        assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
     });
 }
 
 #[test]
+fn create_multiple_fungible_items() {
+    new_test_ext().execute_with(|| {
+        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+        let mode: CollectionMode = CollectionMode::Fungible(3);
+
+        assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 
+            collection_numbers_limit: 10,
+            account_token_ownership_limit: 10,
+            collections_admins_limit: 5,
+            custom_data_limit: 2048,
+            nft_sponsor_transfer_timeout: 15,
+            fungible_sponsor_transfer_timeout: 15,
+            refungible_sponsor_transfer_timeout: 15,          
+        }));
+
+        let origin1 = Origin::signed(1);
+        assert_ok!(TemplateModule::create_collection(
+            origin1.clone(),
+            col_name1.clone(),
+            col_desc1.clone(),
+            token_prefix1.clone(),
+            mode
+        ));
+        assert_eq!(TemplateModule::collection(1).owner, 1);
+
+        let properties = [[].to_vec(), [].to_vec(), [].to_vec()].to_vec();
+
+        assert_ok!(TemplateModule::create_multiple_items(
+            origin1.clone(),
+            1,
+            properties.clone(),
+            1
+        ));
+        
+        for (index, _) in properties.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(|| {
         let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();