difftreelog
Merge pull request #66 from usetech-llc/feature/NFTPAR-280
in: master
Feature/nftpar 280
3 files changed
pallets/nft/src/lib.rsdiffbeforeafterboth--- 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<TokenId>;
/// 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::<Call<T>>::is_sub_type(call) {
Some(Call::create_item(collection_id, _owner, _properties)) => {
+ // sponsor timeout
+ let block_number = <system::Module<T>>::block_number() as T::BlockNumber;
+
+ let limit = <Collection<T>>::get(collection_id).limits.sponsor_transfer_timeout;
+ let mut sponsored = true;
+ if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {
+ let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));
+ let limit_time = last_tx_block + limit.into();
+ if block_number <= limit_time {
+ sponsored = false;
+ }
+ }
+ if sponsored {
+ <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);
+ }
+
// check free create limit
if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&
- (<Collection<T>>::get(collection_id).sponsor_confirmed)
+ (<Collection<T>>::get(collection_id).sponsor_confirmed) &&
+ (sponsored)
{
<Collection<T>>::get(collection_id).sponsor
} else {
runtime/src/lib.rsdiffbeforeafterboth143 spec_name: create_runtime_str!("nft"),143 spec_name: create_runtime_str!("nft"),144 impl_name: create_runtime_str!("nft"),144 impl_name: create_runtime_str!("nft"),145 authoring_version: 1,145 authoring_version: 1,146 spec_version: 2,146 spec_version: 3,147 impl_version: 1,147 impl_version: 1,148 apis: RUNTIME_API_VERSIONS,148 apis: RUNTIME_API_VERSIONS,149 transaction_version: 1,149 transaction_version: 1,tests/src/confirmSponsorship.test.tsdiffbeforeafterboth--- 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():', () => {