From 0dbd5ddfd2658c301a9b5ee93d2973e0fce0fc17 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Tue, 13 Oct 2020 11:29:33 +0000 Subject: [PATCH] Merge pull request #9 from usetech-llc/feature_limits_nft_78_85_105 Transfer rate limit + chain bounds --- --- a/node/src/chain_spec.rs +++ b/node/src/chain_spec.rs @@ -130,23 +130,35 @@ }), sudo: Some(SudoConfig { key: root_key }), nft: Some(NftConfig { - collection: vec![(1, CollectionType { - owner: get_account_id_from_seed::("Alice"), - mode: CollectionMode::NFT(50), - access: AccessMode::Normal, - decimal_points: 0, - name: vec!(), - description: vec!(), - token_prefix: vec!(), - custom_data_size: 50, - mint_mode: false, - offchain_schema: vec!(), - sponsor: get_account_id_from_seed::("Alice"), - unconfirmed_sponsor: get_account_id_from_seed::("Alice"), - })], - nft_item_id: vec!(), - fungible_item_id: vec!(), - refungible_item_id: vec!(), + collection: vec![( + 1, + CollectionType { + owner: get_account_id_from_seed::("Alice"), + mode: CollectionMode::NFT(50), + access: AccessMode::Normal, + decimal_points: 0, + name: vec![], + description: vec![], + token_prefix: vec![], + custom_data_size: 50, + mint_mode: false, + offchain_schema: vec![], + sponsor: get_account_id_from_seed::("Alice"), + unconfirmed_sponsor: get_account_id_from_seed::("Alice"), + }, + )], + nft_item_id: vec![], + fungible_item_id: vec![], + refungible_item_id: vec![], + chain_limit: 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, + }, }), contracts: Some(ContractsConfig { current_schedule: ContractsSchedule { --- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -1,6 +1,9 @@ #![cfg_attr(not(feature = "std"), no_std)] #[cfg(feature = "std")] +pub use std::*; + +#[cfg(feature = "std")] pub use serde::*; use codec::{Decode, Encode}; @@ -20,7 +23,7 @@ IsSubType, StorageValue, }; -use frame_system::{self as system, ensure_signed}; +use frame_system::{self as system, ensure_signed, ensure_root}; use sp_runtime::sp_std::prelude::Vec; use sp_runtime::{ traits::{ @@ -157,6 +160,27 @@ pub vesting_date: Moment, } +#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct BasketItem { + pub address: AccountId, + pub start_block: BlockNumber, +} + +#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)] +#[cfg_attr(feature = "std", derive(Serialize, Deserialize))] +pub struct ChainLimits { + pub collection_numbers_limit: u64, + pub account_token_ownership_limit: u64, + pub collections_admins_limit: u64, + pub custom_data_limit: u32, + + // Timeouts for item types in passed blocks + pub nft_sponsor_transfer_timeout: u32, + pub fungible_sponsor_transfer_timeout: u32, + pub refungible_sponsor_transfer_timeout: u32, +} + pub trait Trait: system::Trait { type Event: From> + Into<::Event>; } @@ -172,6 +196,14 @@ ChainVersion: u64; ItemListIndex: map hasher(blake2_128_concat) u64 => u64; + // Chain limits struct + pub ChainLimit get(fn chain_limit) config(): ChainLimits; + + // Bound counters + CollectionCount: u64; + pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64; + + // Basic collections pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType; pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec; pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec; @@ -190,13 +222,18 @@ /// Index list pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec; + /// Tokens transfer baskets + pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber; + pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => Vec>; + pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber; + // Sponsorship pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId; pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId; } add_extra_genesis { build(|config: &GenesisConfig| { - // Modification of storage + // Modification of storage for (_num, _c) in &config.collection { >::init_collection(_c); } @@ -212,7 +249,7 @@ for (_num, _q, _i) in &config.refungible_item_id { >::init_refungible_token(_i); } - }) + }) } } @@ -295,8 +332,18 @@ // Anyone can create a collection let who = ensure_signed(origin)?; let custom_data_size = match mode { - CollectionMode::NFT(size) => size, - CollectionMode::ReFungible(size, _) => size, + CollectionMode::NFT(size) => { + + // bound Custom data size + ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded"); + size + }, + CollectionMode::ReFungible(size, _) => { + + // bound Custom data size + ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded"); + size + }, _ => 0 }; @@ -306,6 +353,9 @@ _ => 0 }; + // bound Total number of collections + ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded"); + // check params ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4"); @@ -326,7 +376,13 @@ .checked_add(1) .expect("collection id error"); + // bound counter + let total = CollectionCount::get() + .checked_add(1) + .expect("collection counter error"); + CreatedCollectionCount::put(next_id); + CollectionCount::put(total); // Create new collection let new_collection = CollectionType { @@ -368,7 +424,6 @@ let sender = ensure_signed(origin)?; Self::check_owner_permissions(collection_id, sender)?; - // TODO Items remove >::remove_prefix(collection_id); >::remove_prefix(collection_id); >::remove_prefix(collection_id); @@ -377,6 +432,24 @@ >::remove(collection_id); >::remove(collection_id); + >::remove_prefix(collection_id); + >::remove_prefix(collection_id); + >::remove_prefix(collection_id); + + >::remove_prefix(collection_id); + >::remove_prefix(collection_id); + >::remove_prefix(collection_id); + + if CollectionCount::get() > 0 + { + // bound couter + let total = CollectionCount::get() + .checked_sub(1) + .expect("collection counter error"); + + CollectionCount::put(total); + } + Ok(()) } @@ -544,6 +617,9 @@ ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role"); } + // Number of collection admins + ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded"); + admin_arr.push(new_admin_id); >::insert(collection_id, admin_arr); @@ -758,8 +834,8 @@ // Transfer permissions check let target_collection = >::get(collection_id); - ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) || - Self::is_owner_or_admin_permissions(collection_id, sender.clone()), + ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) || + Self::is_owner_or_admin_permissions(collection_id, sender.clone()), "Only item owner, collection owner and admins can modify item"); if target_collection.access == AccessMode::WhiteList { @@ -810,8 +886,8 @@ // Transfer permissions check let target_collection = >::get(collection_id); - ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) || - Self::is_owner_or_admin_permissions(collection_id, sender.clone()), + ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) || + Self::is_owner_or_admin_permissions(collection_id, sender.clone()), "Only item owner, collection owner and admins can modify item"); if target_collection.access == AccessMode::WhiteList { @@ -852,8 +928,8 @@ // Transfer permissions check let target_collection = >::get(collection_id); - ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) || - Self::is_owner_or_admin_permissions(collection_id, sender.clone()), + ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) || + Self::is_owner_or_admin_permissions(collection_id, sender.clone()), "Only item owner, collection owner and admins can approve"); if target_collection.access == AccessMode::WhiteList { @@ -919,7 +995,7 @@ // Transfer permissions check let target_collection = >::get(collection_id); - ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()), + ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()), "Only item owner, collection owner and admins can modify items"); if target_collection.access == AccessMode::WhiteList { @@ -987,6 +1063,17 @@ Ok(()) } + + // Sudo permissions function + #[weight = 0] + pub fn set_chain_limits( + origin, + limits: ChainLimits + ) -> DispatchResult { + ensure_root(origin)?; + ::put(limits); + Ok(()) + } } } @@ -1004,6 +1091,10 @@ ::insert(item.collection, current_index); >::insert(item.collection, current_index, itemcopy); + // Add current block + let v: Vec> = Vec::new(); + >::insert(item.collection, current_index, v); + // Update balance let new_balance = >::get(item.collection, owner.clone()) .checked_add(value) @@ -1027,6 +1118,10 @@ ::insert(item.collection, current_index); >::insert(item.collection, current_index, itemcopy); + // Add current block + let block_number: T::BlockNumber = 0.into(); + >::insert(item.collection, current_index, block_number); + // Update balance let new_balance = >::get(item.collection, owner.clone()) .checked_add(value) @@ -1048,6 +1143,10 @@ ::insert(collection_id, current_index); >::insert(collection_id, current_index, item); + // Add current block + let block_number: T::BlockNumber = 0.into(); + >::insert(collection_id, current_index, block_number); + // Update balance let new_balance = >::get(collection_id, item_owner.clone()) .checked_add(1) @@ -1057,7 +1156,11 @@ 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!( >::contains_key(collection_id, item_id), "Item does not exists" @@ -1149,7 +1252,6 @@ } fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool { - let target_collection = >::get(collection_id); let mut result: bool = subject == target_collection.owner; let exists = >::contains_key(collection_id); @@ -1163,12 +1265,17 @@ result } - fn check_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult { - + 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"); + ensure!( + result, + "You do not have permissions to modify this collection" + ); Ok(()) } @@ -1193,7 +1300,6 @@ } fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult { - let mes = "Address is not in white list"; ensure!(>::contains_key(collection_id), mes); let wl = >::get(collection_id); @@ -1209,7 +1315,6 @@ owner: T::AccountId, new_owner: T::AccountId, ) -> DispatchResult { - ensure!( >::contains_key(collection_id, item_id), "Item not exists" @@ -1299,7 +1404,6 @@ owner: T::AccountId, new_owner: T::AccountId, ) -> DispatchResult { - ensure!( >::contains_key(collection_id, item_id), "Item not exists" @@ -1385,7 +1489,6 @@ sender: T::AccountId, new_owner: T::AccountId, ) -> DispatchResult { - ensure!( >::contains_key(collection_id, item_id), "Item not exists" @@ -1422,24 +1525,34 @@ Ok(()) } - fn init_collection(item: &CollectionType){ + fn init_collection(item: &CollectionType) { + // check params + assert!( + item.decimal_points <= 4, + "decimal_points parameter must be lower than 4" + ); + assert!( + item.name.len() <= 64, + "Collection name can not be longer than 63 char" + ); + assert!( + item.name.len() <= 256, + "Collection description can not be longer than 255 char" + ); + assert!( + item.token_prefix.len() <= 16, + "Token prefix can not be longer than 15 char" + ); - // check params - assert!(item.decimal_points <= 4, "decimal_points parameter must be lower than 4"); - assert!(item.name.len() <= 64, "Collection name can not be longer than 63 char"); - assert!(item.name.len() <= 256, "Collection description can not be longer than 255 char"); - assert!(item.token_prefix.len() <= 16, "Token prefix can not be longer than 15 char"); - - // Generate next collection ID - let next_id = CreatedCollectionCount::get() - .checked_add(1) - .expect("collection id error"); - - CreatedCollectionCount::put(next_id); - } + // Generate next collection ID + let next_id = CreatedCollectionCount::get() + .checked_add(1) + .expect("collection id error"); - fn init_nft_token(item: &NftItemType){ + CreatedCollectionCount::put(next_id); + } + fn init_nft_token(item: &NftItemType) { let current_index = ::get(item.collection) .checked_add(1) .expect("Item list index id error"); @@ -1457,8 +1570,7 @@ >::insert(collection_id, item_owner.clone(), new_balance); } - fn init_fungible_token(item: &FungibleItemType){ - + fn init_fungible_token(item: &FungibleItemType) { let current_index = ::get(item.collection) .checked_add(1) .expect("Item list index id error"); @@ -1476,8 +1588,7 @@ >::insert(item.collection, owner.clone(), new_balance); } - fn init_refungible_token(item: &ReFungibleItemType){ - + fn init_refungible_token(item: &ReFungibleItemType) { let current_index = ::get(item.collection) .checked_add(1) .expect("Item list index id error"); @@ -1497,6 +1608,21 @@ } fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult { + + // add to account limit + if >::contains_key(owner.clone()) { + + // bound Owned tokens by a single address + let count = >::get(owner.clone()); + ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded"); + + >::insert(owner.clone(), + count.checked_add(1).unwrap()); + } + else { + >::insert(owner.clone(), 1); + } + let list_exists = >::contains_key(collection_id, owner.clone()); if list_exists { let mut list = >::get(collection_id, owner.clone()); @@ -1511,6 +1637,7 @@ let mut itm = Vec::new(); itm.push(item_index.clone()); >::insert(collection_id, owner, itm); + } Ok(()) @@ -1521,6 +1648,12 @@ item_index: u64, owner: T::AccountId, ) -> DispatchResult { + + // update counter + >::insert(owner.clone(), + >::get(owner.clone()).checked_sub(1).unwrap()); + + let list_exists = >::contains_key(collection_id, owner.clone()); if list_exists { let mut list = >::get(collection_id, owner.clone()); @@ -1628,7 +1761,65 @@ >::get(collection_id).sponsor } Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => { - >::get(collection_id).sponsor + let _collection_mode = >::get(collection_id).mode; + + // sponsor timeout + let sponsor_transfer = match _collection_mode { + CollectionMode::NFT(_) => { + let basket = >::get(collection_id, _item_id); + let block_number = >::block_number() as T::BlockNumber; + let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into(); + if block_number >= limit_time { + >::insert(collection_id, _item_id, block_number); + true + } + else { + false + } + } + CollectionMode::Fungible(_) => { + let mut basket = >::get(collection_id, _item_id); + let block_number = >::block_number() as T::BlockNumber; + if basket.iter().any(|i| i.address == _new_owner.clone()) + { + let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone(); + let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into(); + if block_number >= limit_time { + basket.retain(|x| x.address == item.address); + basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() }); + >::insert(collection_id, _item_id, basket); + true + } + else { + false + } + } + else { + basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()}); + true + } + } + CollectionMode::ReFungible(_, _) => { + let basket = >::get(collection_id, _item_id); + let block_number = >::block_number() as T::BlockNumber; + let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into(); + if block_number >= limit_time { + >::insert(collection_id, _item_id, block_number); + true + } else { + false + } + } + _ => { + false + }, + }; + + if !sponsor_transfer { + T::AccountId::default() + } else { + >::get(collection_id).sponsor + } } _ => T::AccountId::default(), @@ -1745,4 +1936,4 @@ Ok(()) } } -// #endregion \ No newline at end of file +// #endregion --- a/pallets/nft/src/mock.rs +++ b/pallets/nft/src/mock.rs @@ -65,6 +65,7 @@ } pub type TemplateModule = Module; + // This function basically just builds a genesis storage key/value store according to // our desired mockup. pub fn new_test_ext() -> sp_io::TestExternalities { --- a/pallets/nft/src/tests.rs +++ b/pallets/nft/src/tests.rs @@ -1,7 +1,8 @@ // Tests to be written here use crate::mock::*; -use crate::{ApprovePermissions, CollectionMode, AccessMode, Ownership}; +use crate::{AccessMode, ApprovePermissions, CollectionMode, Ownership, ChainLimits}; use frame_support::{assert_noop, assert_ok}; +use frame_system::{ RawOrigin }; // Use cases tests region // #region @@ -13,6 +14,16 @@ let token_prefix1: Vec = 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(), @@ -41,6 +52,16 @@ let token_prefix1: Vec = 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(), @@ -79,6 +100,16 @@ let token_prefix1: Vec = 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(), @@ -109,6 +140,16 @@ let token_prefix1: Vec = 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); let origin2 = Origin::signed(2); assert_ok!(TemplateModule::create_collection( @@ -167,6 +208,16 @@ let token_prefix1: Vec = 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); let origin2 = Origin::signed(2); assert_ok!(TemplateModule::create_collection( @@ -264,6 +315,16 @@ let token_prefix1: Vec = 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(), @@ -302,6 +363,16 @@ let token_prefix1: Vec = 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); let origin2 = Origin::signed(2); assert_ok!(TemplateModule::create_collection( @@ -323,8 +394,16 @@ assert_eq!(TemplateModule::balance_count(1, 1), 1); assert_eq!(TemplateModule::address_tokens(1, 1), [1]); - 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::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)); @@ -362,6 +441,16 @@ let token_prefix1: Vec = 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); let origin2 = Origin::signed(2); assert_ok!(TemplateModule::create_collection( @@ -393,8 +482,16 @@ assert_eq!(TemplateModule::balance_count(1, 1), 1000); assert_eq!(TemplateModule::address_tokens(1, 1), [1]); - 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::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)); @@ -444,6 +541,16 @@ let token_prefix1: Vec = 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); let origin2 = Origin::signed(2); assert_ok!(TemplateModule::create_collection( @@ -465,8 +572,16 @@ assert_eq!(TemplateModule::balance_count(1, 1), 1000); assert_eq!(TemplateModule::address_tokens(1, 1), [1]); - 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::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)); @@ -532,6 +647,16 @@ let token_prefix1: Vec = 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(), @@ -557,6 +682,16 @@ let token_prefix1: Vec = 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(), @@ -577,6 +712,16 @@ let token_prefix1: Vec = 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(), @@ -617,6 +762,16 @@ let token_prefix1: Vec = 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(), @@ -655,6 +810,16 @@ let token_prefix1: Vec = b"token_prefix1\0".to_vec(); let mode: CollectionMode = CollectionMode::ReFungible(200, 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); let origin2 = Origin::signed(2); assert_ok!(TemplateModule::create_collection( @@ -664,9 +829,17 @@ 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::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)); @@ -704,6 +877,16 @@ let token_prefix1: Vec = 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); let origin2 = Origin::signed(2); let origin3 = Origin::signed(3); @@ -754,6 +937,16 @@ let origin2 = Origin::signed(2); let origin3 = Origin::signed(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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -809,6 +1002,16 @@ let origin1 = Origin::signed(1); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -881,6 +1084,16 @@ let nft_mode: CollectionMode = CollectionMode::NFT(2000); let origin1 = Origin::signed(1); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -915,6 +1128,16 @@ let origin1 = Origin::signed(1); let origin2 = Origin::signed(2); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -937,8 +1160,16 @@ 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::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)); @@ -972,6 +1203,16 @@ let mode: CollectionMode = CollectionMode::NFT(2000); let origin1 = Origin::signed(1); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -995,6 +1236,16 @@ let origin1 = Origin::signed(1); let origin2 = Origin::signed(2); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -1019,6 +1270,16 @@ let origin1 = Origin::signed(1); let origin2 = Origin::signed(2); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -1027,16 +1288,32 @@ mode )); - assert_noop!(TemplateModule::add_to_white_list(origin2.clone(), 1, 3), "You do not have permissions to modify this collection"); + assert_noop!( + TemplateModule::add_to_white_list(origin2.clone(), 1, 3), + "You do not have permissions to modify this collection" + ); }); } #[test] fn nobody_can_add_address_to_white_list_of_nonexisting_collection() { new_test_ext().execute_with(|| { + let origin1 = Origin::signed(1); + + 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_noop!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2), "This collection does not exist"); + assert_noop!( + TemplateModule::add_to_white_list(origin1.clone(), 1, 2), + "This collection does not exist" + ); }); } @@ -1049,6 +1326,16 @@ let mode: CollectionMode = CollectionMode::NFT(2000); let origin1 = Origin::signed(1); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -1058,7 +1345,10 @@ )); assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1)); - assert_noop!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2), "This collection does not exist"); + assert_noop!( + TemplateModule::add_to_white_list(origin1.clone(), 1, 2), + "This collection does not exist" + ); }); } @@ -1066,13 +1356,22 @@ #[test] fn address_is_already_added_to_white_list() { new_test_ext().execute_with(|| { - let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); let token_prefix1: Vec = b"token_prefix1\0".to_vec(); let mode: CollectionMode = CollectionMode::NFT(2000); let origin1 = Origin::signed(1); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -1091,13 +1390,22 @@ #[test] fn owner_can_remove_address_from_white_list() { new_test_ext().execute_with(|| { - let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); let token_prefix1: Vec = b"token_prefix1\0".to_vec(); let mode: CollectionMode = CollectionMode::NFT(2000); let origin1 = Origin::signed(1); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -1107,7 +1415,11 @@ )); assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2)); - assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2)); + assert_ok!(TemplateModule::remove_from_white_list( + origin1.clone(), + 1, + 2 + )); assert_eq!(TemplateModule::white_list(1).len(), 0); }); } @@ -1115,7 +1427,6 @@ #[test] fn admin_can_remove_address_from_white_list() { new_test_ext().execute_with(|| { - let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); let token_prefix1: Vec = b"token_prefix1\0".to_vec(); @@ -1123,6 +1434,16 @@ let origin1 = Origin::signed(1); let origin2 = Origin::signed(2); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -1134,7 +1455,11 @@ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2)); assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3)); - assert_ok!(TemplateModule::remove_from_white_list(origin2.clone(), 1, 3)); + assert_ok!(TemplateModule::remove_from_white_list( + origin2.clone(), + 1, + 3 + )); assert_eq!(TemplateModule::white_list(1).len(), 0); }); } @@ -1142,7 +1467,6 @@ #[test] fn nonprivileged_user_cannot_remove_address_from_white_list() { new_test_ext().execute_with(|| { - let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); let token_prefix1: Vec = b"token_prefix1\0".to_vec(); @@ -1150,6 +1474,16 @@ let origin1 = Origin::signed(1); let origin2 = Origin::signed(2); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -1159,7 +1493,10 @@ )); assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2)); - assert_noop!(TemplateModule::remove_from_white_list(origin2.clone(), 1, 2), "You do not have permissions to modify this collection"); + assert_noop!( + TemplateModule::remove_from_white_list(origin2.clone(), 1, 2), + "You do not have permissions to modify this collection" + ); assert_eq!(TemplateModule::white_list(1)[0], 2); }); } @@ -1167,16 +1504,28 @@ #[test] fn nobody_can_remove_address_from_white_list_of_nonexisting_collection() { new_test_ext().execute_with(|| { + let origin1 = Origin::signed(1); + + 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_noop!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2), "This collection does not exist"); + assert_noop!( + TemplateModule::remove_from_white_list(origin1.clone(), 1, 2), + "This collection does not exist" + ); }); } #[test] fn nobody_can_remove_address_from_white_list_of_deleted_collection() { new_test_ext().execute_with(|| { - let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); let token_prefix1: Vec = b"token_prefix1\0".to_vec(); @@ -1184,6 +1533,16 @@ let origin1 = Origin::signed(1); let origin2 = Origin::signed(2); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -1194,7 +1553,10 @@ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2)); assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1)); - assert_noop!(TemplateModule::remove_from_white_list(origin2.clone(), 1, 2), "This collection does not exist"); + assert_noop!( + TemplateModule::remove_from_white_list(origin2.clone(), 1, 2), + "This collection does not exist" + ); assert_eq!(TemplateModule::white_list(1).len(), 0); }); } @@ -1209,6 +1571,16 @@ let mode: CollectionMode = CollectionMode::NFT(2000); let origin1 = Origin::signed(1); + 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, + })); + assert_ok!(TemplateModule::create_collection( origin1.clone(), col_name1.clone(), @@ -1218,8 +1590,16 @@ )); assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2)); - assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2)); - assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2)); + assert_ok!(TemplateModule::remove_from_white_list( + origin1.clone(), + 1, + 2 + )); + assert_ok!(TemplateModule::remove_from_white_list( + origin1.clone(), + 1, + 2 + )); assert_eq!(TemplateModule::white_list(1).len(), 0); }); } @@ -1233,6 +1613,16 @@ let token_prefix1: Vec = 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(), @@ -1250,16 +1640,17 @@ 1 )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); - assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2)); - - assert_noop!(TemplateModule::transfer( + assert_ok!(TemplateModule::set_public_access_mode( origin1.clone(), - 3, 1, - 1, - 1 - ), "Address is not in white list"); + AccessMode::WhiteList + )); + assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2)); + + assert_noop!( + TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1), + "Address is not in white list" + ); }); } @@ -1271,6 +1662,16 @@ let token_prefix1: Vec = 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(), @@ -1288,24 +1689,28 @@ 1 )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); + 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)); // do approve assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1)); assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1); - - assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 1)); - assert_noop!(TemplateModule::transfer_from( + assert_ok!(TemplateModule::remove_from_white_list( origin1.clone(), - 1, - 3, 1, - 1, 1 - ), "Address is not in white list"); + )); + + assert_noop!( + TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1), + "Address is not in white list" + ); }); } @@ -1318,6 +1723,16 @@ let token_prefix1: Vec = 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(), @@ -1335,16 +1750,17 @@ 1 )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); - assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1)); - - assert_noop!(TemplateModule::transfer( + assert_ok!(TemplateModule::set_public_access_mode( origin1.clone(), - 3, 1, - 1, - 1 - ), "Address is not in white list"); + AccessMode::WhiteList + )); + assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1)); + + assert_noop!( + TemplateModule::transfer(origin1.clone(), 3, 1, 1, 1), + "Address is not in white list" + ); }); } @@ -1356,6 +1772,16 @@ let token_prefix1: Vec = 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(), @@ -1373,7 +1799,11 @@ 1 )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); + 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)); @@ -1381,16 +1811,16 @@ assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1)); assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1); - assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2)); - - assert_noop!(TemplateModule::transfer_from( + assert_ok!(TemplateModule::remove_from_white_list( origin1.clone(), - 1, - 3, 1, - 1, - 1 - ), "Address is not in white list"); + 2 + )); + + assert_noop!( + TemplateModule::transfer_from(origin1.clone(), 1, 3, 1, 1, 1), + "Address is not in white list" + ); }); } @@ -1403,6 +1833,16 @@ let token_prefix1: Vec = 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(), @@ -1420,8 +1860,15 @@ 1 )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); - assert_noop!(TemplateModule::burn_item(origin1.clone(), 1, 1), "Address is not in white list"); + assert_ok!(TemplateModule::set_public_access_mode( + origin1.clone(), + 1, + AccessMode::WhiteList + )); + assert_noop!( + TemplateModule::burn_item(origin1.clone(), 1, 1), + "Address is not in white list" + ); }); } @@ -1434,6 +1881,16 @@ let token_prefix1: Vec = 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(), @@ -1442,10 +1899,17 @@ token_prefix1.clone(), mode )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); + assert_ok!(TemplateModule::set_public_access_mode( + origin1.clone(), + 1, + AccessMode::WhiteList + )); // do approve - assert_noop!(TemplateModule::approve(origin1.clone(), 1, 1, 1), "Address is not in white list"); + assert_noop!( + TemplateModule::approve(origin1.clone(), 1, 1, 1), + "Address is not in white list" + ); }); } @@ -1459,6 +1923,16 @@ let token_prefix1: Vec = 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(), @@ -1476,17 +1950,15 @@ 1 )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); + 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::transfer( - origin1.clone(), - 2, - 1, - 1, - 1 - )); + assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1)); }); } @@ -1498,6 +1970,16 @@ let token_prefix1: Vec = 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(), @@ -1515,7 +1997,11 @@ 1 )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); + 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)); @@ -1543,6 +2029,16 @@ let token_prefix1: Vec = 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(), @@ -1552,8 +2048,16 @@ mode )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); - assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, false)); + assert_ok!(TemplateModule::set_public_access_mode( + origin1.clone(), + 1, + AccessMode::WhiteList + )); + assert_ok!(TemplateModule::set_mint_permission( + origin1.clone(), + 1, + false + )); assert_ok!(TemplateModule::create_item( origin1.clone(), @@ -1573,6 +2077,16 @@ let token_prefix1: Vec = 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); let origin2 = Origin::signed(2); assert_ok!(TemplateModule::create_collection( @@ -1583,8 +2097,16 @@ mode )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); - assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, false)); + assert_ok!(TemplateModule::set_public_access_mode( + origin1.clone(), + 1, + AccessMode::WhiteList + )); + assert_ok!(TemplateModule::set_mint_permission( + origin1.clone(), + 1, + false + )); assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2)); @@ -1606,6 +2128,16 @@ let token_prefix1: Vec = 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); let origin2 = Origin::signed(2); assert_ok!(TemplateModule::create_collection( @@ -1616,16 +2148,22 @@ mode )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); - assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, false)); + assert_ok!(TemplateModule::set_public_access_mode( + origin1.clone(), + 1, + AccessMode::WhiteList + )); + assert_ok!(TemplateModule::set_mint_permission( + origin1.clone(), + 1, + false + )); assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2)); - assert_noop!(TemplateModule::create_item( - origin2.clone(), - 1, - [1, 2, 3].to_vec(), - 2 - ), "Collection is not in mint mode"); + assert_noop!( + TemplateModule::create_item(origin2.clone(), 1, [1, 2, 3].to_vec(), 2), + "Collection is not in mint mode" + ); }); } @@ -1638,6 +2176,16 @@ let token_prefix1: Vec = 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); let origin2 = Origin::signed(2); assert_ok!(TemplateModule::create_collection( @@ -1648,15 +2196,21 @@ mode )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); - assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, false)); + assert_ok!(TemplateModule::set_public_access_mode( + origin1.clone(), + 1, + AccessMode::WhiteList + )); + assert_ok!(TemplateModule::set_mint_permission( + origin1.clone(), + 1, + false + )); - assert_noop!(TemplateModule::create_item( - origin2.clone(), - 1, - [1, 2, 3].to_vec(), - 2 - ), "Collection is not in mint mode"); + assert_noop!( + TemplateModule::create_item(origin2.clone(), 1, [1, 2, 3].to_vec(), 2), + "Collection is not in mint mode" + ); }); } @@ -1669,6 +2223,16 @@ let token_prefix1: Vec = 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(), @@ -1678,8 +2242,16 @@ mode )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); - 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::set_mint_permission( + origin1.clone(), + 1, + true + )); assert_ok!(TemplateModule::create_item( origin1.clone(), @@ -1699,6 +2271,16 @@ let token_prefix1: Vec = 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); let origin2 = Origin::signed(2); assert_ok!(TemplateModule::create_collection( @@ -1709,8 +2291,16 @@ mode )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); - 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::set_mint_permission( + origin1.clone(), + 1, + true + )); assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2)); @@ -1732,6 +2322,16 @@ let token_prefix1: Vec = 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); let origin2 = Origin::signed(2); assert_ok!(TemplateModule::create_collection( @@ -1742,15 +2342,21 @@ mode )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); - 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::set_mint_permission( + origin1.clone(), + 1, + true + )); - assert_noop!(TemplateModule::create_item( - origin2.clone(), - 1, - [1, 2, 3].to_vec(), - 2 - ), "Address is not in white list"); + assert_noop!( + TemplateModule::create_item(origin2.clone(), 1, [1, 2, 3].to_vec(), 2), + "Address is not in white list" + ); }); } @@ -1763,6 +2369,16 @@ let token_prefix1: Vec = 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); let origin2 = Origin::signed(2); assert_ok!(TemplateModule::create_collection( @@ -1773,8 +2389,16 @@ mode )); - assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList)); - 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::set_mint_permission( + origin1.clone(), + 1, + true + )); assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2)); assert_ok!(TemplateModule::create_item( @@ -1786,4 +2410,290 @@ }); } -// #endregion \ No newline at end of file +// Total number of collections. Positive test +#[test] +fn total_number_collections_bound() { + new_test_ext().execute_with(|| { + let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); + let token_prefix1: Vec = 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 + )); + }); +} + +// Total number of collections. Negotive test +#[test] +fn total_number_collections_bound_neg() { + new_test_ext().execute_with(|| { + let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); + let token_prefix1: Vec = 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); + + for _ in 0..10 { + + assert_ok!(TemplateModule::create_collection( + origin1.clone(), + col_name1.clone(), + col_desc1.clone(), + token_prefix1.clone(), + mode.clone() + )); + } + + // 11-th collection in chain. Expects error + assert_noop!(TemplateModule::create_collection( + origin1.clone(), + col_name1.clone(), + col_desc1.clone(), + token_prefix1.clone(), + mode.clone() + ), "Total collections bound exceeded"); + }); +} + +// Owned tokens by a single address. Positive test +#[test] +fn owned_tokens_bound() { + new_test_ext().execute_with(|| { + let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); + let token_prefix1: Vec = 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_ok!(TemplateModule::create_item( + origin1.clone(), + 1, + [1, 2, 3].to_vec(), + 1 + )); + + assert_ok!(TemplateModule::create_item( + origin1.clone(), + 1, + [1, 2, 3].to_vec(), + 1 + )); + }); +} + +// Owned tokens by a single address. Negotive test +#[test] +fn owned_tokens_bound_neg() { + new_test_ext().execute_with(|| { + let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); + let token_prefix1: Vec = 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: 1, + 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_ok!(TemplateModule::create_item( + origin1.clone(), + 1, + [1, 2, 3].to_vec(), + 1 + )); + + assert_noop!(TemplateModule::create_item( + origin1.clone(), + 1, + [1, 2, 3].to_vec(), + 1 + ), "Owned tokens by a single address bound exceeded"); + }); +} + +// Number of collection admins. Positive test +#[test] +fn collection_admins_bound() { + new_test_ext().execute_with(|| { + let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); + let token_prefix1: Vec = 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: 2, + 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_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2)); + assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3)); + }); +} + +// Number of collection admins. Negotive test +#[test] +fn collection_admins_bound_neg() { + new_test_ext().execute_with(|| { + let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); + let token_prefix1: Vec = 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: 1, + collections_admins_limit: 1, + 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_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2)); + assert_noop!(TemplateModule::add_collection_admin(origin1.clone(), 1, 3), "Number of collection admins bound exceeded"); + }); +} + +// Custom data size. Positive test +#[test] +fn custom_data_size_bound() { + new_test_ext().execute_with(|| { + let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); + let token_prefix1: Vec = 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 + )); + }); +} + +// Custom data size. Negotive test +#[test] +fn custom_data_size_bound_neg() { + new_test_ext().execute_with(|| { + let col_name1: Vec = "Test1\0".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1\0".encode_utf16().collect::>(); + let token_prefix1: Vec = 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: 200, + nft_sponsor_transfer_timeout: 15, + fungible_sponsor_transfer_timeout: 15, + refungible_sponsor_transfer_timeout: 15, + })); + + let origin1 = Origin::signed(1); + assert_noop!(TemplateModule::create_collection( + origin1.clone(), + col_name1.clone(), + col_desc1.clone(), + token_prefix1.clone(), + mode + ), "Custom data size bound exceeded"); + }); +} +// #endregion -- gitstuff