git.delta.rocks / unique-network / refs/commits / fb1ebd6bb0f6

difftreelog

refactor move ChainLimits to runtime config

Yaroslav Bolyukin2021-08-10parent: #8c07465.patch.diff
in: master

6 files changed

modifiednode/cli/src/chain_spec.rsdiffbeforeafterboth
--- a/node/cli/src/chain_spec.rs
+++ b/node/cli/src/chain_spec.rs
@@ -202,18 +202,6 @@
 			nft_item_id: vec![],
 			fungible_item_id: vec![],
 			refungible_item_id: vec![],
-			chain_limit: ChainLimits {
-				collection_numbers_limit: 100000,
-				account_token_ownership_limit: 1000000,
-				collections_admins_limit: 5,
-				custom_data_limit: 2048,
-				nft_sponsor_transfer_timeout: 15,
-				fungible_sponsor_transfer_timeout: 15,
-				refungible_sponsor_transfer_timeout: 15,
-				offchain_schema_limit: 1024,
-				variable_on_chain_schema_limit: 1024,
-				const_on_chain_schema_limit: 1024,
-			},
 		},
 		parachain_info: nft_runtime::ParachainInfoConfig { parachain_id: id },
 		aura: nft_runtime::AuraConfig {
modifiedpallets/nft/src/eth/sponsoring.rsdiffbeforeafterboth
before · pallets/nft/src/eth/sponsoring.rs
1//! Implements EVM sponsoring logic via OnChargeEVMTransaction23use crate::{4	ChainLimit, Collection, CollectionById, Config, FungibleTransferBasket, NftTransferBasket,5	eth::{account::EvmBackwardsAddressMapping, map_eth_to_id},6};7use evm_coder::{Call, abi::AbiReader};8use frame_support::{9	storage::{StorageMap, StorageDoubleMap, StorageValue},10};11use sp_core::H160;12use sp_std::prelude::*;13use up_sponsorship::SponsorshipHandler;14use super::{15	account::CrossAccountId,16	erc::{UniqueFungibleCall, UniqueNFTCall, ERC721Call, ERC20Call, ERC721UniqueExtensionsCall},17};18use core::convert::TryInto;19use core::marker::PhantomData;2021struct AnyError;2223fn try_sponsor<T: Config>(24	caller: &H160,25	collection_id: u32,26	collection: &Collection<T>,27	call: &[u8],28) -> Result<(), AnyError> {29	let (method_id, mut reader) = AbiReader::new_call(call).map_err(|_| AnyError)?;30	match &collection.mode {31		crate::CollectionMode::NFT => {32			let call: UniqueNFTCall = UniqueNFTCall::parse(method_id, &mut reader)33				.map_err(|_| AnyError)?34				.ok_or(AnyError)?;35			match call {36				UniqueNFTCall::ERC721UniqueExtensions(37					ERC721UniqueExtensionsCall::TransferNft { token_id, .. },38				)39				| UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => {40					let token_id: u32 = token_id.try_into().map_err(|_| AnyError)?;41					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;42					let collection_limits = &collection.limits;43					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {44						collection_limits.sponsor_transfer_timeout45					} else {46						ChainLimit::get().nft_sponsor_transfer_timeout47					};4849					let mut sponsor = true;50					if <NftTransferBasket<T>>::contains_key(collection_id, token_id) {51						let last_tx_block = <NftTransferBasket<T>>::get(collection_id, token_id);52						let limit_time = last_tx_block + limit.into();53						if block_number <= limit_time {54							sponsor = false;55						}56					}57					if sponsor {58						<NftTransferBasket<T>>::insert(collection_id, token_id, block_number);59						return Ok(());60					}61				}62				_ => {}63			}64		}65		crate::CollectionMode::Fungible(_) => {66			let call: UniqueFungibleCall = UniqueFungibleCall::parse(method_id, &mut reader)67				.map_err(|_| AnyError)?68				.ok_or(AnyError)?;69			#[allow(clippy::single_match)]70			match call {71				UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {72					let who = T::CrossAccountId::from_eth(*caller);73					let collection_limits = &collection.limits;74					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {75						collection_limits.sponsor_transfer_timeout76					} else {77						ChainLimit::get().fungible_sponsor_transfer_timeout78					};7980					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;81					let mut sponsored = true;82					if <FungibleTransferBasket<T>>::contains_key(collection_id, who.as_sub()) {83						let last_tx_block =84							<FungibleTransferBasket<T>>::get(collection_id, who.as_sub());85						let limit_time = last_tx_block + limit.into();86						if block_number <= limit_time {87							sponsored = false;88						}89					}90					if sponsored {91						<FungibleTransferBasket<T>>::insert(92							collection_id,93							who.as_sub(),94							block_number,95						);96						return Ok(());97					}98				}99				_ => {}100			}101		}102		_ => {}103	}104	Err(AnyError)105}106107pub struct NftEthSponsorshipHandler<T: Config>(PhantomData<*const T>);108impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for NftEthSponsorshipHandler<T> {109	fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {110		if let Some(collection_id) = map_eth_to_id(&call.0) {111			if let Some(collection) = <CollectionById<T>>::get(collection_id) {112				if !collection.sponsorship.confirmed() {113					return None;114				}115				if try_sponsor(who, collection_id, &collection, &call.1).is_ok() {116					return collection117						.sponsorship118						.sponsor()119						.cloned()120						.map(T::EvmBackwardsAddressMapping::from_account_id);121				}122			}123		}124		None125	}126}
after · pallets/nft/src/eth/sponsoring.rs
1//! Implements EVM sponsoring logic via OnChargeEVMTransaction23use crate::{4	Collection, CollectionById, Config, FungibleTransferBasket, NftTransferBasket,5	eth::{account::EvmBackwardsAddressMapping, map_eth_to_id}, limit,6};7use evm_coder::{Call, abi::AbiReader};8use frame_support::{9	storage::{StorageMap, StorageDoubleMap},10	traits::Get,11};12use sp_core::H160;13use sp_std::prelude::*;14use up_sponsorship::SponsorshipHandler;15use super::{16	account::CrossAccountId,17	erc::{UniqueFungibleCall, UniqueNFTCall, ERC721Call, ERC20Call, ERC721UniqueExtensionsCall},18};19use core::convert::TryInto;20use core::marker::PhantomData;2122struct AnyError;2324fn try_sponsor<T: Config>(25	caller: &H160,26	collection_id: u32,27	collection: &Collection<T>,28	call: &[u8],29) -> Result<(), AnyError> {30	let (method_id, mut reader) = AbiReader::new_call(call).map_err(|_| AnyError)?;31	match &collection.mode {32		crate::CollectionMode::NFT => {33			let call: UniqueNFTCall = UniqueNFTCall::parse(method_id, &mut reader)34				.map_err(|_| AnyError)?35				.ok_or(AnyError)?;36			match call {37				UniqueNFTCall::ERC721UniqueExtensions(38					ERC721UniqueExtensionsCall::TransferNft { token_id, .. },39				)40				| UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => {41					let token_id: u32 = token_id.try_into().map_err(|_| AnyError)?;42					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;43					let collection_limits = &collection.limits;44					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {45						collection_limits.sponsor_transfer_timeout46					} else {47						<limit!(T, NftSponsorTransferTimeout)>::get()48					};4950					let mut sponsor = true;51					if <NftTransferBasket<T>>::contains_key(collection_id, token_id) {52						let last_tx_block = <NftTransferBasket<T>>::get(collection_id, token_id);53						let limit_time = last_tx_block + limit.into();54						if block_number <= limit_time {55							sponsor = false;56						}57					}58					if sponsor {59						<NftTransferBasket<T>>::insert(collection_id, token_id, block_number);60						return Ok(());61					}62				}63				_ => {}64			}65		}66		crate::CollectionMode::Fungible(_) => {67			let call: UniqueFungibleCall = UniqueFungibleCall::parse(method_id, &mut reader)68				.map_err(|_| AnyError)?69				.ok_or(AnyError)?;70			#[allow(clippy::single_match)]71			match call {72				UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {73					let who = T::CrossAccountId::from_eth(*caller);74					let collection_limits = &collection.limits;75					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {76						collection_limits.sponsor_transfer_timeout77					} else {78						<limit!(T, FungibleSponsorTransferTimeout)>::get()79					};8081					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;82					let mut sponsored = true;83					if <FungibleTransferBasket<T>>::contains_key(collection_id, who.as_sub()) {84						let last_tx_block =85							<FungibleTransferBasket<T>>::get(collection_id, who.as_sub());86						let limit_time = last_tx_block + limit.into();87						if block_number <= limit_time {88							sponsored = false;89						}90					}91					if sponsored {92						<FungibleTransferBasket<T>>::insert(93							collection_id,94							who.as_sub(),95							block_number,96						);97						return Ok(());98					}99				}100				_ => {}101			}102		}103		_ => {}104	}105	Err(AnyError)106}107108pub struct NftEthSponsorshipHandler<T: Config>(PhantomData<*const T>);109impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for NftEthSponsorshipHandler<T> {110	fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {111		if let Some(collection_id) = map_eth_to_id(&call.0) {112			if let Some(collection) = <CollectionById<T>>::get(collection_id) {113				if !collection.sponsorship.confirmed() {114					return None;115				}116				if try_sponsor(who, collection_id, &collection, &call.1).is_ok() {117					return collection118						.sponsorship119						.sponsor()120						.cloned()121						.map(T::EvmBackwardsAddressMapping::from_account_id);122				}123			}124		}125		None126	}127}
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -31,7 +31,7 @@
 	StorageValue, transactional,
 };
 
