From add913f79e3c2e5554f922fc533190831b37ef27 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 18 Jan 2021 16:33:30 +0000 Subject: [PATCH] Merge pull request #66 from usetech-llc/feature/NFTPAR-280 Feature/nftpar 280 --- --- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -419,6 +419,7 @@ pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec; /// Tokens transfer baskets + pub CreateItemBasket get(fn create_item_basket): map hasher(twox_64_concat) (CollectionId, T::AccountId) => T::BlockNumber; pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber; pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber; pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber; @@ -2297,9 +2298,26 @@ let mut sponsor: T::AccountId = match IsSubType::>::is_sub_type(call) { Some(Call::create_item(collection_id, _owner, _properties)) => { + // sponsor timeout + let block_number = >::block_number() as T::BlockNumber; + + let limit = >::get(collection_id).limits.sponsor_transfer_timeout; + let mut sponsored = true; + if >::contains_key((collection_id, &who)) { + let last_tx_block = >::get((collection_id, &who)); + let limit_time = last_tx_block + limit.into(); + if block_number <= limit_time { + sponsored = false; + } + } + if sponsored { + >::insert((collection_id, who.clone()), block_number); + } + // check free create limit if (>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) && - (>::get(collection_id).sponsor_confirmed) + (>::get(collection_id).sponsor_confirmed) && + (sponsored) { >::get(collection_id).sponsor } else { --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -143,7 +143,7 @@ spec_name: create_runtime_str!("nft"), impl_name: create_runtime_str!("nft"), authoring_version: 1, - spec_version: 2, + spec_version: 3, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, --- a/tests/src/confirmSponsorship.test.ts +++ b/tests/src/confirmSponsorship.test.ts @@ -170,7 +170,7 @@ }); }); - it('NFT: Sponsoring is rate limited', async () => { + it('NFT: Sponsoring of transfers is rate limited', async () => { const collectionId = await createCollectionExpectSuccess(); await setCollectionSponsorExpectSuccess(collectionId, bob.address); await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); @@ -285,6 +285,51 @@ }); }); + it('NFT: Sponsoring of createItem is rate limited', async () => { + const collectionId = await createCollectionExpectSuccess(); + await setCollectionSponsorExpectSuccess(collectionId, bob.address); + await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); + + // Enable collection white list + await enableWhiteListExpectSuccess(alice, collectionId); + + // Enable public minting + await enablePublicMintingExpectSuccess(alice, collectionId); + + await usingApi(async (api) => { + // Find unused address + const zeroBalance = await findUnusedAddress(api); + + // Add zeroBalance address to white list + await addToWhiteListExpectSuccess(alice, collectionId, zeroBalance.address); + + // Mint token using unused address as signer - gets sponsored + await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address); + + // Second mint should fail + const AsponsorBalance = new BigNumber((await api.query.system.account(bob.address)).data.free.toString()); + + const consoleError = console.error; + const consoleLog = console.log; + console.error = () => {}; + console.log = () => {}; + const badTransaction = async function () { + await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address); + }; + await expect(badTransaction()).to.be.rejectedWith("Inability to pay some fees"); + console.error = consoleError; + console.log = consoleLog; + const BsponsorBalance = new BigNumber((await api.query.system.account(bob.address)).data.free.toString()); + + // Try again after Zero gets some balance - now it should succeed + const balancetx = api.tx.balances.transfer(zeroBalance.address, 1e15); + await submitTransactionAsync(alice, balancetx); + await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address); + + expect(BsponsorBalance.isEqualTo(AsponsorBalance)).to.be.true; + }); + }); + }); describe('(!negative test!) integration test: ext. removeCollectionSponsor():', () => { -- gitstuff