difftreelog
Merge pull request #32 from usetech-llc/feature/nftpar_118
in: master
NFTPAR-118. Per Collection Limits
4 files changed
node/src/chain_spec.rsdiffbeforeafterboth1// use nft_runtime::{2// AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,3// SystemConfig, WASM_BINARY,4// };5// use nft_runtime::{ContractsConfig, ContractsSchedule, NftConfig, CollectionType};6use nft_runtime::*;7use sc_service::ChainType;8use sp_consensus_aura::sr25519::AuthorityId as AuraId;9use sp_core::{sr25519, Pair, Public};10use sp_finality_grandpa::AuthorityId as GrandpaId;11use sp_runtime::traits::{IdentifyAccount, Verify};1213// Note this is the URL for the telemetry server14//const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";1516/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.17pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig>;1819/// Helper function to generate a crypto pair from seed20pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {21 TPublic::Pair::from_string(&format!("//{}", seed), None)22 .expect("static values are valid; qed")23 .public()24}2526type AccountPublic = <Signature as Verify>::Signer;2728/// Helper function to generate an account ID from seed29pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId30where31 AccountPublic: From<<TPublic::Pair as Pair>::Public>,32{33 AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()34}3536/// Helper function to generate an authority key for Aura37pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {38 (get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))39}4041pub fn development_config() -> Result<ChainSpec, String> {42 let wasm_binary = WASM_BINARY.ok_or("Development wasm binary not available".to_string())?;4344 Ok(ChainSpec::from_genesis(45 // Name46 "Development",47 // ID48 "dev",49 ChainType::Development,50 move || testnet_genesis(51 wasm_binary,52 // Initial PoA authorities53 vec![54 authority_keys_from_seed("Alice"),55 ],56 // Sudo account57 get_account_id_from_seed::<sr25519::Public>("Alice"),58 // Pre-funded accounts59 vec![60 get_account_id_from_seed::<sr25519::Public>("Alice"),61 get_account_id_from_seed::<sr25519::Public>("Bob"),62 get_account_id_from_seed::<sr25519::Public>("Alice//stash"),63 get_account_id_from_seed::<sr25519::Public>("Bob//stash"),64 ],65 true,66 ),67 // Bootnodes68 vec![],69 // Telemetry70 None,71 // Protocol ID72 None,73 // Properties74 None,75 // Extensions76 None,77 ))78}7980pub fn local_testnet_config() -> Result<ChainSpec, String> {81 let wasm_binary = WASM_BINARY.ok_or("Development wasm binary not available".to_string())?;8283 Ok(ChainSpec::from_genesis(84 // Name85 "Local Testnet",86 // ID87 "local_testnet",88 ChainType::Local,89 move || testnet_genesis(90 wasm_binary,91 // Initial PoA authorities92 vec![93 authority_keys_from_seed("Alice"),94 authority_keys_from_seed("Bob"),95 ],96 // Sudo account97 get_account_id_from_seed::<sr25519::Public>("Alice"),98 // Pre-funded accounts99 vec![100 get_account_id_from_seed::<sr25519::Public>("Alice"),101 get_account_id_from_seed::<sr25519::Public>("Bob"),102 get_account_id_from_seed::<sr25519::Public>("Charlie"),103 get_account_id_from_seed::<sr25519::Public>("Dave"),104 get_account_id_from_seed::<sr25519::Public>("Eve"),105 get_account_id_from_seed::<sr25519::Public>("Ferdie"),106 get_account_id_from_seed::<sr25519::Public>("Alice//stash"),107 get_account_id_from_seed::<sr25519::Public>("Bob//stash"),108 get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),109 get_account_id_from_seed::<sr25519::Public>("Dave//stash"),110 get_account_id_from_seed::<sr25519::Public>("Eve//stash"),111 get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),112 ],113 true,114 ),115 // Bootnodes116 vec![],117 // Telemetry118 None,119 // Protocol ID120 None,121 // Properties122 None,123 // Extensions124 None,125 ))126}127128fn testnet_genesis(129 wasm_binary: &[u8],130 initial_authorities: Vec<(AuraId, GrandpaId)>,131 root_key: AccountId,132 endowed_accounts: Vec<AccountId>,133 enable_println: bool,134) -> GenesisConfig {135 GenesisConfig {136 system: Some(SystemConfig {137 code: wasm_binary.to_vec(),138 changes_trie_config: Default::default(),139 }),140 pallet_balances: Some(BalancesConfig {141 balances: endowed_accounts142 .iter()143 .cloned()144 .map(|k| (k, 1 << 100))145 .collect(),146 }),147 pallet_aura: Some(AuraConfig {148 authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),149 }),150 pallet_grandpa: Some(GrandpaConfig {151 authorities: initial_authorities152 .iter()153 .map(|x| (x.1.clone(), 1))154 .collect(),155 }),156 pallet_treasury: Some(Default::default()),157 pallet_sudo: Some(SudoConfig { key: root_key }),158 pallet_nft: Some(NftConfig {159 collection: vec![(160 1,161 CollectionType {162 owner: get_account_id_from_seed::<sr25519::Public>("Alice"),163 mode: CollectionMode::NFT,164 access: AccessMode::Normal,165 decimal_points: 0,166 name: vec![],167 description: vec![],168 token_prefix: vec![],169 mint_mode: false,170 offchain_schema: vec![],171 sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),172 unconfirmed_sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),173 const_on_chain_schema: vec![],174 variable_on_chain_schema: vec![]175 },176 )],177 nft_item_id: vec![],178 fungible_item_id: vec![],179 refungible_item_id: vec![],180 chain_limit: ChainLimits {181 collection_numbers_limit: 10,182 account_token_ownership_limit: 10,183 collections_admins_limit: 5,184 custom_data_limit: 2048,185 nft_sponsor_transfer_timeout: 15,186 fungible_sponsor_transfer_timeout: 15,187 refungible_sponsor_transfer_timeout: 15,188 },189 }),190 pallet_contracts: Some(ContractsConfig {191 current_schedule: ContractsSchedule {192 enable_println,193 ..Default::default()194 },195 }),196 }197}1// use nft_runtime::{2// AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,3// SystemConfig, WASM_BINARY,4// };5// use nft_runtime::{ContractsConfig, ContractsSchedule, NftConfig, CollectionType};6use nft_runtime::*;7use sc_service::ChainType;8use sp_consensus_aura::sr25519::AuthorityId as AuraId;9use sp_core::{sr25519, Pair, Public};10use sp_finality_grandpa::AuthorityId as GrandpaId;11use sp_runtime::traits::{IdentifyAccount, Verify};1213// Note this is the URL for the telemetry server14//const STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";1516/// Specialized `ChainSpec`. This is a specialization of the general Substrate ChainSpec type.17pub type ChainSpec = sc_service::GenericChainSpec<GenesisConfig>;1819/// Helper function to generate a crypto pair from seed20pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {21 TPublic::Pair::from_string(&format!("//{}", seed), None)22 .expect("static values are valid; qed")23 .public()24}2526type AccountPublic = <Signature as Verify>::Signer;2728/// Helper function to generate an account ID from seed29pub fn get_account_id_from_seed<TPublic: Public>(seed: &str) -> AccountId30where31 AccountPublic: From<<TPublic::Pair as Pair>::Public>,32{33 AccountPublic::from(get_from_seed::<TPublic>(seed)).into_account()34}3536/// Helper function to generate an authority key for Aura37pub fn authority_keys_from_seed(s: &str) -> (AuraId, GrandpaId) {38 (get_from_seed::<AuraId>(s), get_from_seed::<GrandpaId>(s))39}4041pub fn development_config() -> Result<ChainSpec, String> {42 let wasm_binary = WASM_BINARY.ok_or("Development wasm binary not available".to_string())?;4344 Ok(ChainSpec::from_genesis(45 // Name46 "Development",47 // ID48 "dev",49 ChainType::Development,50 move || testnet_genesis(51 wasm_binary,52 // Initial PoA authorities53 vec![54 authority_keys_from_seed("Alice"),55 ],56 // Sudo account57 get_account_id_from_seed::<sr25519::Public>("Alice"),58 // Pre-funded accounts59 vec![60 get_account_id_from_seed::<sr25519::Public>("Alice"),61 get_account_id_from_seed::<sr25519::Public>("Bob"),62 get_account_id_from_seed::<sr25519::Public>("Alice//stash"),63 get_account_id_from_seed::<sr25519::Public>("Bob//stash"),64 ],65 true,66 ),67 // Bootnodes68 vec![],69 // Telemetry70 None,71 // Protocol ID72 None,73 // Properties74 None,75 // Extensions76 None,77 ))78}7980pub fn local_testnet_config() -> Result<ChainSpec, String> {81 let wasm_binary = WASM_BINARY.ok_or("Development wasm binary not available".to_string())?;8283 Ok(ChainSpec::from_genesis(84 // Name85 "Local Testnet",86 // ID87 "local_testnet",88 ChainType::Local,89 move || testnet_genesis(90 wasm_binary,91 // Initial PoA authorities92 vec![93 authority_keys_from_seed("Alice"),94 authority_keys_from_seed("Bob"),95 ],96 // Sudo account97 get_account_id_from_seed::<sr25519::Public>("Alice"),98 // Pre-funded accounts99 vec![100 get_account_id_from_seed::<sr25519::Public>("Alice"),101 get_account_id_from_seed::<sr25519::Public>("Bob"),102 get_account_id_from_seed::<sr25519::Public>("Charlie"),103 get_account_id_from_seed::<sr25519::Public>("Dave"),104 get_account_id_from_seed::<sr25519::Public>("Eve"),105 get_account_id_from_seed::<sr25519::Public>("Ferdie"),106 get_account_id_from_seed::<sr25519::Public>("Alice//stash"),107 get_account_id_from_seed::<sr25519::Public>("Bob//stash"),108 get_account_id_from_seed::<sr25519::Public>("Charlie//stash"),109 get_account_id_from_seed::<sr25519::Public>("Dave//stash"),110 get_account_id_from_seed::<sr25519::Public>("Eve//stash"),111 get_account_id_from_seed::<sr25519::Public>("Ferdie//stash"),112 ],113 true,114 ),115 // Bootnodes116 vec![],117 // Telemetry118 None,119 // Protocol ID120 None,121 // Properties122 None,123 // Extensions124 None,125 ))126}127128fn testnet_genesis(129 wasm_binary: &[u8],130 initial_authorities: Vec<(AuraId, GrandpaId)>,131 root_key: AccountId,132 endowed_accounts: Vec<AccountId>,133 enable_println: bool,134) -> GenesisConfig {135 GenesisConfig {136 system: Some(SystemConfig {137 code: wasm_binary.to_vec(),138 changes_trie_config: Default::default(),139 }),140 pallet_balances: Some(BalancesConfig {141 balances: endowed_accounts142 .iter()143 .cloned()144 .map(|k| (k, 1 << 100))145 .collect(),146 }),147 pallet_aura: Some(AuraConfig {148 authorities: initial_authorities.iter().map(|x| (x.0.clone())).collect(),149 }),150 pallet_grandpa: Some(GrandpaConfig {151 authorities: initial_authorities152 .iter()153 .map(|x| (x.1.clone(), 1))154 .collect(),155 }),156 pallet_treasury: Some(Default::default()),157 pallet_sudo: Some(SudoConfig { key: root_key }),158 pallet_nft: Some(NftConfig {159 collection: vec![(160 1,161 CollectionType {162 owner: get_account_id_from_seed::<sr25519::Public>("Alice"),163 mode: CollectionMode::NFT,164 access: AccessMode::Normal,165 decimal_points: 0,166 name: vec![],167 description: vec![],168 token_prefix: vec![],169 mint_mode: false,170 offchain_schema: vec![],171 sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),172 unconfirmed_sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),173 const_on_chain_schema: vec![],174 variable_on_chain_schema: vec![],175 limits: CollectionLimits::default()176 },177 )],178 nft_item_id: vec![],179 fungible_item_id: vec![],180 refungible_item_id: vec![],181 chain_limit: ChainLimits {182 collection_numbers_limit: 10,183 account_token_ownership_limit: 10,184 collections_admins_limit: 5,185 custom_data_limit: 2048,186 nft_sponsor_transfer_timeout: 15,187 fungible_sponsor_transfer_timeout: 15,188 refungible_sponsor_transfer_timeout: 15,189 },190 }),191 pallet_contracts: Some(ContractsConfig {192 current_schedule: ContractsSchedule {193 enable_println,194 ..Default::default()195 },196 }),197 }198}pallets/nft/src/lib.rsdiffbeforeafterboth--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -46,6 +46,8 @@
mod default_weights;
pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;
+pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;
+pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;
// Structs
// #region
@@ -116,6 +118,7 @@
pub offchain_schema: Vec<u8>,
pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender
pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship
+ pub limits: CollectionLimits, // Collection private restrictions
pub variable_on_chain_schema: Vec<u8>, //
pub const_on_chain_schema: Vec<u8>, //
}
@@ -171,6 +174,27 @@
pub start_block: BlockNumber,
}
+#[derive(Encode, Decode, Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
+pub struct CollectionLimits {
+ pub account_token_ownership_limit: u32,
+ pub sponsored_data_size: u32,
+ pub token_limit: u32,
+
+ // Timeouts for item types in passed blocks
+ pub sponsor_transfer_timeout: u32,
+}
+
+impl Default for CollectionLimits {
+ fn default() -> CollectionLimits {
+ CollectionLimits {
+ account_token_ownership_limit: 10_000_000,
+ token_limit: u32::max_value(),
+ sponsored_data_size: u32::max_value(),
+ sponsor_transfer_timeout: 14400 }
+ }
+}
+
#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct ChainLimits {
@@ -328,7 +352,13 @@
/// Unexpected collection type.
UnexpectedCollectionType,
/// Can't store metadata in fungible tokens.
- CantStoreMetadataInFungibleTokens
+ CantStoreMetadataInFungibleTokens,
+ /// Collection token limit exceeded
+ CollectionTokenLimitExceeded,
+ /// Account token limit exceeded per collection
+ AccountTokenLimitExceeded,
+ /// Collection limit bounds per collection exceeded
+ CollectionLimitBoundsExceeded
}
}
@@ -544,6 +574,7 @@
unconfirmed_sponsor: T::AccountId::default(),
variable_on_chain_schema: Vec::new(),
const_on_chain_schema: Vec::new(),
+ limits: CollectionLimits::default(),
};
// Add new collection to map
@@ -1022,9 +1053,12 @@
pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {
let sender = ensure_signed(origin)?;
+ let target_collection = <Collection<T>>::get(collection_id);
+
+ // Limits check
+ Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;
// Transfer permissions check
- let target_collection = <Collection<T>>::get(collection_id);
ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||
Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
Error::<T>::NoPermission);
@@ -1135,11 +1169,15 @@
}
}
- // Transfer permissions check
let target_collection = <Collection<T>>::get(collection_id);
- ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
- Error::<T>::NoPermission);
+ // Limits check
+ Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;
+
+ // Transfer permissions check
+ ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
+ Error::<T>::NoPermission);
+
if target_collection.access == AccessMode::WhiteList {
Self::check_white_list(collection_id, &sender)?;
Self::check_white_list(collection_id, &recipient)?;
@@ -1387,24 +1425,55 @@
Ok(())
}
- // #[cfg(feature = "runtime-benchmarks")]
- // #[weight = 0]
- // pub fn add_contract_sponsoring_debug(
- // origin,
- // contract_address: T::AccountId,
- // owner: T::AccountId) -> DispatchResult {
- // let sender = ensure_signed(origin)?;
- // <ContractOwner<T>>::insert(contract_address.clone(), owner);
- // Ok(())
- // }
-
+ #[weight = 0]
+ pub fn set_collection_limits(
+ origin,
+ collection_id: u32,
+ limits: CollectionLimits,
+ ) -> DispatchResult {
+ let sender = ensure_signed(origin)?;
+ Self::check_owner_permissions(collection_id, sender.clone())?;
+ let mut target_collection = <Collection<T>>::get(collection_id);
+ let chain_limits = ChainLimit::get();
+ let climits = target_collection.limits;
+
+ // collection bounds
+ ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&
+ limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP,
+ Error::<T>::CollectionLimitBoundsExceeded);
+
+ // token_limit check prev
+ ensure!(climits.token_limit > limits.token_limit &&
+ limits.token_limit <= chain_limits.account_token_ownership_limit,
+ Error::<T>::AccountTokenLimitExceeded);
+
+ target_collection.limits = limits;
+ <Collection<T>>::insert(collection_id, target_collection);
+
+ Ok(())
+ }
}
}
impl<T: Trait> Module<T> {
+ fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {
+
+ // check token limit and account token limit
+ let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;
+ ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);
+
+ Ok(())
+ }
+
fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {
+ // check token limit and account token limit
+ let total_items: u32 = ItemListIndex::get(collection_id);
+ let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;
+ ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);
+ ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);
+
if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);
Self::check_white_list(collection_id, owner)?;
@@ -1485,7 +1554,6 @@
Self::add_refungible_item(item)?;
}
};
-
// call event
Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));
@@ -2213,18 +2281,35 @@
// Determine who is paying transaction fee based on ecnomic model
// Parse call to extract collection ID and access collection sponsor
let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {
- Some(Call::create_item(collection_id, _properties, _owner)) => {
- <Collection<T>>::get(collection_id).sponsor
+ Some(Call::create_item(collection_id, _owner, _properties)) => {
+
+ // check free create limit
+ if <Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)
+ {
+ <Collection<T>>::get(collection_id).sponsor
+ } else {
+ T::AccountId::default()
+ }
}
Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {
+
+ let _collection_limits = <Collection<T>>::get(collection_id).limits;
let _collection_mode = <Collection<T>>::get(collection_id).mode;
// sponsor timeout
let sponsor_transfer = match _collection_mode {
CollectionMode::NFT => {
+
+ // get correct limit
+ let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {
+ _collection_limits.sponsor_transfer_timeout
+ } else {
+ ChainLimit::get().nft_sponsor_transfer_timeout
+ };
+
let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);
let block_number = <system::Module<T>>::block_number() as T::BlockNumber;
- let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();
+ let limit_time = basket + limit.into();
if block_number >= limit_time {
<NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);
true
@@ -2234,12 +2319,20 @@
}
}
CollectionMode::Fungible(_) => {
+
+ // get correct limit
+ let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {
+ _collection_limits.sponsor_transfer_timeout
+ } else {
+ ChainLimit::get().fungible_sponsor_transfer_timeout
+ };
+
let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);
let block_number = <system::Module<T>>::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();
+ let limit_time = item.start_block + limit.into();
if block_number >= limit_time {
basket.retain(|x| x.address == item.address);
basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });
@@ -2256,9 +2349,17 @@
}
}
CollectionMode::ReFungible(_) => {
+
+ // get correct limit
+ let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {
+ _collection_limits.sponsor_transfer_timeout
+ } else {
+ ChainLimit::get().refungible_sponsor_transfer_timeout
+ };
+
let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);
let block_number = <system::Module<T>>::block_number() as T::BlockNumber;
- let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();
+ let limit_time = basket + limit.into();
if block_number >= limit_time {
<ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);
true
pallets/nft/src/tests.rsdiffbeforeafterboth--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -3,7 +3,7 @@
use crate::mock::*;
use crate::{AccessMode, ApprovePermissions, CollectionMode,
Ownership, ChainLimits, CreateItemData, CreateNftData, CreateFungibleData, CreateReFungibleData,
- CollectionId, TokenId, MAX_DECIMAL_POINTS}; //Err
+ CollectionId, TokenId, MAX_DECIMAL_POINTS};
use frame_support::{assert_noop, assert_ok};
use frame_system::{ RawOrigin };
runtime_types.jsondiffbeforeafterboth--- a/runtime_types.json
+++ b/runtime_types.json
@@ -46,21 +46,12 @@
"Owner": "AccountId",
"Value": "u128"
},
- "ReFungibleItemType": {
- "Collection": "CollectionId",
- "Owner": "Vec<Ownership>",
- "Data": "Vec<u8>"
- },
"NftItemType": {
"Collection": "CollectionId",
"Owner": "AccountId",
"ConstData": "Vec<u8>",
"VariableData": "Vec<u8>"
},
- "Ownership": {
- "owner": "AccountId",
- "fraction": "u128"
- },
"ReFungibleItemType": {
"Collection": "CollectionId",
"Owner": "Vec<Ownership<AccountId>>",
@@ -79,6 +70,7 @@
"OffchainSchema": "Vec<u8>",
"Sponsor": "AccountId",
"UnconfirmedSponsor": "AccountId",
+ "Limits": "CollectionLimits",
"VariableOnChainSchema": "Vec<u8>",
"ConstOnChainSchema": "Vec<u8>"
},
@@ -117,9 +109,15 @@
"account_token_ownership_limit": "u32",
"collections_admins_limit": "u64",
"custom_data_limit": "u32",
- "nft_sponsor_transfer_timeout": "u32",
- "fungible_sponsor_transfer_timeout": "u32",
- "refungible_sponsor_transfer_timeout": "u32"
+ "nft_sponsor_timeout": "u32",
+ "fungible_sponsor_timeout": "u32",
+ "refungible_sponsor_timeout": "u32"
+ },
+ "CollectionLimits": {
+ "AccountTokenOwnershipLimit": "u32",
+ "SponsoredMintSize": "u32",
+ "TokenLimit": "u32",
+ "SponsorTimeout": "u32"
}
}
\ No newline at end of file