-use frame_system::{self as system, ensure_signed, ensure_root};
+use frame_system::{self as system, ensure_signed};
 use sp_core::H160;
 use sp_std::vec;
 use sp_runtime::sp_std::prelude::Vec;
@@ -243,6 +243,15 @@
 		<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,
 	>;
 	type TreasuryAccountId: Get<Self::AccountId>;
+	type ChainLimits: ChainLimits;
+}
+
+pub type ChainLimitsOf<T> = <T as Config>::ChainLimits;
+#[macro_export]
+macro_rules! limit {
+	($config:ty, $limit:ident) => {
+		<$crate::ChainLimitsOf<$config> as nft_data_structs::ChainLimits>::$limit
+	}
 }
 
 // # Used definitions
@@ -280,10 +289,6 @@
 		ItemListIndex: map hasher(blake2_128_concat) CollectionId => TokenId;
 		//#endregion
 
-		//#region Chain limits struct
-		pub ChainLimit get(fn chain_limit) config(): ChainLimits;
-		//#endregion
-
 		//#region Bound counters
 		/// Amount of collections destroyed, used for total amount tracking with
 		/// CreatedCollectionCount
@@ -485,14 +490,12 @@
 				CollectionMode::Fungible(points) => points,
 				_ => 0
 			};
-
-			let chain_limit = ChainLimit::get();
 
 			let created_count = CreatedCollectionCount::get();
 			let destroyed_count = DestroyedCollectionCount::get();
 
 			// bound Total number of collections
