difftreelog
Limits logic fixed. Tests added
in: master
4 files changed
pallets/nft/src/lib.rsdiffbeforeafterboth302 /// Amount of collections destroyed, used for total amount tracking with302 /// Amount of collections destroyed, used for total amount tracking with303 /// CreatedCollectionCount303 /// CreatedCollectionCount304 DestroyedCollectionCount: u32;304 DestroyedCollectionCount: u32;305 /// Total amount of account owned tokens (NFTs + RFTs + unique fungibles)306 /// Account id (real)307 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;308 //#endregion305 //#endregion309306310 //#region Basic collections307 //#region Basic collections1596 let account_items: u32 =1593 let account_items: u32 =1597 <AddressTokens<T>>::get(collection_id, recipient.as_sub()).len() as u32;1594 <AddressTokens<T>>::get(collection_id, recipient.as_sub()).len() as u32;15951596 // zero limit means collection limit is disabled1597 // otherwise get lower value1598 let limit = if collection.limits.account_token_ownership_limit == 01599 || collection.limits.account_token_ownership_limit > ACCOUNT_TOKEN_OWNERSHIP_LIMIT1600 {1601 ACCOUNT_TOKEN_OWNERSHIP_LIMIT1602 } else {1603 collection.limits.account_token_ownership_limit1604 };16051598 ensure!(1606 ensure!(limit > account_items, Error::<T>::AccountTokenLimitExceeded);1599 collection.limits.account_token_ownership_limit > account_items,1600 Error::<T>::AccountTokenLimitExceeded1601 );160216071623 .checked_add(amount)1628 .checked_add(amount)1624 .ok_or(Error::<T>::AccountTokenLimitExceeded)?;1629 .ok_or(Error::<T>::AccountTokenLimitExceeded)?;16301631 // zero limit means collection limit is disabled1632 // otherwise get lower value1633 let account_token_limit = if collection.limits.account_token_ownership_limit == 01634 || collection.limits.account_token_ownership_limit > ACCOUNT_TOKEN_OWNERSHIP_LIMIT1635 {1636 ACCOUNT_TOKEN_OWNERSHIP_LIMIT1637 } else {1638 collection.limits.account_token_ownership_limit1639 };16401625 ensure!(1641 ensure!(1626 collection.limits.token_limit >= total_items,1642 collection.limits.token_limit >= total_items,1627 Error::<T>::CollectionTokenLimitExceeded1643 Error::<T>::CollectionTokenLimitExceeded1628 );1644 );1629 ensure!(1645 ensure!(1630 collection.limits.account_token_ownership_limit >= account_items,1646 account_token_limit >= account_items,1631 Error::<T>::AccountTokenLimitExceeded1647 Error::<T>::AccountTokenLimitExceeded1632 );1648 );163316492362 item_index: TokenId,2378 item_index: TokenId,2363 owner: &T::CrossAccountId,2379 owner: &T::CrossAccountId,2364 ) -> DispatchResult {2380 ) -> DispatchResult {2365 // add to account limit2366 collection.consume_sload()?;2367 if <AccountItemCount<T>>::contains_key(owner.as_sub()) {2368 // bound Owned tokens by a single address2369 collection.consume_sload()?;2370 let count = <AccountItemCount<T>>::get(owner.as_sub());2371 ensure!(2372 count < ACCOUNT_TOKEN_OWNERSHIP_LIMIT,2373 Error::<T>::AddressOwnershipLimitExceeded2374 );23752376 collection.consume_sstore()?;2377 <AccountItemCount<T>>::insert(2378 owner.as_sub(),2379 count.checked_add(1).ok_or(Error::<T>::NumOverflow)?,2380 );2381 } else {2382 collection.consume_sstore()?;2383 <AccountItemCount<T>>::insert(owner.as_sub(), 1);2384 }23852386 collection.consume_sload()?;2381 collection.consume_sload()?;2387 let list_exists = <AddressTokens<T>>::contains_key(collection.id, owner.as_sub());2382 let list_exists = <AddressTokens<T>>::contains_key(collection.id, owner.as_sub());2388 if list_exists {2383 if list_exists {2389 collection.consume_sload()?;2384 collection.consume_sload()?;2390 let mut list = <AddressTokens<T>>::get(collection.id, owner.as_sub());2385 let mut list = <AddressTokens<T>>::get(collection.id, owner.as_sub());23862387 // bound Owned tokens by a single address in collection2388 let account_items: u32 = list.len() as u32;2389 ensure!(2390 account_items < ACCOUNT_TOKEN_OWNERSHIP_LIMIT,2391 Error::<T>::AddressOwnershipLimitExceeded2392 );23932391 let item_contains = list.contains(&item_index.clone());2394 let item_contains = list.contains(&item_index.clone());239223952410 item_index: TokenId,2413 item_index: TokenId,2411 owner: &T::CrossAccountId,2414 owner: &T::CrossAccountId,2412 ) -> DispatchResult {2415 ) -> DispatchResult {2413 // update counter2414 collection.consume_sload()?;2415 collection.consume_sstore()?;2416 <AccountItemCount<T>>::insert(2417 owner.as_sub(),2418 <AccountItemCount<T>>::get(owner.as_sub())2419 .checked_sub(1)2420 .ok_or(Error::<T>::NumOverflow)?,2421 );24222423 collection.consume_sload()?;2416 collection.consume_sload()?;2424 let list_exists = <AddressTokens<T>>::contains_key(collection.id, owner.as_sub());2417 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) {tests/src/limits.test.tsdiffbeforeafterbothno changes
tests/src/util/helpers.tsdiffbeforeafterboth796 });796 });797}797}798799export async function800getFreeBalance(account: IKeyringPair) : Promise<BigNumber>801{802 let balance = new BigNumber(0) ;803 await usingApi(async (api) => { 804 balance = new BigNumber((await api.query.system.account(account.address)).data.free.toString()); 805 });806807 return balance;808}798809799export async function810export async function800scheduleTransferExpectSuccess(811scheduleTransferExpectSuccess(870 if (type === 'ReFungible') {881 if (type === 'ReFungible') {871 const nftItemData =882 const nftItemData =872 (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;883 (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;884 const expectedOwner = toSubstrateAddress(to);885 const ownerIndex = nftItemData.Owner.findIndex(v => toSubstrateAddress(v.Owner as any as string) == expectedOwner);886 expect(ownerIndex).to.not.equal(-1);873 expect(nftItemData.Owner[0].Owner).to.be.deep.equal(to);887 expect(nftItemData.Owner[ownerIndex].Owner).to.be.deep.equal(normalizeAccountId(to));874 expect(nftItemData.Owner[0].Fraction.toString()).to.be.equal(value.toString());888 expect(nftItemData.Owner[ownerIndex].Fraction).to.be.greaterThanOrEqual(value as number);875 }889 }876 });890 });877}891}1173 return normalizeAccountId((await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON().Owner);1187 return normalizeAccountId((await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON().Owner);1174}1188}11891190export async function waitNewBlocks(blocksCount = 1): Promise<void> {1191 await usingApi(async (api) => {1192 const promise = new Promise<void>(async (resolve) => {1193 1194 const unsubscribe = await api.rpc.chain.subscribeNewHeads(() => {1195 if (blocksCount > 0) {1196 blocksCount--;1197 } else {1198 unsubscribe();1199 resolve();1200 }1201 });1202 });1203 return promise;1204 });1205}1206