From 07649f272b8b4cc4f8fa8bc0fa47d9540a025699 Mon Sep 17 00:00:00 2001 From: usetech-llc Date: Sun, 14 Mar 2021 10:51:48 +0000 Subject: [PATCH] Merge pull request #125 from usetech-llc/fix/NFTPAR-367_createMultipleItems_overflow_checks Fix bulk mint exceeds collection token limit --- --- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -967,7 +967,7 @@ let target_collection = >::get(collection_id); - Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?; + Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner, 1)?; Self::validate_create_item_args(&target_collection, &data)?; Self::create_item_no_validation(collection_id, owner, data)?; @@ -1003,7 +1003,7 @@ Self::collection_exists(collection_id)?; let target_collection = >::get(collection_id); - Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?; + Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner, items_data.len() as u32)?; for data in &items_data { Self::validate_create_item_args(&target_collection, data)?; @@ -1638,13 +1638,17 @@ Ok(()) } - fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult { + fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType, sender: &T::AccountId, owner: &T::AccountId, amount: u32) -> DispatchResult { // check token limit and account token limit - let total_items: u32 = ItemListIndex::get(collection_id); - let account_items: u32 = >::get(collection_id, owner).len() as u32; - ensure!(collection.limits.token_limit > total_items, Error::::CollectionTokenLimitExceeded); - ensure!(collection.limits.account_token_ownership_limit > account_items, Error::::AccountTokenLimitExceeded); + let total_items: u32 = ItemListIndex::get(collection_id) + .checked_add(amount) + .ok_or(Error::::CollectionTokenLimitExceeded)?; + let account_items: u32 = (>::get(collection_id, owner).len() as u32) + .checked_add(amount) + .ok_or(Error::::AccountTokenLimitExceeded)?; + ensure!(collection.limits.token_limit >= total_items, Error::::CollectionTokenLimitExceeded); + ensure!(collection.limits.account_token_ownership_limit >= account_items, Error::::AccountTokenLimitExceeded); if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) { ensure!(collection.mint_mode == true, Error::::PublicMintingNotAllowed); --- a/tests/src/createMultipleItems.test.ts +++ b/tests/src/createMultipleItems.test.ts @@ -11,7 +11,9 @@ import { createCollectionExpectSuccess, destroyCollectionExpectSuccess, + getGenericResult, IReFungibleTokenDataType, + setCollectionLimitsExpectSuccess, } from './util/helpers'; chai.use(chaiAsPromised); @@ -92,6 +94,25 @@ expect(token3Data.VariableData.toString()).to.be.equal('0x33'); }); }); + + it('Can mint amount of items equals to collection limits', async () => { + await usingApi(async (api) => { + const alice = privateKey('//Alice'); + + const collectionId = await createCollectionExpectSuccess(); + await setCollectionLimitsExpectSuccess(alice, collectionId, { + TokenLimit: 2, + }); + const args = [ + { nft: ['A', 'A'] }, + { nft: ['B', 'B'] }, + ]; + const createMultipleItemsTx = api.tx.nft.createMultipleItems(collectionId, alice.address, args); + const events = await submitTransactionAsync(alice, createMultipleItemsTx); + const result = getGenericResult(events); + expect(result.success).to.be.true; + }); + }); }); describe('Negative Integration Test createMultipleItems(collection_id, owner, items_data):', () => { @@ -175,4 +196,21 @@ await expect(submitTransactionExpectFailAsync(Alice, createMultipleItemsTx)).to.be.rejected; }); }); + + it('Fails when minting tokens exceeds collectionLimits amount', async () => { + await usingApi(async (api) => { + const alice = privateKey('//Alice'); + + const collectionId = await createCollectionExpectSuccess(); + await setCollectionLimitsExpectSuccess(alice, collectionId, { + TokenLimit: 1, + }); + const args = [ + { nft: ['A', 'A'] }, + { nft: ['B', 'B'] }, + ]; + const createMultipleItemsTx = api.tx.nft.createMultipleItems(collectionId, alice.address, args); + await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected; + }); + }); }); -- gitstuff