git.delta.rocks / unique-network / refs/commits / 4bce10c77fc9

difftreelog

Fix collection limits

Greg Zaitsev2021-02-26parent: #4b68421.patch.diff
in: master

3 files changed

modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -383,7 +383,7 @@
         /// Collection limit bounds per collection exceeded
         CollectionLimitBoundsExceeded,
         /// Tried to enable permissions which are only permitted to be disabled
-        OwnerPermissionsCantBeReturned,
+        OwnerPermissionsCantBeReverted,
         /// Schema data size limit bound exceeded
         SchemaDataLimitExceeded,
         /// Maximum refungibility exceeded
@@ -626,7 +626,7 @@
             let sender = ensure_signed(origin)?;
             Self::check_owner_permissions(collection_id, sender)?;
 
-            let mut target_collection = <Collection<T>>::get(collection_id);
+            let target_collection = <Collection<T>>::get(collection_id);
             if !target_collection.limits.owner_can_destroy {
                 fail!(Error::<T>::NoPermission);
             }
@@ -1532,31 +1532,32 @@
         pub fn set_collection_limits(
             origin,
             collection_id: u32,
-            limits: CollectionLimits,
+            new_limits: CollectionLimits,
         ) -> DispatchResult {
             let sender = ensure_signed(origin)?;
             Self::check_owner_permissions(collection_id, sender.clone())?;
             let mut target_collection = <Collection<T>>::get(collection_id);
+            let old_limits = target_collection.limits;
             let chain_limits = ChainLimit::get();
-            let climits = target_collection.limits;
 
             // collection bounds
-            ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&
-                limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP,  
+            ensure!(new_limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&
+                new_limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP && 
+                new_limits.sponsored_data_size <= chain_limits.custom_data_limit &&
+                new_limits.sponsored_mint_size <= chain_limits.custom_data_limit,
                 Error::<T>::CollectionLimitBoundsExceeded);
 
             // token_limit   check  prev
-            ensure!(climits.token_limit > limits.token_limit && 
-                limits.token_limit <= chain_limits.account_token_ownership_limit, 
-                Error::<T>::AccountTokenLimitExceeded);
+            ensure!(old_limits.token_limit >= new_limits.token_limit, Error::<T>::CollectionTokenLimitExceeded);
+            ensure!(new_limits.token_limit > 0, Error::<T>::CollectionTokenLimitExceeded);
 
             ensure!(
-                (climits.owner_can_transfer || !limits.owner_can_transfer) &&
-                (climits.owner_can_destroy || !limits.owner_can_destroy),
-                Error::<T>::OwnerPermissionsCantBeReturned,
+                (old_limits.owner_can_transfer || !new_limits.owner_can_transfer) &&
+                (old_limits.owner_can_destroy || !new_limits.owner_can_destroy),
+                Error::<T>::OwnerPermissionsCantBeReverted,
             );
 
-            target_collection.limits = limits;
+            target_collection.limits = new_limits;
             <Collection<T>>::insert(collection_id, target_collection);
 
             Ok(())
modifiedtests/src/setCollectionLimits.test.tsdiffbeforeafterboth
before · tests/src/setCollectionLimits.test.ts
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits7import { ApiPromise, Keyring } from '@polkadot/api';8import { IKeyringPair } from '@polkadot/types/types';9import chai from 'chai';10import chaiAsPromised from 'chai-as-promised';11import usingApi, {submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api';12import { ICollectionInterface } from './types';13import {14  createCollectionExpectSuccess, getCreatedCollectionCount,15  getCreateItemResult,16  getDetailedCollectionInfo,17  setCollectionLimitsExpectFailure,18  setCollectionLimitsExpectSuccess,19} from './util/helpers';2021chai.use(chaiAsPromised);22const expect = chai.expect;2324let alice: IKeyringPair;25let bob: IKeyringPair;26let collectionIdForTesting: number;2728const accountTokenOwnershipLimit = 0;29const sponsoredDataSize = 0;30const sponsoredMintSize = 0;31const tokenLimit = 0;3233describe('hooks', () => {34  before(async () => {35    await usingApi(async () => {36      const keyring = new Keyring({ type: 'sr25519' });37      alice = keyring.addFromUri('//Alice');38    });39  });40  it('choose or create collection for testing', async () => {41    await usingApi(async () => {42      collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}});43    });44  });45});4647describe('setCollectionLimits positive', () => {48  let tx;49  before(async () => {50    await usingApi(async () => {51      const keyring = new Keyring({ type: 'sr25519' });52      alice = keyring.addFromUri('//Alice');53    });54  });55  it('execute setCollectionLimits with predefined params ', async () => {56    await usingApi(async (api: ApiPromise) => {57      tx = api.tx.nft.setCollectionLimits(58        collectionIdForTesting,59        {60          accountTokenOwnershipLimit,61          sponsoredDataSize,62          sponsoredMintSize,63          tokenLimit,64        },65      );66      const events = await submitTransactionAsync(alice, tx);67      const result = getCreateItemResult(events);68      // tslint:disable-next-line:no-unused-expression69      expect(result.success).to.be.true;70    });71  });72  it('get collection limits defined in previous test', async () => {73    await usingApi(async (api: ApiPromise) => {74      const collectionInfo = await getDetailedCollectionInfo(api, collectionIdForTesting) as ICollectionInterface;75      expect(collectionInfo.Limits.AccountTokenOwnershipLimit.toNumber()).to.be.equal(accountTokenOwnershipLimit);76      expect(collectionInfo.Limits.SponsoredMintSize.toNumber()).to.be.equal(sponsoredMintSize);77      expect(collectionInfo.Limits.TokenLimit.toNumber()).to.be.equal(tokenLimit);78      expect(collectionInfo.Limits.SponsorTimeout.toNumber()).to.be.equal(sponsoredDataSize);79    });80  });81});8283describe('setCollectionLimits negative', () => {84  let tx;85  before(async () => {86    await usingApi(async () => {87      const keyring = new Keyring({ type: 'sr25519' });88      alice = keyring.addFromUri('//Alice');89      bob = keyring.addFromUri('//Bob');90    });91  });92  it('execute setCollectionLimits for not exists collection', async () => {93    await usingApi(async (api: ApiPromise) => {94      const collectionCount = await getCreatedCollectionCount(api);95      const nonExistedCollectionId = collectionCount + 1;96      tx = api.tx.nft.setCollectionLimits(97        nonExistedCollectionId,98        {99          accountTokenOwnershipLimit,100          sponsoredDataSize,101          sponsoredMintSize,102          tokenLimit,103        },104      );105      await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected;106    });107  });108  it('execute setCollectionLimits from user who is not owner of this collection', async () => {109    await usingApi(async (api: ApiPromise) => {110      tx = api.tx.nft.setCollectionLimits(111        collectionIdForTesting,112        {113          accountTokenOwnershipLimit,114          sponsoredDataSize,115          sponsoredMintSize,116          tokenLimit,117        },118      );119      await expect(submitTransactionExpectFailAsync(bob, tx)).to.be.rejected;120    });121  });122  it('execute setCollectionLimits with incorrect limits', async () => {123    await usingApi(async (api: ApiPromise) => {124      tx = api.tx.nft.setCollectionLimits(125        collectionIdForTesting,126        {127          accountTokenOwnershipLimit: 'awdawd',128          sponsorTransferTimeout: 'awd',129          sponsoredDataSize: '12312312312312312',130          tokenLimit: '-100',131        },132      );133      await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected;134    });135  });136137  it('fails when trying to enable OwnerCanTransfer after it was disabled', async () => {138    const collectionId = await createCollectionExpectSuccess();139    await setCollectionLimitsExpectSuccess(alice, collectionId, { OwnerCanTransfer: false });140    await setCollectionLimitsExpectFailure(alice, collectionId, { OwnerCanTransfer: true });141  });142143  it('fails when trying to enable OwnerCanDestroy after it was disabled', async () => {144    const collectionId = await createCollectionExpectSuccess();145    await setCollectionLimitsExpectSuccess(alice, collectionId, { OwnerCanDestroy: false });146    await setCollectionLimitsExpectFailure(alice, collectionId, { OwnerCanDestroy: true });147  });148});
after · tests/src/setCollectionLimits.test.ts
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56// https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits7import { ApiPromise, Keyring } from '@polkadot/api';8import { IKeyringPair } from '@polkadot/types/types';9import chai from 'chai';10import chaiAsPromised from 'chai-as-promised';11import usingApi, {submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api';12import { ICollectionInterface } from './types';13import {14  createCollectionExpectSuccess, getCreatedCollectionCount,15  getCreateItemResult,16  getDetailedCollectionInfo,17  setCollectionLimitsExpectFailure,18  setCollectionLimitsExpectSuccess,19} from './util/helpers';2021chai.use(chaiAsPromised);22const expect = chai.expect;2324let alice: IKeyringPair;25let bob: IKeyringPair;26let collectionIdForTesting: number;2728const accountTokenOwnershipLimit = 0;29const sponsoredDataSize = 0;30const sponsoredMintSize = 0;31const sponsorTimeout = 1;32const tokenLimit = 1;3334describe('setCollectionLimits positive', () => {35  let tx;36  before(async () => {37    await usingApi(async () => {38      const keyring = new Keyring({ type: 'sr25519' });39      alice = keyring.addFromUri('//Alice');40      collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}});41    });42  });43  it('execute setCollectionLimits with predefined params ', async () => {44    await usingApi(async (api: ApiPromise) => {45      tx = api.tx.nft.setCollectionLimits(46        collectionIdForTesting,47        {48          AccountTokenOwnershipLimit: accountTokenOwnershipLimit,49          SponsoredMintSize: sponsoredDataSize,50          TokenLimit: tokenLimit,51          SponsorTimeout: sponsorTimeout,52          OwnerCanTransfer: true,53          OwnerCanDestroy: true54        },55      );56      const events = await submitTransactionAsync(alice, tx);57      const result = getCreateItemResult(events);5859      // get collection limits defined previously60      const collectionInfo = await getDetailedCollectionInfo(api, collectionIdForTesting) as ICollectionInterface;6162      // tslint:disable-next-line:no-unused-expression63      expect(result.success).to.be.true;64      expect(collectionInfo.Limits.AccountTokenOwnershipLimit.toNumber()).to.be.equal(accountTokenOwnershipLimit);65      expect(collectionInfo.Limits.SponsoredMintSize.toNumber()).to.be.equal(sponsoredDataSize);66      expect(collectionInfo.Limits.TokenLimit.toNumber()).to.be.equal(tokenLimit);67      expect(collectionInfo.Limits.SponsorTimeout.toNumber()).to.be.equal(sponsorTimeout);68      expect(collectionInfo.Limits.OwnerCanTransfer.valueOf()).to.be.true;69      expect(collectionInfo.Limits.OwnerCanDestroy.valueOf()).to.be.true;70    });71  });72});7374describe('setCollectionLimits negative', () => {75  let tx;76  before(async () => {77    await usingApi(async () => {78      const keyring = new Keyring({ type: 'sr25519' });79      alice = keyring.addFromUri('//Alice');80      bob = keyring.addFromUri('//Bob');81      collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}});82    });83  });84  it('execute setCollectionLimits for not exists collection', async () => {85    await usingApi(async (api: ApiPromise) => {86      const collectionCount = await getCreatedCollectionCount(api);87      const nonExistedCollectionId = collectionCount + 1;88      tx = api.tx.nft.setCollectionLimits(89        nonExistedCollectionId,90        {91          accountTokenOwnershipLimit,92          sponsoredDataSize,93          sponsoredMintSize,94          tokenLimit,95        },96      );97      await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected;98    });99  });100  it('execute setCollectionLimits from user who is not owner of this collection', async () => {101    await usingApi(async (api: ApiPromise) => {102      tx = api.tx.nft.setCollectionLimits(103        collectionIdForTesting,104        {105          accountTokenOwnershipLimit,106          sponsoredDataSize,107          sponsoredMintSize,108          tokenLimit,109        },110      );111      await expect(submitTransactionExpectFailAsync(bob, tx)).to.be.rejected;112    });113  });114  it('execute setCollectionLimits with incorrect limits', async () => {115    await usingApi(async (api: ApiPromise) => {116      tx = api.tx.nft.setCollectionLimits(117        collectionIdForTesting,118        {119          accountTokenOwnershipLimit: 'awdawd',120          sponsorTransferTimeout: 'awd',121          sponsoredDataSize: '12312312312312312',122          tokenLimit: '-100',123        },124      );125      await expect(submitTransactionExpectFailAsync(alice, tx)).to.be.rejected;126    });127  });128129  it('fails when trying to enable OwnerCanTransfer after it was disabled', async () => {130    const collectionId = await createCollectionExpectSuccess();131    await setCollectionLimitsExpectSuccess(alice, collectionId, { 132      AccountTokenOwnershipLimit: accountTokenOwnershipLimit,133      SponsoredMintSize: sponsoredDataSize,134      TokenLimit: tokenLimit,135      SponsorTimeout: sponsorTimeout,136      OwnerCanTransfer: false,137      OwnerCanDestroy: true138    });139    await setCollectionLimitsExpectFailure(alice, collectionId, { 140      AccountTokenOwnershipLimit: accountTokenOwnershipLimit,141      SponsoredMintSize: sponsoredDataSize,142      TokenLimit: tokenLimit,143      SponsorTimeout: sponsorTimeout,144      OwnerCanTransfer: true,145      OwnerCanDestroy: true146    });147  });148149  it('fails when trying to enable OwnerCanDestroy after it was disabled', async () => {150    const collectionId = await createCollectionExpectSuccess();151    await setCollectionLimitsExpectSuccess(alice, collectionId, {152      AccountTokenOwnershipLimit: accountTokenOwnershipLimit,153      SponsoredMintSize: sponsoredDataSize,154      TokenLimit: tokenLimit,155      SponsorTimeout: sponsorTimeout,156      OwnerCanTransfer: true,157      OwnerCanDestroy: false158    });159    await setCollectionLimitsExpectFailure(alice, collectionId, { 160      AccountTokenOwnershipLimit: accountTokenOwnershipLimit,161      SponsoredMintSize: sponsoredDataSize,162      TokenLimit: tokenLimit,163      SponsorTimeout: sponsorTimeout,164      OwnerCanTransfer: true,165      OwnerCanDestroy: true166    });167  });168});
modifiedtests/src/types.tsdiffbeforeafterboth
--- a/tests/src/types.ts
+++ b/tests/src/types.ts
@@ -17,6 +17,8 @@
     SponsoredMintSize: BN;
     TokenLimit: BN;
     SponsorTimeout: BN;
+    OwnerCanTransfer: boolean;
+    OwnerCanDestroy: boolean;
   };
   MintMode: boolean;
   Mode: {