-			ensure!(created_count - destroyed_count < chain_limit.collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);
+			ensure!(created_count - destroyed_count < <limit!(T, CollectionNumberLimit)>::get(), Error::<T>::TotalCollectionsLimitExceeded);
 
 			// check params
 			ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);
@@ -508,7 +511,7 @@
 			CreatedCollectionCount::put(next_id);
 
 			let limits = CollectionLimits {
-				sponsored_data_size: chain_limit.custom_data_limit,
+				sponsored_data_size: <limit!(T, CustomDataLimit)>::get(),
 				..Default::default()
 			};
 
@@ -737,8 +740,7 @@
 			match admin_arr.binary_search(&new_admin_id) {
 				Ok(_) => {},
 				Err(idx) => {
-					let limits = ChainLimit::get();
-					ensure!(admin_arr.len() < limits.collections_admins_limit as usize, Error::<T>::CollectionAdminsLimitExceeded);
+					ensure!(admin_arr.len() < <limit!(T, CollectionAdminsLimit)>::get() as usize, Error::<T>::CollectionAdminsLimitExceeded);
 					admin_arr.insert(idx, new_admin_id);
 					<AdminList<T>>::insert(collection_id, admin_arr);
 				}
@@ -862,7 +864,7 @@
 
 		#[weight = <T as Config>::WeightInfo::create_item(data.data_size())]
 		#[transactional]
-		pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResult {
+		pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData<ChainLimitsOf<T>>) -> DispatchResult {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
 			let collection = Self::get_collection(collection_id)?;
 
@@ -893,7 +895,7 @@
 							   .map(|data| { data.data_size() })
 							   .sum())]
 		#[transactional]
