difftreelog
NFTPAR-96: Batch Minting.
in: master
2 files changed
pallets/nft/src/lib.rsdiffbeforeafterboth--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -10,7 +10,7 @@
pub use frame_support::{
construct_runtime, decl_event, decl_module, decl_storage,
dispatch::DispatchResult,
- ensure, parameter_types,
+ ensure, fail, parameter_types,
traits::{
Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,
Randomness, WithdrawReason,
@@ -747,68 +747,53 @@
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);
-
- if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
- ensure!(target_collection.mint_mode == true, "Public minting is not allowed for this collection");
- Self::check_white_list(collection_id, &owner)?;
- Self::check_white_list(collection_id, &sender)?;
- }
- match target_collection.mode
- {
- CollectionMode::NFT(_) => {
+ Self::collection_exists(collection_id)?;
- // check size
- ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");
+ let target_collection = <Collection<T>>::get(collection_id);
- // Create nft item
- let item = NftItemType {
- collection: collection_id,
- owner: owner,
- data: properties.clone(),
- };
-
- Self::add_nft_item(item)?;
-
- },
- CollectionMode::Fungible(_) => {
-
- // check size
- ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type");
+ Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;
+ Self::validate_create_item_args(&target_collection, &properties)?;
+ Self::create_item_no_validation(collection_id, &target_collection, &properties, &owner)?;
- let item = FungibleItemType {
- collection: collection_id,
- owner: owner,
- value: (10 as u128).pow(target_collection.decimal_points)
- };
-
- Self::add_fungible_item(item)?;
- },
- CollectionMode::ReFungible(_, _) => {
-
- // check size
- ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");
+ Ok(())
+ }
- let mut owner_list = Vec::new();
- let value = (10 as u128).pow(target_collection.decimal_points);
- owner_list.push(Ownership {owner: owner.clone(), fraction: value});
+ /// This method creates multiple instances of NFT Collection created with CreateCollection method.
+ ///
+ /// # Permissions
+ ///
+ /// * Collection Owner.
+ /// * Collection Admin.
+ /// * Anyone if
+ /// * White List is enabled, and
+ /// * Address is added to white list, and
+ /// * MintPermission is enabled (see SetMintPermission method)
+ ///
+ /// # Arguments
+ ///
+ /// * collection_id: ID of the collection.
+ ///
+ /// * properties: Array items properties. Each property is an array of bytes itself, see [create_item].
+ ///
+ /// * owner: Address, initial owner of the NFT.
+ #[weight = 0]
+ pub fn create_multiple_items(origin, collection_id: u64, properties: Vec<Vec<u8>>, owner: T::AccountId) -> DispatchResult {
- let item = ReFungibleItemType {
- collection: collection_id,
- owner: owner_list,
- data: properties.clone()
- };
+ ensure!(properties.len() > 0, "Length of items properties must be greater than 0.");
+ let sender = ensure_signed(origin)?;
- Self::add_refungible_item(item)?;
- },
- _ => { ensure!(1 == 0,"just error"); }
+ Self::collection_exists(collection_id)?;
+ let target_collection = <Collection<T>>::get(collection_id);
- };
+ Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;
- // call event
- Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));
+ for prop in &properties {
+ Self::validate_create_item_args(&target_collection, prop)?;
+ }
+ for prop in &properties {
+ Self::create_item_no_validation(collection_id, &target_collection, prop, &owner)?;
+ }
Ok(())
}
@@ -1078,6 +1063,94 @@
}
impl<T: Trait> Module<T> {
+
+ fn can_create_items_in_collection(collection_id: u64, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {
+
+ if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
+ ensure!(collection.mint_mode == true, "Public minting is not allowed for this collection");
+ Self::check_white_list(collection_id, owner)?;
+ Self::check_white_list(collection_id, sender)?;
+ }
+
+ Ok(())
+ }
+
+ fn validate_create_item_args(collection: &CollectionType<T::AccountId>, properties: &Vec<u8>) -> DispatchResult {
+
+ match collection.mode
+ {
+ CollectionMode::NFT(_) => {
+
+ // check size
+ ensure!(collection.custom_data_size >= properties.len() as u32, "Size of item is too large")
+ },
+ CollectionMode::Fungible(_) => {
+
+ // check size
+ ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type")
+ },
+ CollectionMode::ReFungible(_, _) => {
+
+ // check size
+ ensure!(collection.custom_data_size >= properties.len() as u32, "Size of item is too large")
+ },
+ _ => {
+ fail!("Unexpected collection mode")
+ }
+ }
+
+ Ok(())
+ }
+
+ fn create_item_no_validation(collection_id: u64, collection: &CollectionType<T::AccountId>, properties: &Vec<u8>, owner: &T::AccountId) -> DispatchResult {
+ match collection.mode
+ {
+ CollectionMode::NFT(_) => {
+
+ // Create nft item
+ let item = NftItemType {
+ collection: collection_id,
+ owner: owner.clone(),
+ data: properties.clone(),
+ };
+
+ Self::add_nft_item(item)?;
+
+ },
+ CollectionMode::Fungible(_) => {
+
+ let item = FungibleItemType {
+ collection: collection_id,
+ owner: owner.clone(),
+ value: (10 as u128).pow(collection.decimal_points)
+ };
+
+ Self::add_fungible_item(item)?;
+ },
+ CollectionMode::ReFungible(_, _) => {
+
+ let mut owner_list = Vec::new();
+ let value = (10 as u128).pow(collection.decimal_points);
+ owner_list.push(Ownership {owner: owner.clone(), fraction: value});
+
+ let item = ReFungibleItemType {
+ collection: collection_id,
+ owner: owner_list,
+ data: properties.clone()
+ };
+
+ Self::add_refungible_item(item)?;
+ },
+ _ => { ensure!(1 == 0,"just error"); }
+
+ };
+
+ // call event
+ Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));
+
+ Ok(())
+ }
+
fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {
let current_index = <ItemListIndex>::get(item.collection)
.checked_add(1)
pallets/nft/src/tests.rsdiffbeforeafterboth44 });44 });45}45}4647// Use cases tests region48// #region49#[test]50fn create_nft_multiple_items() {51 new_test_ext().execute_with(|| {52 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();53 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();54 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();55 let mode: CollectionMode = CollectionMode::NFT(2000);5657 assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 58 collection_numbers_limit: 10,59 account_token_ownership_limit: 10,60 collections_admins_limit: 5,61 custom_data_limit: 2048,62 nft_sponsor_transfer_timeout: 15,63 fungible_sponsor_transfer_timeout: 15,64 refungible_sponsor_transfer_timeout: 15, 65 }));6667 let origin1 = Origin::signed(1);68 assert_ok!(TemplateModule::create_collection(69 origin1.clone(),70 col_name1.clone(),71 col_desc1.clone(),72 token_prefix1.clone(),73 mode74 ));75 assert_eq!(TemplateModule::collection(1).owner, 1);7677 let properties = [[1, 2, 3].to_vec(), [3, 2, 1].to_vec(), [3, 3, 3].to_vec()].to_vec();7879 assert_ok!(TemplateModule::create_multiple_items(80 origin1.clone(),81 1,82 properties.clone(),83 184 ));85 for (index, data) in properties.iter().enumerate() {86 assert_eq!(TemplateModule::nft_item_id(1, (index + 1) as u64).data, *data);87 }88 });89}469047#[test]91#[test]48fn create_refungible_item() {92fn create_refungible_item() {93}137}9413895#[test]139#[test]96fn create_fungible_item() {140fn create_multiple_refungible_items() {141 new_test_ext().execute_with(|| {142 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();143 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();144 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();145 let mode: CollectionMode = CollectionMode::ReFungible(2000, 3);146147 assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 148 collection_numbers_limit: 10,149 account_token_ownership_limit: 10,150 collections_admins_limit: 5,151 custom_data_limit: 2048,152 nft_sponsor_transfer_timeout: 15,153 fungible_sponsor_transfer_timeout: 15,154 refungible_sponsor_transfer_timeout: 15, 155 }));156157 let origin1 = Origin::signed(1);158 assert_ok!(TemplateModule::create_collection(159 origin1.clone(),160 col_name1.clone(),161 col_desc1.clone(),162 token_prefix1.clone(),163 mode164 ));165 assert_eq!(TemplateModule::collection(1).owner, 1);166167 let properties = [[1, 2, 3].to_vec(), [3, 2, 1].to_vec(), [3, 3, 3].to_vec()].to_vec();168169 assert_ok!(TemplateModule::create_multiple_items(170 origin1.clone(),171 1,172 properties.clone(),173 1174 ));175 for (index, data) in properties.iter().enumerate() {176177 let item = TemplateModule::refungible_item_id(1, (index + 1) as u64);178 assert_eq!(item.data, *data);179 assert_eq!(180 item.owner[0],181 Ownership {182 owner: 1,183 fraction: 1000184 }185 );186 }187 });188}189190#[test]191fn create_fungible_item() {192 new_test_ext().execute_with(|| {193 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();194 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();195 let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();196 let mode: CollectionMode = CollectionMode::Fungible(3);197198 assert_ok!(TemplateModule::set_chain_limits(RawOrigin::Root.into(), ChainLimits { 199 collection_numbers_limit: 10,200 account_token_ownership_limit: 10,201 collections_admins_limit: 5,202 custom_data_limit: 2048,203 nft_sponsor_transfer_timeout: 15,204 fungible_sponsor_transfer_timeout: 15,205 refungible_sponsor_transfer_timeout: 15, 206 }));207208 let origin1 = Origin::signed(1);209 assert_ok!(TemplateModule::create_collection(210 origin1.clone(),211 col_name1.clone(),212 col_desc1.clone(),213 token_prefix1.clone(),214 mode215 ));216 assert_eq!(TemplateModule::collection(1).owner, 1);217218 assert_ok!(TemplateModule::create_item(219 origin1.clone(),220 1,221 [].to_vec(),222 1223 ));224 assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);225 });226}227228#[test]229fn create_multiple_fungible_items() {97 new_test_ext().execute_with(|| {230 new_test_ext().execute_with(|| {98 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();231 let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();99 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();232 let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();120 ));253 ));121 assert_eq!(TemplateModule::collection(1).owner, 1);254 assert_eq!(TemplateModule::collection(1).owner, 1);255256 let properties = [[].to_vec(), [].to_vec(), [].to_vec()].to_vec();122257123 assert_ok!(TemplateModule::create_item(258 assert_ok!(TemplateModule::create_multiple_items(124 origin1.clone(),259 origin1.clone(),125 1,260 1,126 [].to_vec(),261 properties.clone(),127 1262 1128 ));263 ));264 265 for (index, _) in properties.iter().enumerate() {129 assert_eq!(TemplateModule::fungible_item_id(1, 1).owner, 1);266 assert_eq!(TemplateModule::fungible_item_id(1, (index + 1) as u64).owner, 1);267 }130 assert_eq!(TemplateModule::balance_count(1, 1), 1000);268 assert_eq!(TemplateModule::balance_count(1, 1), 3000);131 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);269 assert_eq!(TemplateModule::address_tokens(1, 1), [1, 2, 3]);132 });270 });133}271}134272