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

difftreelog

Merge pull request #32 from usetech-llc/feature/nftpar_118

Greg Zaitsev2020-12-15parents: #c313f34 #2b0cd0f.patch.diff
in: master
NFTPAR-118. Per Collection Limits

4 files changed

modifiednode/src/chain_spec.rsdiffbeforeafterboth
--- a/node/src/chain_spec.rs
+++ b/node/src/chain_spec.rs
@@ -171,7 +171,8 @@
                     sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),
                     unconfirmed_sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),
                     const_on_chain_schema: vec![],
-                    variable_on_chain_schema: vec![]
+					variable_on_chain_schema: vec![],
+					limits: CollectionLimits::default()
                 },
             )],
             nft_item_id: vec![],
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
46mod default_weights;46mod default_weights;
4747
48pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;48pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;
49pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;
50pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;
4951
50// Structs52// Structs
51// #region53// #region
116 pub offchain_schema: Vec<u8>,118 pub offchain_schema: Vec<u8>,
117 pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender119 pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender
118 pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship120 pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship
121 pub limits: CollectionLimits, // Collection private restrictions
119 pub variable_on_chain_schema: Vec<u8>, //122 pub variable_on_chain_schema: Vec<u8>, //
120 pub const_on_chain_schema: Vec<u8>, //123 pub const_on_chain_schema: Vec<u8>, //
121}124}
171 pub start_block: BlockNumber,174 pub start_block: BlockNumber,
172}175}
173176
177#[derive(Encode, Decode, Debug, Clone, PartialEq)]
178#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
179pub struct CollectionLimits {
180 pub account_token_ownership_limit: u32,
181 pub sponsored_data_size: u32,
182 pub token_limit: u32,
183
184 // Timeouts for item types in passed blocks
185 pub sponsor_transfer_timeout: u32,
186}
187
188impl Default for CollectionLimits {
189 fn default() -> CollectionLimits {
190 CollectionLimits {
191 account_token_ownership_limit: 10_000_000,
192 token_limit: u32::max_value(),
193 sponsored_data_size: u32::max_value(),
194 sponsor_transfer_timeout: 14400 }
195 }
196}
197
174#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]198#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
175#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]199#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
176pub struct ChainLimits {200pub struct ChainLimits {
328 /// Unexpected collection type.352 /// Unexpected collection type.
329 UnexpectedCollectionType,353 UnexpectedCollectionType,
330 /// Can't store metadata in fungible tokens.354 /// Can't store metadata in fungible tokens.
331 CantStoreMetadataInFungibleTokens355 CantStoreMetadataInFungibleTokens,
356 /// Collection token limit exceeded
357 CollectionTokenLimitExceeded,
358 /// Account token limit exceeded per collection
359 AccountTokenLimitExceeded,
360 /// Collection limit bounds per collection exceeded
361 CollectionLimitBoundsExceeded
332 }362 }
333}363}
334364
544 unconfirmed_sponsor: T::AccountId::default(),574 unconfirmed_sponsor: T::AccountId::default(),
545 variable_on_chain_schema: Vec::new(),575 variable_on_chain_schema: Vec::new(),
546 const_on_chain_schema: Vec::new(),576 const_on_chain_schema: Vec::new(),
577 limits: CollectionLimits::default(),
547 };578 };
548579
549 // Add new collection to map580 // Add new collection to map
1022 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1053 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {
10231054
1024 let sender = ensure_signed(origin)?;1055 let sender = ensure_signed(origin)?;
1056 let target_collection = <Collection<T>>::get(collection_id);
10251057
1058 // Limits check
1059 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;
1060
1026 // Transfer permissions check1061 // Transfer permissions check
1027 let target_collection = <Collection<T>>::get(collection_id);
1028 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1062 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||
1029 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1063 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
1030 Error::<T>::NoPermission);1064 Error::<T>::NoPermission);
1135 }1169 }
1136 }1170 }
11371171
1138 // Transfer permissions check
1139 let target_collection = <Collection<T>>::get(collection_id);1172 let target_collection = <Collection<T>>::get(collection_id);
1140 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
1141 Error::<T>::NoPermission);
11421173
1174 // Limits check
1175 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;
1176
1177 // Transfer permissions check
1178 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
1179 Error::<T>::NoPermission);
1180
1143 if target_collection.access == AccessMode::WhiteList {1181 if target_collection.access == AccessMode::WhiteList {
1144 Self::check_white_list(collection_id, &sender)?;1182 Self::check_white_list(collection_id, &sender)?;
1145 Self::check_white_list(collection_id, &recipient)?;1183 Self::check_white_list(collection_id, &recipient)?;
1387 Ok(())1425 Ok(())
1388 }1426 }
13891427
1390 // #[cfg(feature = "runtime-benchmarks")]1428 #[weight = 0]
1391 // #[weight = 0]1429 pub fn set_collection_limits(
1430 origin,
1392 // pub fn add_contract_sponsoring_debug(1431 collection_id: u32,
1393 // origin,1432 limits: CollectionLimits,
1394 // contract_address: T::AccountId, 1433 ) -> DispatchResult {
1434 let sender = ensure_signed(origin)?;
1435 Self::check_owner_permissions(collection_id, sender.clone())?;
1395 // owner: T::AccountId) -> DispatchResult {1436 let mut target_collection = <Collection<T>>::get(collection_id);
1437 let chain_limits = ChainLimit::get();
1396 // let sender = ensure_signed(origin)?;1438 let climits = target_collection.limits;
1439
1440 // collection bounds
1441 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&
1442 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP,
1443 Error::<T>::CollectionLimitBoundsExceeded);
1444
1397 // <ContractOwner<T>>::insert(contract_address.clone(), owner);1445 // token_limit check prev
1446 ensure!(climits.token_limit > limits.token_limit &&
1447 limits.token_limit <= chain_limits.account_token_ownership_limit,
1448 Error::<T>::AccountTokenLimitExceeded);
1449
1450 target_collection.limits = limits;
1451 <Collection<T>>::insert(collection_id, target_collection);
1452
1398 // Ok(())1453 Ok(())
1399 // }1454 }
1400
1401 }1455 }
1402}1456}
14031457
1404impl<T: Trait> Module<T> {1458impl<T: Trait> Module<T> {
14051459
1460 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {
1461
1462 // check token limit and account token limit
1463 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;
1464 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);
1465
1466 Ok(())
1467 }
1468
1406 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {1469 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {
14071470
1471 // check token limit and account token limit
1472 let total_items: u32 = ItemListIndex::get(collection_id);
1473 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;
1474 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);
1475 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);
1476
1408 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1477 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
1409 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1478 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);
1410 Self::check_white_list(collection_id, owner)?;1479 Self::check_white_list(collection_id, owner)?;
1486 }1555 }
1487 };1556 };
14881557
1489
1490 // call event1558 // call event
1491 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));1559 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));
14921560
2213 // Determine who is paying transaction fee based on ecnomic model2281 // Determine who is paying transaction fee based on ecnomic model
2214 // Parse call to extract collection ID and access collection sponsor2282 // Parse call to extract collection ID and access collection sponsor
2215 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2283 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {
2216 Some(Call::create_item(collection_id, _properties, _owner)) => {2284 Some(Call::create_item(collection_id, _owner, _properties)) => {
2285
2217 <Collection<T>>::get(collection_id).sponsor2286 // check free create limit
2287 if <Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)
2288 {
2289 <Collection<T>>::get(collection_id).sponsor
2290 } else {
2291 T::AccountId::default()
2292 }
2218 }2293 }
2219 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2294 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {
2295
2296 let _collection_limits = <Collection<T>>::get(collection_id).limits;
2220 let _collection_mode = <Collection<T>>::get(collection_id).mode;2297 let _collection_mode = <Collection<T>>::get(collection_id).mode;
22212298
2222 // sponsor timeout2299 // sponsor timeout
2223 let sponsor_transfer = match _collection_mode {2300 let sponsor_transfer = match _collection_mode {
2224 CollectionMode::NFT => {2301 CollectionMode::NFT => {
2302
2303 // get correct limit
2304 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {
2305 _collection_limits.sponsor_transfer_timeout
2306 } else {
2307 ChainLimit::get().nft_sponsor_transfer_timeout
2308 };
2309
2225 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2310 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);
2226 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2311 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;
2227 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();2312 let limit_time = basket + limit.into();
2228 if block_number >= limit_time {2313 if block_number >= limit_time {
2229 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2314 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);
2230 true2315 true
2234 }2319 }
2235 }2320 }
2236 CollectionMode::Fungible(_) => {2321 CollectionMode::Fungible(_) => {
2322
2323 // get correct limit
2324 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {
2325 _collection_limits.sponsor_transfer_timeout
2326 } else {
2327 ChainLimit::get().fungible_sponsor_transfer_timeout
2328 };
2329
2237 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2330 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);
2238 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2331 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;
2239 if basket.iter().any(|i| i.address == _new_owner.clone())2332 if basket.iter().any(|i| i.address == _new_owner.clone())
2240 {2333 {
2241 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2334 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();
2242 let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();2335 let limit_time = item.start_block + limit.into();
2243 if block_number >= limit_time {2336 if block_number >= limit_time {
2244 basket.retain(|x| x.address == item.address);2337 basket.retain(|x| x.address == item.address);
2245 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2338 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });
2256 }2349 }
2257 }2350 }
2258 CollectionMode::ReFungible(_) => {2351 CollectionMode::ReFungible(_) => {
2352
2353 // get correct limit
2354 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {
2355 _collection_limits.sponsor_transfer_timeout
2356 } else {
2357 ChainLimit::get().refungible_sponsor_transfer_timeout
2358 };
2359
2259 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2360 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);
2260 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2361 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;
2261 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();2362 let limit_time = basket + limit.into();
2262 if block_number >= limit_time {2363 if block_number >= limit_time {
2263 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2364 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);
2264 true2365 true
modifiedpallets/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 };
 
modifiedruntime_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