difftreelog
Merge pull request #197 from UniqueNetwork/feature/CORE-167
in: master
Limits logic fixed. Tests added
5 files changed
pallets/nft/src/lib.rsdiffbeforeafterboth306 /// Amount of collections destroyed, used for total amount tracking with306 /// Amount of collections destroyed, used for total amount tracking with307 /// CreatedCollectionCount307 /// CreatedCollectionCount308 DestroyedCollectionCount: u32;308 DestroyedCollectionCount: u32;309 /// Total amount of account owned tokens (NFTs + RFTs + unique fungibles)310 /// Account id (real)311 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;312 //#endregion309 //#endregion313310314 //#region Basic collections311 //#region Basic collections1125 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1122 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);112611231127 let collection = Self::get_collection(collection_id)?;1124 let collection = Self::get_collection(collection_id)?;1125 Self::meta_update_check(&sender, &collection, item_id)?;112811261129 Self::set_variable_meta_data_internal(&sender, &collection, item_id, data)?;1127 Self::set_variable_meta_data_internal(&sender, &collection, item_id, data)?;113011281648 let account_items: u32 =1646 let account_items: u32 =1649 <AddressTokens<T>>::get(collection_id, recipient.as_sub()).len() as u32;1647 <AddressTokens<T>>::get(collection_id, recipient.as_sub()).len() as u32;16481649 // zero limit means collection limit is disabled1650 // otherwise get lower value1651 let limit = if collection.limits.account_token_ownership_limit == 01652 || collection.limits.account_token_ownership_limit > ACCOUNT_TOKEN_OWNERSHIP_LIMIT1653 {1654 ACCOUNT_TOKEN_OWNERSHIP_LIMIT1655 } else {1656 collection.limits.account_token_ownership_limit1657 };16581650 ensure!(1659 ensure!(limit > account_items, Error::<T>::AccountTokenLimitExceeded);1651 collection.limits.account_token_ownership_limit > account_items,1652 Error::<T>::AccountTokenLimitExceeded1653 );165416601675 .checked_add(amount)1681 .checked_add(amount)1676 .ok_or(Error::<T>::AccountTokenLimitExceeded)?;1682 .ok_or(Error::<T>::AccountTokenLimitExceeded)?;16831684 // zero limit means collection limit is disabled1685 // otherwise get lower value1686 let account_token_limit = if collection.limits.account_token_ownership_limit == 01687 || collection.limits.account_token_ownership_limit > ACCOUNT_TOKEN_OWNERSHIP_LIMIT1688 {1689 ACCOUNT_TOKEN_OWNERSHIP_LIMIT1690 } else {1691 collection.limits.account_token_ownership_limit1692 };16931677 ensure!(1694 ensure!(1678 collection.limits.token_limit >= total_items,1695 collection.limits.token_limit >= total_items,1679 Error::<T>::CollectionTokenLimitExceeded1696 Error::<T>::CollectionTokenLimitExceeded1680 );1697 );1681 ensure!(1698 ensure!(1682 collection.limits.account_token_ownership_limit >= account_items,1699 account_token_limit >= account_items,1683 Error::<T>::AccountTokenLimitExceeded1700 Error::<T>::AccountTokenLimitExceeded1684 );1701 );168517022409 item_index: TokenId,2426 item_index: TokenId,2410 owner: &T::CrossAccountId,2427 owner: &T::CrossAccountId,2411 ) -> DispatchResult {2428 ) -> DispatchResult {2412 // add to account limit2413 collection.consume_sload()?;2414 if <AccountItemCount<T>>::contains_key(owner.as_sub()) {2415 // bound Owned tokens by a single address2416 collection.consume_sload()?;2417 let count = <AccountItemCount<T>>::get(owner.as_sub());2418 ensure!(2419 count < ACCOUNT_TOKEN_OWNERSHIP_LIMIT,2420 Error::<T>::AddressOwnershipLimitExceeded2421 );24222423 collection.consume_sstore()?;2424 <AccountItemCount<T>>::insert(2425 owner.as_sub(),2426 count.checked_add(1).ok_or(Error::<T>::NumOverflow)?,2427 );2428 } else {2429 collection.consume_sstore()?;2430 <AccountItemCount<T>>::insert(owner.as_sub(), 1);2431 }24322433 collection.consume_sload()?;2429 collection.consume_sload()?;2434 let list_exists = <AddressTokens<T>>::contains_key(collection.id, owner.as_sub());2430 let list_exists = <AddressTokens<T>>::contains_key(collection.id, owner.as_sub());2435 if list_exists {2431 if list_exists {2436 collection.consume_sload()?;2432 collection.consume_sload()?;2437 let mut list = <AddressTokens<T>>::get(collection.id, owner.as_sub());2433 let mut list = <AddressTokens<T>>::get(collection.id, owner.as_sub());24342435 // bound Owned tokens by a single address in collection2436 let account_items: u32 = list.len() as u32;2437 ensure!(2438 account_items < ACCOUNT_TOKEN_OWNERSHIP_LIMIT,2439 Error::<T>::AddressOwnershipLimitExceeded2440 );24412438 let item_contains = list.contains(&item_index.clone());2442 let item_contains = list.contains(&item_index.clone());243924432457 item_index: TokenId,2461 item_index: TokenId,2458 owner: &T::CrossAccountId,2462 owner: &T::CrossAccountId,2459 ) -> DispatchResult {2463 ) -> DispatchResult {2460 // update counter2461 collection.consume_sload()?;2462 collection.consume_sstore()?;2463 <AccountItemCount<T>>::insert(2464 owner.as_sub(),2465 <AccountItemCount<T>>::get(owner.as_sub())2466 .checked_sub(1)2467 .ok_or(Error::<T>::NumOverflow)?,2468 );24692470 collection.consume_sload()?;2464 collection.consume_sload()?;2471 let list_exists = <AddressTokens<T>>::contains_key(collection.id, owner.as_sub());2465 let list_exists = <AddressTokens<T>>::contains_key(collection.id, owner.as_sub());pallets/nft/src/sponsorship.rsdiffbeforeafterboth61 sponsor_transfer = match collection_mode {61 sponsor_transfer = match collection_mode {62 CollectionMode::NFT => {62 CollectionMode::NFT => {63 // get correct limit63 // get correct limit64 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {64 let limit: u32 = if collection_limits.sponsor_transfer_timeout != 0 {65 if collection_limits.sponsor_transfer_timeout > NFT_SPONSOR_TRANSFER_TIMEOUT66 {65 collection_limits.sponsor_transfer_timeout67 collection_limits.sponsor_transfer_timeout66 } else {68 } else {67 NFT_SPONSOR_TRANSFER_TIMEOUT69 NFT_SPONSOR_TRANSFER_TIMEOUT68 };70 }71 } else {72 073 };697470 let mut sponsored = true;75 let mut sponsored = true;71 if NftTransferBasket::<T>::contains_key(collection_id, item_id) {76 if NftTransferBasket::<T>::contains_key(collection_id, item_id) {83 }88 }84 CollectionMode::Fungible(_) => {89 CollectionMode::Fungible(_) => {85 // get correct limit90 // get correct limit86 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {91 let limit: u32 = if collection_limits.sponsor_transfer_timeout != 0 {92 if collection_limits.sponsor_transfer_timeout93 > FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT94 {87 collection_limits.sponsor_transfer_timeout95 collection_limits.sponsor_transfer_timeout88 } else {96 } else {89 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT97 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT90 };98 }9199 } else {92 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;100 0101 };10293 let mut sponsored = true;103 let mut sponsored = true;94 if FungibleTransferBasket::<T>::contains_key(collection_id, who) {104 if FungibleTransferBasket::<T>::contains_key(collection_id, who) {106 }116 }107 CollectionMode::ReFungible => {117 CollectionMode::ReFungible => {108 // get correct limit118 // get correct limit109 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {119 let limit: u32 = if collection_limits.sponsor_transfer_timeout != 0 {120 if collection_limits.sponsor_transfer_timeout121 > REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT122 {110 collection_limits.sponsor_transfer_timeout123 collection_limits.sponsor_transfer_timeout111 } else {124 } else {112 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT125 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT113 };126 }127 } else {128 0129 };114130115 let mut sponsored = true;131 let mut sponsored = true;116 if ReFungibleTransferBasket::<T>::contains_key(collection_id, item_id) {132 if ReFungibleTransferBasket::<T>::contains_key(collection_id, item_id) {pallets/nft/src/tests.rsdiffbeforeafterboth1789 let data = default_nft_data();1789 let data = default_nft_data();1790 assert_noop!(1790 assert_noop!(1791 TemplateModule::create_item(origin1, 1, account(1), data.into()),1791 TemplateModule::create_item(origin1, 1, account(1), data.into()),1792 Error::<Test>::AddressOwnershipLimitExceeded1792 Error::<Test>::AccountTokenLimitExceeded1793 );1793 );1794 });1794 });1795}1795}2016 let data = default_nft_data();2016 let data = default_nft_data();2017 create_test_item(1, &data.into());2017 create_test_item(1, &data.into());201820182019 TemplateModule::set_meta_update_permission_flag(2019 assert_ok!(TemplateModule::set_meta_update_permission_flag(2020 origin1.clone(),2020 origin1.clone(),2021 collection_id,2021 collection_id,2022 MetaUpdatePermission::ItemOwner,2022 MetaUpdatePermission::ItemOwner,2023 );2023 ));202420242025 let variable_data = b"ten chars.".to_vec();2025 let variable_data = b"ten chars.".to_vec();2026 assert_ok!(TemplateModule::set_variable_meta_data(2026 assert_ok!(TemplateModule::set_variable_meta_data(2040}2040}204120412042#[test]2042#[test]2043fn set_variable_meta_data_on_nft_with_item_owner_permission_flag_neg() {2043fn set_variable_meta_data_on_nft_with_item_owner_permission_flag_neg() {2044 new_test_ext().execute_with(|| {2044 new_test_ext().execute_with(|| {2045 // default_limits();2045 let collection_id = create_test_collection_for_owner(&CollectionMode::NFT, 1, 1);204620462047 let collection_id = create_test_collection_for_owner(&CollectionMode::NFT, 2, 1);2047 let origin1 = Origin::signed(1);204820482049 let origin1 = Origin::signed(1);2049 assert_ok!(TemplateModule::set_mint_permission(2050 let origin2 = Origin::signed(2);2050 origin1.clone(),20512051 collection_id,2052 assert_ok!(TemplateModule::set_mint_permission(2052 true2053 origin2.clone(),2053 ));2054 collection_id,2054 assert_ok!(TemplateModule::add_to_white_list(2055 true2055 origin1.clone(),2056 ));2056 collection_id,2057 assert_ok!(TemplateModule::add_to_white_list(2057 account(1)2058 origin2.clone(),2058 ));2059 collection_id,20592060 account(1)2060 let data = default_nft_data();2061 ));2061 create_test_item(1, &data.into());206220622063 let data = default_nft_data();2063 assert_ok!(TemplateModule::set_meta_update_permission_flag(2064 create_test_item(1, &data.into());2064 origin1.clone(),20652065 collection_id,2066 assert_ok!(TemplateModule::set_meta_update_permission_flag(2066 MetaUpdatePermission::ItemOwner,2067 origin2.clone(),2067 ));2068 collection_id,20682069 MetaUpdatePermission::ItemOwner,2069 let variable_data = b"1234567890123".to_vec();2070 ));2070 assert_noop!(20712071 TemplateModule::set_variable_meta_data(2072 let variable_data = b"ten chars.++".to_vec();2072 origin1,2073 assert_noop!(2073 collection_id,2074 TemplateModule::set_variable_meta_data(2074 1,2075 origin2,2075 variable_data.clone()2076 collection_id,2076 ),2077 1,2077 Error::<Test>::TokenVariableDataLimitExceeded2078 variable_data.clone()2078 );2079 ),2079 })2080 Error::<Test>::TokenVariableDataLimitExceeded2080}2081 );208220812083 #[test]2082#[test]2084 fn collection_transfer_flag_works() {2083fn collection_transfer_flag_works() {2141 MetaUpdatePermission::Admin,2140 MetaUpdatePermission::Admin,2142 ));2141 ));214321422144 let variable_data = b"test set_variable_meta_data method.".to_vec();2143 let variable_data = b"test.".to_vec();2145 assert_ok!(TemplateModule::set_variable_meta_data(2144 assert_ok!(TemplateModule::set_variable_meta_data(2146 origin1,2145 origin1,2147 collection_id,2146 collection_id,2188 MetaUpdatePermission::Admin,2187 MetaUpdatePermission::Admin,2189 ));2188 ));219021892191 let variable_data = b"test set_variable_meta_data method.".to_vec();2190 let variable_data = b"test.".to_vec();2192 assert_noop!(2191 assert_noop!(2193 TemplateModule::set_variable_meta_data(2192 TemplateModule::set_variable_meta_data(2194 origin1,2193 origin1,2243 MetaUpdatePermission::None,2242 MetaUpdatePermission::None,2244 ));2243 ));224522442246 let variable_data = b"test set_variable_meta_data method.".to_vec();2245 let variable_data = b"test.".to_vec();2247 assert_noop!(2246 assert_noop!(2248 TemplateModule::set_variable_meta_data(2247 TemplateModule::set_variable_meta_data(2249 origin1.clone(),2248 origin1.clone(),2285 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);2284 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);2286 });2285 });2287 }2286}2288 });2289}22902287tests/src/limits.test.tsdiffbeforeafterbothno changes
tests/src/util/helpers.tsdiffbeforeafterboth810 });810 });811}811}812813export async function814getFreeBalance(account: IKeyringPair) : Promise<BigNumber>815{816 let balance = new BigNumber(0) ;817 await usingApi(async (api) => { 818 balance = new BigNumber((await api.query.system.account(account.address)).data.free.toString()); 819 });820821 return balance;822}812823813export async function824export async function814scheduleTransferExpectSuccess(825scheduleTransferExpectSuccess(884 if (type === 'ReFungible') {895 if (type === 'ReFungible') {885 const nftItemData =896 const nftItemData =886 (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;897 (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;898 const expectedOwner = toSubstrateAddress(to);899 const ownerIndex = nftItemData.Owner.findIndex(v => toSubstrateAddress(v.Owner as any as string) == expectedOwner);900 expect(ownerIndex).to.not.equal(-1);887 expect(nftItemData.Owner[0].Owner).to.be.deep.equal(to);901 expect(nftItemData.Owner[ownerIndex].Owner).to.be.deep.equal(normalizeAccountId(to));888 expect(nftItemData.Owner[0].Fraction.toString()).to.be.equal(value.toString());902 expect(nftItemData.Owner[ownerIndex].Fraction).to.be.greaterThanOrEqual(value as number);889 }903 }890 });904 });891}905}