-		pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResult {
+		pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData<ChainLimitsOf<T>>>) -> DispatchResult {
 
 			ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
@@ -1138,7 +1140,7 @@
 			Self::check_owner_or_admin_permissions(&target_collection, &sender)?;
 
 			// check schema limit
-			ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");
+			ensure!(schema.len() as u32 <= <limit!(T, OffchainSchemaLimit)>::get(), "");
 
 			target_collection.offchain_schema = schema;
 			target_collection.save()
@@ -1168,7 +1170,7 @@
 			Self::check_owner_or_admin_permissions(&target_collection, &sender)?;
 
 			// check schema limit
-			ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");
+			ensure!(schema.len() as u32 <= <limit!(T, ConstOnChainSchemaLimit)>::get(), "");
 
 			target_collection.const_on_chain_schema = schema;
 			target_collection.save()
@@ -1198,25 +1200,10 @@
 			Self::check_owner_or_admin_permissions(&target_collection, &sender)?;
 
 			// check schema limit
-			ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");
+			ensure!(schema.len() as u32 <= <limit!(T, VariableOnChainSchemaLimit)>::get(), "");
 
 			target_collection.variable_on_chain_schema = schema;
 			target_collection.save()
-		}
-
-		// Sudo permissions function
-		#[weight = <T as Config>::WeightInfo::set_chain_limits()]
-		#[transactional]
-		pub fn set_chain_limits(
-			origin,
-			limits: ChainLimits
-		) -> DispatchResult {
-
-			#[cfg(not(feature = "runtime-benchmarks"))]
-			ensure_root(origin)?;
-
-			<ChainLimit>::put(limits);
-			Ok(())
 		}
 
 		#[weight = <T as Config>::WeightInfo::set_collection_limits()]
@@ -1230,12 +1217,11 @@
 			let mut target_collection = Self::get_collection(collection_id)?;
 			Self::check_owner_permissions(&target_collection, sender.as_sub())?;
 			let old_limits = &target_collection.limits;
-			let chain_limits = ChainLimit::get();
 
 			// collection bounds
 			ensure!(new_limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&
 				new_limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP &&
-				new_limits.sponsored_data_size <= chain_limits.custom_data_limit,
+				new_limits.sponsored_data_size <= <ChainLimitsOf<T> as ChainLimits>::CustomDataLimit::get(),
 				Error::<T>::CollectionLimitBoundsExceeded);
 
 			// token_limit   check  prev
@@ -1260,7 +1246,7 @@
 		sender: &T::CrossAccountId,
 		collection: &CollectionHandle<T>,
 		owner: &T::CrossAccountId,
-		data: CreateItemData,
+		data: CreateItemData<ChainLimitsOf<T>>,
 	) -> DispatchResult {
 		Self::can_create_items_in_collection(collection, sender, owner, 1)?;
 		Self::validate_create_item_args(collection, &data)?;
@@ -1471,7 +1457,7 @@
 		Self::token_exists(collection, item_id)?;
 
 		ensure!(
-			ChainLimit::get().custom_data_limit >= data.len() as u32,
+			<limit!(T, CustomDataLimit)>::get() >= data.len() as u32,
 			Error::<T>::TokenVariableDataLimitExceeded
 		);
 
@@ -1498,7 +1484,7 @@
 		sender: &T::CrossAccountId,
 		collection: &CollectionHandle<T>,
 		owner: &T::CrossAccountId,
-		items_data: Vec<CreateItemData>,
+		items_data: Vec<CreateItemData<ChainLimitsOf<T>>>,
 	) -> DispatchResult {
 		Self::can_create_items_in_collection(collection, sender, owner, items_data.len() as u32)?;
 
@@ -1612,18 +1598,18 @@
 
 	fn validate_create_item_args(
 		target_collection: &CollectionHandle<T>,
-		data: &CreateItemData,
+		data: &CreateItemData<ChainLimitsOf<T>>,
 	) -> DispatchResult {
 		match target_collection.mode {
 			CollectionMode::NFT => {
 				if let CreateItemData::NFT(data) = data {
 					// check sizes
 					ensure!(
-						ChainLimit::get().custom_data_limit >= data.const_data.len() as u32,
+						<limit!(T, CustomDataLimit)>::get() >= data.const_data.len() as u32,
 						Error::<T>::TokenConstDataLimitExceeded
 					);
 					ensure!(
-						ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32,
+						<limit!(T, CustomDataLimit)>::get() >= data.variable_data.len() as u32,
 						Error::<T>::TokenVariableDataLimitExceeded
 					);
 				} else {
@@ -1640,11 +1626,11 @@
 				if let CreateItemData::ReFungible(data) = data {
 					// check sizes
 					ensure!(
-						ChainLimit::get().custom_data_limit >= data.const_data.len() as u32,
+						<limit!(T, CustomDataLimit)>::get() >= data.const_data.len() as u32,
 						Error::<T>::TokenConstDataLimitExceeded
 					);
 					ensure!(
-						ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32,
+						<limit!(T, CustomDataLimit)>::get() >= data.variable_data.len() as u32,
 						Error::<T>::TokenVariableDataLimitExceeded
 					);
 
@@ -1669,7 +1655,7 @@
 	fn create_item_no_validation(
 		collection: &CollectionHandle<T>,
 		owner: &T::CrossAccountId,
-		data: CreateItemData,
+		data: CreateItemData<ChainLimitsOf<T>>,
 	) -> DispatchResult {
 		match data {
 			CreateItemData::NFT(data) => {
@@ -2292,7 +2278,7 @@
 			// bound Owned tokens by a single address
 			let count = <AccountItemCount<T>>::get(owner.as_sub());
 			ensure!(
-				count < ChainLimit::get().account_token_ownership_limit,
+				count < <limit!(T, AccountTokenOwnershipLimit)>::get(),
 				Error::<T>::AddressOwnershipLimitExceeded
 			);
 
modifiedpallets/nft/src/sponsorship.rsdiffbeforeafterboth
--- a/pallets/nft/src/sponsorship.rs
+++ b/pallets/nft/src/sponsorship.rs
@@ -1,13 +1,13 @@
 use crate::{
 	Config, Call, CollectionById, CreateItemBasket, VariableMetaDataBasket,
-	ReFungibleTransferBasket, FungibleTransferBasket, NftTransferBasket, ChainLimit,
-	CreateItemData, CollectionMode,
+	ReFungibleTransferBasket, FungibleTransferBasket, NftTransferBasket,
+	CreateItemData, CollectionMode, limit,
 };
 use core::marker::PhantomData;
 use up_sponsorship::SponsorshipHandler;
 use frame_support::{
-	traits::IsSubType,
-	storage::{StorageMap, StorageDoubleMap, StorageValue},
+	traits::{IsSubType, Get},
+	storage::{StorageMap, StorageDoubleMap},
 };
 use nft_data_structs::{TokenId, CollectionId};
 
@@ -16,7 +16,7 @@
 	pub fn withdraw_create_item(
 		who: &T::AccountId,
 		collection_id: &CollectionId,
-		_properties: &CreateItemData,
+		_properties: &CreateItemData<T::ChainLimits>,
 	) -> Option<T::AccountId> {
 		let collection = CollectionById::<T>::get(collection_id)?;
 
@@ -47,7 +47,6 @@
 		item_id: &TokenId,
 	) -> Option<T::AccountId> {
 		let collection = CollectionById::<T>::get(collection_id)?;
-		let limits = ChainLimit::get();
 
 		let mut sponsor_transfer = false;
 		if collection.sponsorship.confirmed() {
@@ -62,7 +61,7 @@
 					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {
 						collection_limits.sponsor_transfer_timeout
 					} else {
-						limits.nft_sponsor_transfer_timeout
+						<limit!(T, NftSponsorTransferTimeout)>::get()
 					};
 
 					let mut sponsored = true;
@@ -84,7 +83,7 @@
 					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {
 						collection_limits.sponsor_transfer_timeout
 					} else {
-						limits.fungible_sponsor_transfer_timeout
+						<limit!(T, FungibleSponsorTransferTimeout)>::get()
 					};
 
 					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
@@ -107,7 +106,7 @@
 					let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {
 						collection_limits.sponsor_transfer_timeout
 					} else {
-						limits.refungible_sponsor_transfer_timeout
+						<limit!(T, ReFungibleSponsorTransferTimeout)>::get()
 					};
 
 					let mut sponsored = true;
modifiedprimitives/nft/src/lib.rsdiffbeforeafterboth
--- a/primitives/nft/src/lib.rs
+++ b/primitives/nft/src/lib.rs
@@ -28,14 +28,6 @@
 pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;
 pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;
 
-// TODO: Somehow use ChainLimits for BoundedVec len calculation?
-// Do we need ChainLimits anyway, if we can change them via forkless upgrades?
-parameter_types! {
-pub const MaxDataSize: u32 = 2048;
-// TODO: This limit isn't checked for substrate create_multiple_items call
-pub const MaxItemsPerBatch: u32 = 200;
-}
-
 pub type CollectionId = u32;
 pub type TokenId = u32;
 pub type DecimalPoints = u8;
@@ -211,23 +203,25 @@
 	}
 }
 
-#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub struct ChainLimits {
-	pub collection_numbers_limit: u32,
-	pub account_token_ownership_limit: u32,
-	pub collections_admins_limit: u64,
-	pub custom_data_limit: u32,
+pub trait ChainLimits {
+	type CollectionNumberLimit: Get<u32>;
+	type AccountTokenOwnershipLimit: Get<u32>;
+	type CollectionAdminsLimit: Get<u64>;
+	type CustomDataLimit: Get<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,
+	type NftSponsorTransferTimeout: Get<u32>;
+	type FungibleSponsorTransferTimeout: Get<u32>;
+	type ReFungibleSponsorTransferTimeout: Get<u32>;
 
 	// Schema limits
-	pub offchain_schema_limit: u32,
-	pub variable_on_chain_schema_limit: u32,
-	pub const_on_chain_schema_limit: u32,
+	type OffchainSchemaLimit: Get<u32>;
+	type VariableOnChainSchemaLimit: Get<u32>;
+	type ConstOnChainSchemaLimit: Get<u32>;
+
+	/// How much items can be created per single
+	/// create_many call
+	type MaxItemsPerBatch: Get<u32>;
 }
 
 /// BoundedVec doesn't supports serde
@@ -263,16 +257,16 @@
 	}
 }
 
-#[derive(Encode, Decode, MaxEncodedLen, Default, Derivative, Clone, PartialEq)]
+#[derive(Encode, Decode, MaxEncodedLen, Default, Derivative)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-#[derivative(Debug)]
-pub struct CreateNftData {
+#[derivative(Debug(bound = ""), PartialEq(bound = ""), Clone(bound = ""))]
+pub struct CreateNftData<T: ChainLimits> {
 	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]
 	#[derivative(Debug = "ignore")]
-	pub const_data: BoundedVec<u8, MaxDataSize>,
+	pub const_data: BoundedVec<u8, T::CustomDataLimit>,
 	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]
 	#[derivative(Debug = "ignore")]
-	pub variable_data: BoundedVec<u8, MaxDataSize>,
+	pub variable_data: BoundedVec<u8, T::CustomDataLimit>,
 }
 
 #[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq)]
@@ -281,28 +275,29 @@
 	pub value: u128,
 }
 
-#[derive(Encode, Decode, MaxEncodedLen, Default, Derivative, Clone, PartialEq)]
+#[derive(Encode, Decode, MaxEncodedLen, Default, Derivative)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-#[derivative(Debug)]
-pub struct CreateReFungibleData {
+#[derivative(Debug(bound = ""), PartialEq(bound = ""), Clone(bound = ""))]
+pub struct CreateReFungibleData<T: ChainLimits> {
 	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]
 	#[derivative(Debug = "ignore")]
-	pub const_data: BoundedVec<u8, MaxDataSize>,
+	pub const_data: BoundedVec<u8, T::CustomDataLimit>,
 	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]
 	#[derivative(Debug = "ignore")]
-	pub variable_data: BoundedVec<u8, MaxDataSize>,
+	pub variable_data: BoundedVec<u8, T::CustomDataLimit>,
 	pub pieces: u128,
 }
 
-#[derive(Encode, Decode, MaxEncodedLen, Debug, Clone, PartialEq)]
+#[derive(Encode, Decode, MaxEncodedLen, Derivative)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
-pub enum CreateItemData {
-	NFT(CreateNftData),
+#[derivative(Debug(bound = ""), PartialEq(bound = ""), Clone(bound = ""))]
+pub enum CreateItemData<T: ChainLimits> {
+	NFT(CreateNftData<T>),
 	Fungible(CreateFungibleData),
-	ReFungible(CreateReFungibleData),
+	ReFungible(CreateReFungibleData<T>),
 }
 
-impl CreateItemData {
+impl<T: ChainLimits> CreateItemData<T> {
 	pub fn data_size(&self) -> usize {
 		match self {
 			CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),
@@ -312,19 +307,19 @@
 	}
 }
 
-impl From<CreateNftData> for CreateItemData {
-	fn from(item: CreateNftData) -> Self {
+impl<T: ChainLimits> From<CreateNftData<T>> for CreateItemData<T> {
+	fn from(item: CreateNftData<T>) -> Self {
 		CreateItemData::NFT(item)
 	}
 }
 
-impl From<CreateReFungibleData> for CreateItemData {
-	fn from(item: CreateReFungibleData) -> Self {
+impl<T: ChainLimits> From<CreateReFungibleData<T>> for CreateItemData<T> {
+	fn from(item: CreateReFungibleData<T>) -> Self {
 		CreateItemData::ReFungible(item)
 	}
 }
 
-impl From<CreateFungibleData> for CreateItemData {
+impl<T: ChainLimits> From<CreateFungibleData> for CreateItemData<T> {
 	fn from(item: CreateFungibleData) -> Self {
 		CreateItemData::Fungible(item)
 	}
modifiedruntime/src/lib.rsdiffbeforeafterboth
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -683,6 +683,35 @@
 }
 
 parameter_types! {
+	pub const CollectionNumberLimit: u32 = 100000;
+	pub const AccountTokenOwnershipLimit: u32 = 1000000;
+	pub const CollectionAdminsLimit: u64 = 5;
+	pub const CustomDataLimit: u32 = 2048;
+	pub const NftSponsorTransferTimeout: u32 = 5;
+	pub const FungibleSponsorTransferTimeout: u32 = 5;
+	pub const ReFungibleSponsorTransferTimeout: u32 = 5;
+	pub const OffchainSchemaLimit: u32 = 1024;
+	pub const VariableOnChainSchemaLimit: u32 = 1024;
+	pub const ConstOnChainSchemaLimit: u32 = 1024;
+	pub const MaxItemsPerBatch: u32 = 200;
+}
+
+pub struct ChainLimits;
+impl nft_data_structs::ChainLimits for ChainLimits {
+    type CollectionNumberLimit = CollectionNumberLimit;
+    type AccountTokenOwnershipLimit = AccountTokenOwnershipLimit;
+    type CollectionAdminsLimit = CollectionAdminsLimit;
+    type CustomDataLimit = CustomDataLimit;
+    type NftSponsorTransferTimeout = NftSponsorTransferTimeout;
+    type FungibleSponsorTransferTimeout = FungibleSponsorTransferTimeout;
+    type ReFungibleSponsorTransferTimeout = ReFungibleSponsorTransferTimeout;
+    type OffchainSchemaLimit = OffchainSchemaLimit;
+    type VariableOnChainSchemaLimit = VariableOnChainSchemaLimit;
+    type ConstOnChainSchemaLimit = ConstOnChainSchemaLimit;
+    type MaxItemsPerBatch = MaxItemsPerBatch;
+}
+
+parameter_types! {
 	pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account();
 	pub const CollectionCreationPrice: Balance = 100 * UNIQUE;
 }
@@ -699,6 +728,7 @@
 	type Currency = Balances;
 	type CollectionCreationPrice = CollectionCreationPrice;
 	type TreasuryAccountId = TreasuryAccountId;
+	type ChainLimits = ChainLimits;
 }
 
 parameter_types! {