From 0231a432ed7dced97591a55a347986a2343bcb6d Mon Sep 17 00:00:00 2001 From: ut-akuznetsov <59873862+ut-akuznetsov@users.noreply.github.com> Date: Fri, 30 Sep 2022 12:51:28 +0000 Subject: [PATCH] Merge pull request #596 from UniqueNetwork/test/playground-migration Test/playground migration --- --- a/tests/package.json +++ b/tests/package.json @@ -44,6 +44,7 @@ "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts", "testSetSchemaVersion": "mocha --timeout 9999999 -r ts-node/register ./**/setSchemaVersion.test.ts", "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts", + "testChangeCollectionOwner": "mocha --timeout 9999999 -r ts-node/register ./**/change-collection-owner.test.ts", "testSetCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionSponsor.test.ts", "testConfirmSponsorship": "mocha --timeout 9999999 -r ts-node/register ./**/confirmSponsorship.test.ts", "testRemoveCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionAdmin.test.ts", --- a/tests/src/adminTransferAndBurn.test.ts +++ b/tests/src/adminTransferAndBurn.test.ts @@ -15,14 +15,7 @@ // along with Unique Network. If not, see . import {IKeyringPair} from '@polkadot/types/types'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import {usingPlaygrounds} from './util/playgrounds'; - -chai.use(chaiAsPromised); -const expect = chai.expect; - -let donor: IKeyringPair; +import {usingPlaygrounds, expect, itSub} from './util/playgrounds'; describe('Integration Test: ownerCanTransfer allows admins to use only transferFrom/burnFrom:', () => { let alice: IKeyringPair; @@ -31,44 +24,40 @@ before(async () => { await usingPlaygrounds(async (helper, privateKey) => { - donor = privateKey('//Alice'); + const donor = privateKey('//Alice'); [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor); }); }); - it('admin transfers other user\'s token', async () => { - await usingPlaygrounds(async (helper) => { - const {collectionId} = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}); - await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true}); - const limits = await helper.collection.getEffectiveLimits(collectionId); - expect(limits.ownerCanTransfer).to.be.true; + itSub('admin transfers other user\'s token', async ({helper}) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}); + await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true}); + const limits = await helper.collection.getEffectiveLimits(collectionId); + expect(limits.ownerCanTransfer).to.be.true; - const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address}); - const transferResult = async () => helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}); - await expect(transferResult()).to.be.rejected; + const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address}); + const transferResult = async () => helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}); + await expect(transferResult()).to.be.rejected; - await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: bob.address}, {Substrate: charlie.address}); - const newTokenOwner = await helper.nft.getTokenOwner(collectionId, tokenId); - expect(newTokenOwner.Substrate).to.be.equal(charlie.address); - }); + await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: bob.address}, {Substrate: charlie.address}); + const newTokenOwner = await helper.nft.getTokenOwner(collectionId, tokenId); + expect(newTokenOwner.Substrate).to.be.equal(charlie.address); }); - it('admin burns other user\'s token', async () => { - await usingPlaygrounds(async (helper) => { - const {collectionId} = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}); + itSub('admin burns other user\'s token', async ({helper}) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}); - await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true}); - const limits = await helper.collection.getEffectiveLimits(collectionId); - expect(limits.ownerCanTransfer).to.be.true; + await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true}); + const limits = await helper.collection.getEffectiveLimits(collectionId); + expect(limits.ownerCanTransfer).to.be.true; - const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address}); - const burnTxFailed = async () => helper.nft.burnToken(alice, collectionId, tokenId); + const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address}); + const burnTxFailed = async () => helper.nft.burnToken(alice, collectionId, tokenId); - await expect(burnTxFailed()).to.be.rejected; + await expect(burnTxFailed()).to.be.rejected; - await helper.nft.burnToken(bob, collectionId, tokenId); - const token = await helper.nft.getToken(collectionId, tokenId); - expect(token).to.be.null; - }); + await helper.nft.burnToken(bob, collectionId, tokenId); + const token = await helper.nft.getToken(collectionId, tokenId); + expect(token).to.be.null; }); }); --- a/tests/src/allowLists.test.ts +++ b/tests/src/allowLists.test.ts @@ -18,7 +18,7 @@ import {usingPlaygrounds, expect, itSub} from './util/playgrounds'; import {ICollectionPermissions} from './util/playgrounds/types'; -describe('Integration Test ext. Add to Allow List', () => { +describe('Integration Test ext. Allow list tests', () => { let alice: IKeyringPair; let bob: IKeyringPair; let charlie: IKeyringPair; @@ -38,7 +38,7 @@ const allowList = await helper.nft.getAllowList(collectionId); expect(allowList).to.deep.contain({Substrate: bob.address}); }); - + itSub('Admin can add address to allow list', async ({helper}) => { const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); await helper.nft.addAdmin(alice, collectionId, {Substrate: bob.address}); @@ -64,7 +64,7 @@ await expect(helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address})) .to.be.rejectedWith(/common\.CollectionNotFound/); }); - + itSub('Nobody can add address to allow list of destroyed collection', async ({helper}) => { const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); await helper.collection.burn(alice, collectionId); @@ -80,7 +80,7 @@ }); }); -describe('Integration Test ext. Remove from Allow List', () => { +describe('Integration Test ext. Remove from Allow List', () => { let alice: IKeyringPair; let bob: IKeyringPair; let charlie: IKeyringPair; @@ -120,9 +120,9 @@ await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address}); const allowListBefore = await helper.nft.getAllowList(collectionId); expect(allowListBefore).to.not.deep.contain({Substrate: bob.address}); - + await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address}); - + const allowListAfter = await helper.nft.getAllowList(collectionId); expect(allowListAfter).to.not.deep.contain({Substrate: bob.address}); }); @@ -138,25 +138,25 @@ const allowList = await helper.nft.getAllowList(collectionId); expect(allowList).to.deep.contain({Substrate: charlie.address}); }); - + itSub('Nobody can remove address from allow list of non-existing collection', async ({helper}) => { const collectionId = (1<<32) - 1; await expect(helper.collection.removeFromAllowList(bob, collectionId, {Substrate: charlie.address})) .to.be.rejectedWith(/common\.CollectionNotFound/); }); - + itSub('Nobody can remove address from allow list of deleted collection', async ({helper}) => { const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address}); await helper.collection.burn(alice, collectionId); - + await expect(helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address})) .to.be.rejectedWith(/common\.CollectionNotFound/); }); }); }); -describe('Integration Test ext. Transfer if included in Allow List', () => { +describe('Integration Test ext. Transfer if included in Allow List', () => { let alice: IKeyringPair; let bob: IKeyringPair; let charlie: IKeyringPair; @@ -179,7 +179,7 @@ const owner = await helper.nft.getTokenOwner(collectionId, tokenId); expect(owner.Substrate).to.be.equal(charlie.address); }); - + itSub('If Public Access mode is set to AllowList, tokens can be transferred to a allowlisted address with transferFrom.', async ({helper}) => { const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address}); @@ -187,24 +187,24 @@ await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address}); await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address}); await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address}); - + await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address}); const owner = await helper.nft.getTokenOwner(collectionId, tokenId); expect(owner.Substrate).to.be.equal(charlie.address); }); - + itSub('If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transfer', async ({helper}) => { const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address}); await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'}); await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address}); await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address}); - + await helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}); const owner = await helper.nft.getTokenOwner(collectionId, tokenId); expect(owner.Substrate).to.be.equal(charlie.address); }); - + itSub('If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transferFrom', async ({helper}) => { const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address}); @@ -212,7 +212,7 @@ await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address}); await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address}); await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address}); - + await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address}); const owner = await helper.nft.getTokenOwner(collectionId, tokenId); expect(owner.Substrate).to.be.equal(charlie.address); @@ -225,11 +225,11 @@ const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address}); await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'}); await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address}); - + await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address})) .to.be.rejectedWith(/common\.AddressNotInAllowlist/); }); - + itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred from a non-allowlisted address with transfer or transferFrom. Test2', async ({helper}) => { const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address}); @@ -238,35 +238,35 @@ await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address}); await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address}); await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: alice.address}); - + await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address})) .to.be.rejectedWith(/common\.AddressNotInAllowlist/); }); - + itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred to a non-allowlisted address with transfer or transferFrom. Test1', async ({helper}) => { const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address}); await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'}); await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address}); - + await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address})) .to.be.rejectedWith(/common\.AddressNotInAllowlist/); }); - + itSub('If Public Access mode is set to AllowList, tokens can\'t be transferred to a non-allowlisted address with transfer or transferFrom. Test2', async ({helper}) => { const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address}); await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList'}); await helper.nft.addToAllowList(alice, collectionId, {Substrate: alice.address}); await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address}); - + await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address}); await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: alice.address}); - + await expect(helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address})) .to.be.rejectedWith(/common\.AddressNotInAllowlist/); }); - + itSub('If Public Access mode is set to AllowList, tokens can\'t be destroyed by a non-allowlisted address (even if it owned them before enabling AllowList mode)', async ({helper}) => { const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address}); @@ -274,7 +274,7 @@ await expect(helper.nft.burnToken(bob, collectionId, tokenId)) .to.be.rejectedWith(/common\.NoPermission/); }); - + itSub('If Public Access mode is set to AllowList, token transfers can\'t be Approved by a non-allowlisted address (see Approve method)', async ({helper}) => { const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address}); @@ -285,7 +285,7 @@ }); }); -describe('Integration Test ext. Mint if included in Allow List', () => { +describe('Integration Test ext. Mint if included in Allow List', () => { let alice: IKeyringPair; let bob: IKeyringPair; @@ -309,7 +309,7 @@ const appropriateRejectionMessage = permissions.mintMode! ? /common\.AddressNotInAllowlist/ : /common\.PublicMintingNotAllowed/; const allowlistedMintingTest = () => itSub( - `With the condtions above, tokens can${allowlistedMintingShouldFail ? '\'t' : ''} be created by allow-listed addresses`, + `With the condtions above, tokens can${allowlistedMintingShouldFail ? '\'t' : ''} be created by allow-listed addresses`, async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {}); await collection.setPermissions(alice, permissions); @@ -330,7 +330,7 @@ await collection.setPermissions(alice, permissions); await expect(collection.mintToken(alice, {Substrate: alice.address})).to.not.be.rejected; }); - + itSub('With the condtions above, tokens can be created by admin', async ({helper}) => { const collection = await helper.nft.mintCollection(alice, {}); await collection.setPermissions(alice, permissions); --- a/tests/src/change-collection-owner.test.ts +++ b/tests/src/change-collection-owner.test.ts @@ -14,231 +14,156 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api'; -import {createCollectionExpectSuccess, - addCollectionAdminExpectSuccess, - setCollectionSponsorExpectSuccess, - confirmSponsorshipExpectSuccess, - removeCollectionSponsorExpectSuccess, - enableAllowListExpectSuccess, - setMintPermissionExpectSuccess, - destroyCollectionExpectSuccess, - setCollectionSponsorExpectFailure, - confirmSponsorshipExpectFailure, - removeCollectionSponsorExpectFailure, - enableAllowListExpectFail, - setMintPermissionExpectFailure, - destroyCollectionExpectFailure, - setPublicAccessModeExpectSuccess, - queryCollectionExpectSuccess, -} from './util/helpers'; - -chai.use(chaiAsPromised); -const expect = chai.expect; +import {IKeyringPair} from '@polkadot/types/types'; +import {usingPlaygrounds, expect, itSub} from './util/playgrounds'; describe('Integration Test changeCollectionOwner(collection_id, new_owner):', () => { - it('Changing owner changes owner address', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); + let alice: IKeyringPair; + let bob: IKeyringPair; - const collection =await queryCollectionExpectSuccess(api, collectionId); - expect(collection.owner.toString()).to.be.deep.eq(alice.address); + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor); + }); + }); - const changeOwnerTx = api.tx.unique.changeCollectionOwner(collectionId, bob.address); - await submitTransactionAsync(alice, changeOwnerTx); + itSub('Changing owner changes owner address', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const beforeChanging = await helper.collection.getData(collection.collectionId); + expect(beforeChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(alice.address)); - const collectionAfterOwnerChange = await queryCollectionExpectSuccess(api, collectionId); - expect(collectionAfterOwnerChange.owner.toString()).to.be.deep.eq(bob.address); - }); + await collection.changeOwner(alice, bob.address); + const afterChanging = await helper.collection.getData(collection.collectionId); + expect(afterChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(bob.address)); }); }); describe('Integration Test changeCollectionOwner(collection_id, new_owner) special checks for exOwner:', () => { - it('Changing the owner of the collection is not allowed for the former owner', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); + let alice: IKeyringPair; + let bob: IKeyringPair; + let charlie: IKeyringPair; - const collection = await queryCollectionExpectSuccess(api, collectionId); - expect(collection.owner.toString()).to.be.deep.eq(alice.address); - - const changeOwnerTx = api.tx.unique.changeCollectionOwner(collectionId, bob.address); - await submitTransactionAsync(alice, changeOwnerTx); - - const badChangeOwnerTx = api.tx.unique.changeCollectionOwner(collectionId, alice.address); - await expect(submitTransactionExpectFailAsync(alice, badChangeOwnerTx)).to.be.rejected; - - const collectionAfterOwnerChange = await queryCollectionExpectSuccess(api, collectionId); - expect(collectionAfterOwnerChange.owner.toString()).to.be.deep.eq(bob.address); + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); }); - - it('New collectionOwner has access to sponsorship management operations in the collection', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//Charlie'); - const collection = await queryCollectionExpectSuccess(api, collectionId); - expect(collection.owner.toString()).to.be.deep.eq(alice.address); - - const changeOwnerTx = api.tx.unique.changeCollectionOwner(collectionId, bob.address); - await submitTransactionAsync(alice, changeOwnerTx); - - const collectionAfterOwnerChange = await queryCollectionExpectSuccess(api, collectionId); - expect(collectionAfterOwnerChange.owner.toString()).to.be.deep.eq(bob.address); + itSub('Changing the owner of the collection is not allowed for the former owner', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); - // After changing the owner of the collection, all privileged methods are available to the new owner - // The new owner of the collection has access to sponsorship management operations in the collection - await setCollectionSponsorExpectSuccess(collectionId, charlie.address, '//Bob'); - await confirmSponsorshipExpectSuccess(collectionId, '//Charlie'); - await removeCollectionSponsorExpectSuccess(collectionId, '//Bob'); + await collection.changeOwner(alice, bob.address); - // The new owner of the collection has access to operations for managing the collection parameters - const collectionLimits = { - accountTokenOwnershipLimit: 1, - sponsoredMintSize: 1, - tokenLimit: 1, - sponsorTransferTimeout: 1, - ownerCanTransfer: true, - ownerCanDestroy: true, - }; - const tx1 = api.tx.unique.setCollectionLimits( - collectionId, - collectionLimits, - ); - await submitTransactionAsync(bob, tx1); + const changeOwnerTx = async () => collection.changeOwner(alice, alice.address); + await expect(changeOwnerTx()).to.be.rejectedWith(/common\.NoPermission/); - await setPublicAccessModeExpectSuccess(bob, collectionId, 'AllowList'); - await enableAllowListExpectSuccess(bob, collectionId); - await setMintPermissionExpectSuccess(bob, collectionId, true); - await destroyCollectionExpectSuccess(collectionId, '//Bob'); - }); + const afterChanging = await helper.collection.getData(collection.collectionId); + expect(afterChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(bob.address)); }); - it('New collectionOwner has access to changeCollectionOwner', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//Charlie'); + itSub('New collectionOwner has access to sponsorship management operations in the collection', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.changeOwner(alice, bob.address); - const collection = await queryCollectionExpectSuccess(api, collectionId); - expect(collection.owner.toString()).to.be.deep.eq(alice.address); + const afterChanging = await helper.collection.getData(collection.collectionId); + expect(afterChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(bob.address)); - const changeOwnerTx = api.tx.unique.changeCollectionOwner(collectionId, bob.address); - await submitTransactionAsync(alice, changeOwnerTx); + await collection.setSponsor(bob, charlie.address); + await collection.confirmSponsorship(charlie); + await collection.removeSponsor(bob); + const limits = { + accountTokenOwnershipLimit: 1, + tokenLimit: 1, + sponsorTransferTimeout: 1, + ownerCanDestroy: true, + ownerCanTransfer: true, + }; - const collectionAfterOwnerChange = await queryCollectionExpectSuccess(api, collectionId); - expect(collectionAfterOwnerChange.owner.toString()).to.be.deep.eq(bob.address); + await collection.setLimits(bob, limits); + const gotLimits = await collection.getEffectiveLimits(); + expect(gotLimits).to.be.deep.contains(limits); - const changeOwnerTx2 = api.tx.unique.changeCollectionOwner(collectionId, charlie.address); - await submitTransactionAsync(bob, changeOwnerTx2); + await collection.setPermissions(bob, {access: 'AllowList', mintMode: true}); - // ownership lost - const collectionAfterOwnerChange2 = await queryCollectionExpectSuccess(api, collectionId); - expect(collectionAfterOwnerChange2.owner.toString()).to.be.deep.eq(charlie.address); - }); + await collection.burn(bob); + const collectionData = await helper.collection.getData(collection.collectionId); + expect(collectionData).to.be.null; }); + + itSub('New collectionOwner has access to changeCollectionOwner', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.changeOwner(alice, bob.address); + await collection.changeOwner(bob, charlie.address); + const collectionData = await collection.getData(); + expect(collectionData?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(charlie.address)); + }); }); describe('Negative Integration Test changeCollectionOwner(collection_id, new_owner):', () => { - it('Not owner can\'t change owner.', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - - const changeOwnerTx = api.tx.unique.changeCollectionOwner(collectionId, bob.address); - await expect(submitTransactionExpectFailAsync(bob, changeOwnerTx)).to.be.rejected; - - const collectionAfterOwnerChange = await queryCollectionExpectSuccess(api, collectionId); - expect(collectionAfterOwnerChange.owner.toString()).to.be.deep.eq(alice.address); + let alice: IKeyringPair; + let bob: IKeyringPair; + let charlie: IKeyringPair; - // Verifying that nothing bad happened (network is live, new collections can be created, etc.) - await createCollectionExpectSuccess(); + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); }); - it('Collection admin can\'t change owner.', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - - const changeOwnerTx = api.tx.unique.changeCollectionOwner(collectionId, bob.address); - await expect(submitTransactionExpectFailAsync(bob, changeOwnerTx)).to.be.rejected; - - const collectionAfterOwnerChange = await queryCollectionExpectSuccess(api, collectionId); - expect(collectionAfterOwnerChange.owner.toString()).to.be.deep.eq(alice.address); - - // Verifying that nothing bad happened (network is live, new collections can be created, etc.) - await createCollectionExpectSuccess(); - }); + itSub('Not owner can\'t change owner.', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const changeOwnerTx = async () => collection.changeOwner(bob, bob.address); + await expect(changeOwnerTx()).to.be.rejectedWith(/common\.NoPermission/); }); - it('Can\'t change owner of a non-existing collection.', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = (1<<32) - 1; - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - - const changeOwnerTx = api.tx.unique.changeCollectionOwner(collectionId, bob.address); - await expect(submitTransactionExpectFailAsync(alice, changeOwnerTx)).to.be.rejected; + itSub('Collection admin can\'t change owner.', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.addAdmin(alice, {Substrate: bob.address}); + const changeOwnerTx = async () => collection.changeOwner(bob, bob.address); + await expect(changeOwnerTx()).to.be.rejectedWith(/common\.NoPermission/); + }); - // Verifying that nothing bad happened (network is live, new collections can be created, etc.) - await createCollectionExpectSuccess(); - }); + itSub('Can\'t change owner of a non-existing collection.', async ({helper}) => { + const collectionId = (1 << 32) - 1; + const changeOwnerTx = async () => helper.collection.changeOwner(bob, collectionId, bob.address); + await expect(changeOwnerTx()).to.be.rejectedWith(/common\.CollectionNotFound/); }); - it('Former collectionOwner not allowed to sponsorship management operations in the collection', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess(); - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//Charlie'); + itSub('Former collectionOwner not allowed to sponsorship management operations in the collection', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.changeOwner(alice, bob.address); - const collection = await queryCollectionExpectSuccess(api, collectionId); - expect(collection.owner.toString()).to.be.deep.eq(alice.address); + const changeOwnerTx = async () => collection.changeOwner(alice, alice.address); + await expect(changeOwnerTx()).to.be.rejectedWith(/common\.NoPermission/); - const changeOwnerTx = api.tx.unique.changeCollectionOwner(collectionId, bob.address); - await submitTransactionAsync(alice, changeOwnerTx); + const afterChanging = await helper.collection.getData(collection.collectionId); + expect(afterChanging?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(bob.address)); - const badChangeOwnerTx = api.tx.unique.changeCollectionOwner(collectionId, alice.address); - await expect(submitTransactionExpectFailAsync(alice, badChangeOwnerTx)).to.be.rejected; + const setSponsorTx = async () => collection.setSponsor(alice, charlie.address); + const confirmSponsorshipTx = async () => collection.confirmSponsorship(alice); + const removeSponsorTx = async () => collection.removeSponsor(alice); + await expect(setSponsorTx()).to.be.rejectedWith(/common\.NoPermission/); + await expect(confirmSponsorshipTx()).to.be.rejectedWith(/unique\.ConfirmUnsetSponsorFail/); + await expect(removeSponsorTx()).to.be.rejectedWith(/common\.NoPermission/); - const collectionAfterOwnerChange = await queryCollectionExpectSuccess(api, collectionId); - expect(collectionAfterOwnerChange.owner.toString()).to.be.deep.eq(bob.address); + const limits = { + accountTokenOwnershipLimit: 1, + tokenLimit: 1, + sponsorTransferTimeout: 1, + ownerCanDestroy: true, + ownerCanTransfer: true, + }; - await setCollectionSponsorExpectFailure(collectionId, charlie.address, '//Alice'); - await confirmSponsorshipExpectFailure(collectionId, '//Alice'); - await removeCollectionSponsorExpectFailure(collectionId, '//Alice'); + const setLimitsTx = async () => collection.setLimits(alice, limits); + await expect(setLimitsTx()).to.be.rejectedWith(/common\.NoPermission/); - const collectionLimits = { - accountTokenOwnershipLimit: 1, - sponsoredMintSize: 1, - tokenLimit: 1, - sponsorTransferTimeout: 1, - ownerCanTransfer: true, - ownerCanDestroy: true, - }; - const tx1 = api.tx.unique.setCollectionLimits( - collectionId, - collectionLimits, - ); - await expect(submitTransactionExpectFailAsync(alice, tx1)).to.be.rejected; + const setPermissionTx = async () => collection.setPermissions(alice, {access: 'AllowList', mintMode: true}); + await expect(setPermissionTx()).to.be.rejectedWith(/common\.NoPermission/); - await enableAllowListExpectFail(alice, collectionId); - await setMintPermissionExpectFailure(alice, collectionId, true); - await destroyCollectionExpectFailure(collectionId, '//Alice'); - }); + const burnTx = async () => collection.burn(alice); + await expect(burnTx()).to.be.rejectedWith(/common\.NoPermission/); }); }); --- a/tests/src/confirmSponsorship.test.ts +++ b/tests/src/confirmSponsorship.test.ts @@ -14,404 +14,230 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api'; -import { - createCollectionExpectSuccess, - setCollectionSponsorExpectSuccess, - destroyCollectionExpectSuccess, - confirmSponsorshipExpectSuccess, - confirmSponsorshipExpectFailure, - createItemExpectSuccess, - findUnusedAddress, - getGenericResult, - enableAllowListExpectSuccess, - enablePublicMintingExpectSuccess, - addToAllowListExpectSuccess, - normalizeAccountId, - addCollectionAdminExpectSuccess, - getCreatedCollectionCount, - UNIQUE, - requirePallets, - Pallets, -} from './util/helpers'; import {IKeyringPair} from '@polkadot/types/types'; +import {usingPlaygrounds, expect, itSub, Pallets} from './util/playgrounds'; -chai.use(chaiAsPromised); -const expect = chai.expect; +async function setSponsorHelper(collection: any, signer: IKeyringPair, sponsorAddress: string) { + await collection.setSponsor(signer, sponsorAddress); + const raw = (await collection.getData())?.raw; + expect(raw.sponsorship.Unconfirmed).to.be.equal(sponsorAddress); +} -let alice: IKeyringPair; -let bob: IKeyringPair; -let charlie: IKeyringPair; +async function confirmSponsorHelper(collection: any, signer: IKeyringPair) { + await collection.confirmSponsorship(signer); + const raw = (await collection.getData())?.raw; + expect(raw.sponsorship.Confirmed).to.be.equal(signer.address); +} describe('integration test: ext. confirmSponsorship():', () => { + let alice: IKeyringPair; + let bob: IKeyringPair; + let charlie: IKeyringPair; + let zeroBalance: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob, charlie, zeroBalance] = await helper.arrange.createAccounts([100n, 100n, 100n, 0n], donor); }); }); - it('Confirm collection sponsorship', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); + itSub('Confirm collection sponsorship', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await setSponsorHelper(collection, alice, bob.address); + await confirmSponsorHelper(collection, bob); }); - it('Add sponsor to a collection after the same sponsor was already added and confirmed', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); + + itSub('Add sponsor to a collection after the same sponsor was already added and confirmed', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await setSponsorHelper(collection, alice, bob.address); + await confirmSponsorHelper(collection, bob); + await setSponsorHelper(collection, alice, bob.address); }); - it('Add new sponsor to a collection after another sponsor was already added and confirmed', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); - await setCollectionSponsorExpectSuccess(collectionId, charlie.address); + itSub('Add new sponsor to a collection after another sponsor was already added and confirmed', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await setSponsorHelper(collection, alice, bob.address); + await confirmSponsorHelper(collection, bob); + await setSponsorHelper(collection, alice, charlie.address); }); - it('NFT: Transfer fees are paid by the sponsor after confirmation', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); - - await usingApi(async (api, privateKeyWrapper) => { - const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt(); - - // Find unused address - const zeroBalance = await findUnusedAddress(api, privateKeyWrapper); - - // Mint token for unused address - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', zeroBalance.address); - - // Transfer this tokens from unused address to Alice - const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 0); - const events = await submitTransactionAsync(zeroBalance, zeroToAlice); - const result = getGenericResult(events); - expect(result.success).to.be.true; - - const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt(); - - expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; - }); - + itSub('NFT: Transfer fees are paid by the sponsor after confirmation', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.setSponsor(alice, bob.address); + await collection.confirmSponsorship(bob); + const bobBalanceBefore = await helper.balance.getSubstrate(bob.address); + const token = await collection.mintToken(alice, {Substrate: zeroBalance.address}); + await token.transfer(zeroBalance, {Substrate: alice.address}); + const bobBalanceAfter = await helper.balance.getSubstrate(bob.address); + expect(bobBalanceAfter < bobBalanceBefore).to.be.true; }); - it('Fungible: Transfer fees are paid by the sponsor after confirmation', async () => { - const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); - - await usingApi(async (api, privateKeyWrapper) => { - const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt(); - - // Find unused address - const zeroBalance = await findUnusedAddress(api, privateKeyWrapper); - - // Mint token for unused address - const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', zeroBalance.address); - - // Transfer this tokens from unused address to Alice - const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1); - const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice); - const result1 = getGenericResult(events1); - expect(result1.success).to.be.true; - - const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt(); - - expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; - }); + itSub('Fungible: Transfer fees are paid by the sponsor after confirmation', async ({helper}) => { + const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + await collection.setSponsor(alice, bob.address); + await collection.confirmSponsorship(bob); + const bobBalanceBefore = await helper.balance.getSubstrate(bob.address); + await collection.mint(alice, 100n, {Substrate: zeroBalance.address}); + await collection.transfer(zeroBalance, {Substrate: alice.address}, 1n); + const bobBalanceAfter = await helper.balance.getSubstrate(bob.address); + expect(bobBalanceAfter < bobBalanceBefore).to.be.true; }); - - it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); - - await usingApi(async (api, privateKeyWrapper) => { - const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt(); - // Find unused address - const zeroBalance = await findUnusedAddress(api, privateKeyWrapper); - - // Mint token for unused address - const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', zeroBalance.address); - - // Transfer this tokens from unused address to Alice - const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1); - const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice); - const result1 = getGenericResult(events1); - - const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt(); - - expect(result1.success).to.be.true; - expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; - }); + itSub.ifWithPallets('ReFungible: Transfer fees are paid by the sponsor after confirmation', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.setSponsor(alice, bob.address); + await collection.confirmSponsorship(bob); + const bobBalanceBefore = await helper.balance.getSubstrate(bob.address); + const token = await collection.mintToken(alice, 100n, {Substrate: zeroBalance.address}); + await token.transfer(zeroBalance, {Substrate: alice.address}, 1n); + const bobBalanceAfter = await helper.balance.getSubstrate(bob.address); + expect(bobBalanceAfter < bobBalanceBefore).to.be.true; }); - - it('CreateItem fees are paid by the sponsor after confirmation', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); - - // Enable collection allow list - await enableAllowListExpectSuccess(alice, collectionId); - // Enable public minting - await enablePublicMintingExpectSuccess(alice, collectionId); - - // Create Item - await usingApi(async (api, privateKeyWrapper) => { - const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt(); - - // Find unused address - const zeroBalance = await findUnusedAddress(api, privateKeyWrapper); - - // Add zeroBalance address to allow list - await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address); - - // Mint token using unused address as signer - await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address); + itSub('CreateItem fees are paid by the sponsor after confirmation', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.setSponsor(alice, bob.address); + await collection.confirmSponsorship(bob); + await collection.setPermissions(alice, {access: 'AllowList', mintMode: true}); + await collection.addToAllowList(alice, {Substrate: zeroBalance.address}); - const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt(); + const bobBalanceBefore = await helper.balance.getSubstrate(bob.address); + await collection.mintToken(zeroBalance, {Substrate: zeroBalance.address}); + const bobBalanceAfter = await helper.balance.getSubstrate(bob.address); - expect(sponsorBalanceAfter < sponsorBalanceBefore).to.be.true; - }); + expect(bobBalanceAfter < bobBalanceBefore).to.be.true; }); - it('NFT: Sponsoring of transfers is rate limited', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); + itSub('NFT: Sponsoring of transfers is rate limited', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.setSponsor(alice, bob.address); + await collection.confirmSponsorship(bob); - await usingApi(async (api, privateKeyWrapper) => { - // Find unused address - const zeroBalance = await findUnusedAddress(api, privateKeyWrapper); - - // Mint token for alice - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); + const token = await collection.mintToken(alice, {Substrate: alice.address}); + await token.transfer(alice, {Substrate: zeroBalance.address}); + const bobBalanceBefore = await helper.balance.getSubstrate(bob.address); - // Transfer this token from Alice to unused address and back - // Alice to Zero gets sponsored - const aliceToZero = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 0); - const events1 = await submitTransactionAsync(alice, aliceToZero); - const result1 = getGenericResult(events1); + const transferTx = async () => token.transfer(zeroBalance, {Substrate: alice.address}); + await expect(transferTx()).to.be.rejectedWith('Inability to pay some fees'); + const bobBalanceAfter = await helper.balance.getSubstrate(bob.address); - // Second transfer should fail - const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt(); - const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 0); - const badTransaction = async function () { - await submitTransactionExpectFailAsync(zeroBalance, zeroToAlice); - }; - await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees'); - const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt(); - - // Try again after Zero gets some balance - now it should succeed - const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE); - await submitTransactionAsync(alice, balancetx); - const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice); - const result2 = getGenericResult(events2); - - expect(result1.success).to.be.true; - expect(result2.success).to.be.true; - expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore); - }); + expect(bobBalanceAfter === bobBalanceBefore).to.be.true; }); - it('Fungible: Sponsoring is rate limited', async () => { - const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); - - await usingApi(async (api, privateKeyWrapper) => { - // Find unused address - const zeroBalance = await findUnusedAddress(api, privateKeyWrapper); - - // Mint token for unused address - const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', zeroBalance.address); - - // Transfer this tokens in parts from unused address to Alice - const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(zeroBalance.address), collectionId, itemId, 1); - const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice); - const result1 = getGenericResult(events1); - expect(result1.success).to.be.true; + itSub('Fungible: Sponsoring is rate limited', async ({helper}) => { + const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.setSponsor(alice, bob.address); + await collection.confirmSponsorship(bob); - const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt(); - await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejected; - const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt(); + await collection.mint(alice, 100n, {Substrate: zeroBalance.address}); + await collection.transfer(zeroBalance, {Substrate: zeroBalance.address}, 1n); + const bobBalanceBefore = await helper.balance.getSubstrate(bob.address); - // Try again after Zero gets some balance - now it should succeed - const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE); - await submitTransactionAsync(alice, balancetx); - const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice); - const result2 = getGenericResult(events2); - expect(result2.success).to.be.true; + const transferTx = async () => collection.transfer(zeroBalance, {Substrate: zeroBalance.address}); + await expect(transferTx()).to.be.rejected; + const bobBalanceAfter = await helper.balance.getSubstrate(bob.address); - expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore); - }); + expect(bobBalanceAfter === bobBalanceBefore).to.be.true; }); - - it('ReFungible: Sponsoring is rate limited', async function() { - await requirePallets(this, [Pallets.ReFungible]); - const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); - - await usingApi(async (api, privateKeyWrapper) => { - // Find unused address - const zeroBalance = await findUnusedAddress(api, privateKeyWrapper); - - // Mint token for alice - const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', zeroBalance.address); + itSub.ifWithPallets('ReFungible: Sponsoring is rate limited', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.setSponsor(alice, bob.address); + await collection.confirmSponsorship(bob); - const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 1); - - // Zero to alice gets sponsored - const events1 = await submitTransactionAsync(zeroBalance, zeroToAlice); - const result1 = getGenericResult(events1); - expect(result1.success).to.be.true; + const token = await collection.mintToken(alice, 100n, {Substrate: zeroBalance.address}); + await token.transfer(zeroBalance, {Substrate: alice.address}); - // Second transfer should fail - const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt(); - await expect(submitTransactionExpectFailAsync(zeroBalance, zeroToAlice)).to.be.rejectedWith('Inability to pay some fees'); - const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt(); - expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore); + const bobBalanceBefore = await helper.balance.getSubstrate(bob.address); + const transferTx = async () => token.transfer(zeroBalance, {Substrate: alice.address}); + await expect(transferTx()).to.be.rejectedWith('Inability to pay some fees'); + const bobBalanceAfter = await helper.balance.getSubstrate(bob.address); - // Try again after Zero gets some balance - now it should succeed - const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE); - await submitTransactionAsync(alice, balancetx); - const events2 = await submitTransactionAsync(zeroBalance, zeroToAlice); - const result2 = getGenericResult(events2); - expect(result2.success).to.be.true; - }); + expect(bobBalanceAfter === bobBalanceBefore).to.be.true; }); - it('NFT: Sponsoring of createItem is rate limited', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); - - // Enable collection allow list - await enableAllowListExpectSuccess(alice, collectionId); - - // Enable public minting - await enablePublicMintingExpectSuccess(alice, collectionId); - - await usingApi(async (api, privateKeyWrapper) => { - // Find unused address - const zeroBalance = await findUnusedAddress(api, privateKeyWrapper); - - // Add zeroBalance address to allow list - await addToAllowListExpectSuccess(alice, collectionId, zeroBalance.address); + itSub('NFT: Sponsoring of createItem is rate limited', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.setSponsor(alice, bob.address); + await collection.confirmSponsorship(bob); + await collection.setPermissions(alice, {mintMode: true, access: 'AllowList'}); + await collection.addToAllowList(alice, {Substrate: zeroBalance.address}); - // Mint token using unused address as signer - gets sponsored - await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address); + await collection.mintToken(zeroBalance, {Substrate: zeroBalance.address}); - // Second mint should fail - const sponsorBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt(); + const bobBalanceBefore = await helper.balance.getSubstrate(bob.address); + const mintTx = async () => collection.mintToken(zeroBalance, {Substrate: zeroBalance.address}); + await expect(mintTx()).to.be.rejectedWith('Inability to pay some fees'); + const bobBalanceAfter = await helper.balance.getSubstrate(bob.address); - const badTransaction = async function () { - await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address); - }; - await expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees'); - const sponsorBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt(); - - // Try again after Zero gets some balance - now it should succeed - const balancetx = api.tx.balances.transfer(zeroBalance.address, 1n * UNIQUE); - await submitTransactionAsync(alice, balancetx); - await createItemExpectSuccess(zeroBalance, collectionId, 'NFT', zeroBalance.address); - - expect(sponsorBalanceAfter).to.be.equal(sponsorBalanceBefore); - }); + expect(bobBalanceAfter === bobBalanceBefore).to.be.true; }); - }); describe('(!negative test!) integration test: ext. confirmSponsorship():', () => { + let alice: IKeyringPair; + let bob: IKeyringPair; + let charlie: IKeyringPair; + let ownerZeroBalance: IKeyringPair; + let senderZeroBalance: IKeyringPair; + before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob, charlie, ownerZeroBalance, senderZeroBalance] = await helper.arrange.createAccounts([100n, 100n, 100n, 0n, 0n], donor); }); }); - it('(!negative test!) Confirm sponsorship for a collection that never existed', async () => { - // Find the collection that never existed - let collectionId = 0; - await usingApi(async (api) => { - collectionId = await getCreatedCollectionCount(api) + 1; - }); - - await confirmSponsorshipExpectFailure(collectionId, '//Bob'); + itSub('(!negative test!) Confirm sponsorship for a collection that never existed', async ({helper}) => { + const collectionId = 1_000_000; + const confirmSponsorshipTx = async () => helper.collection.confirmSponsorship(bob, collectionId); + await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.CollectionNotFound/); }); - - it('(!negative test!) Confirm sponsorship using a non-sponsor address', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - - await usingApi(async (api) => { - const transfer = api.tx.balances.transfer(charlie.address, 1e15); - await submitTransactionAsync(alice, transfer); - }); - await confirmSponsorshipExpectFailure(collectionId, '//Charlie'); + itSub('(!negative test!) Confirm sponsorship using a non-sponsor address', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.setSponsor(alice, bob.address); + const confirmSponsorshipTx = async () => collection.confirmSponsorship(charlie); + await expect(confirmSponsorshipTx()).to.be.rejectedWith(/unique\.ConfirmUnsetSponsorFail/); }); - it('(!negative test!) Confirm sponsorship using owner address', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectFailure(collectionId, '//Alice'); + itSub('(!negative test!) Confirm sponsorship using owner address', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.setSponsor(alice, bob.address); + const confirmSponsorshipTx = async () => collection.confirmSponsorship(alice); + await expect(confirmSponsorshipTx()).to.be.rejectedWith(/unique\.ConfirmUnsetSponsorFail/); }); - it('(!negative test!) Confirm sponsorship by collection admin', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await addCollectionAdminExpectSuccess(alice, collectionId, charlie.address); - await confirmSponsorshipExpectFailure(collectionId, '//Charlie'); + itSub('(!negative test!) Confirm sponsorship by collection admin', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.setSponsor(alice, bob.address); + await collection.addAdmin(alice, {Substrate: charlie.address}); + const confirmSponsorshipTx = async () => collection.confirmSponsorship(charlie); + await expect(confirmSponsorshipTx()).to.be.rejectedWith(/unique\.ConfirmUnsetSponsorFail/); }); - it('(!negative test!) Confirm sponsorship without sponsor being set with setCollectionSponsor', async () => { - const collectionId = await createCollectionExpectSuccess(); - await confirmSponsorshipExpectFailure(collectionId, '//Bob'); + itSub('(!negative test!) Confirm sponsorship without sponsor being set with setCollectionSponsor', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const confirmSponsorshipTx = async () => collection.confirmSponsorship(charlie); + await expect(confirmSponsorshipTx()).to.be.rejectedWith(/unique\.ConfirmUnsetSponsorFail/); }); - it('(!negative test!) Confirm sponsorship in a collection that was destroyed', async () => { - const collectionId = await createCollectionExpectSuccess(); - await destroyCollectionExpectSuccess(collectionId); - await confirmSponsorshipExpectFailure(collectionId, '//Bob'); + itSub('(!negative test!) Confirm sponsorship in a collection that was destroyed', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.burn(alice); + const confirmSponsorshipTx = async () => collection.confirmSponsorship(charlie); + await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.CollectionNotFound/); }); - it('(!negative test!) Transfer fees are not paid by the sponsor if the transfer failed', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionSponsorExpectSuccess(collectionId, bob.address); - await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); - - await usingApi(async (api, privateKeyWrapper) => { - // Find unused address - const ownerZeroBalance = await findUnusedAddress(api, privateKeyWrapper); - - // Find another unused address - const senderZeroBalance = await findUnusedAddress(api, privateKeyWrapper); - - // Mint token for an unused address - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', ownerZeroBalance.address); - - const sponsorBalanceBeforeTx = (await api.query.system.account(bob.address)).data.free.toBigInt(); - - // Try to transfer this token from an unsponsored unused adress to Alice - const zeroToAlice = api.tx.unique.transfer(normalizeAccountId(alice.address), collectionId, itemId, 0); - await expect(submitTransactionExpectFailAsync(senderZeroBalance, zeroToAlice)).to.be.rejected; - - const sponsorBalanceAfterTx = (await api.query.system.account(bob.address)).data.free.toBigInt(); - - expect(sponsorBalanceAfterTx).to.equal(sponsorBalanceBeforeTx); - }); + itSub('(!negative test!) Transfer fees are not paid by the sponsor if the transfer failed', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.setSponsor(alice, bob.address); + await collection.confirmSponsorship(bob); + const token = await collection.mintToken(alice, {Substrate: ownerZeroBalance.address}); + const sponsorBalanceBefore = await helper.balance.getSubstrate(bob.address); + const transferTx = async () => token.transfer(senderZeroBalance, {Substrate: alice.address}); + await expect(transferTx()).to.be.rejectedWith('Inability to pay some fees'); + const sponsorBalanceAfter = await helper.balance.getSubstrate(bob.address); + expect(sponsorBalanceAfter).to.equal(sponsorBalanceBefore); }); }); --- a/tests/src/createCollection.test.ts +++ b/tests/src/createCollection.test.ts @@ -14,130 +14,143 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import {expect} from 'chai'; -import usingApi, {executeTransaction, submitTransactionAsync} from './substrate/substrate-api'; -import {createCollectionWithPropsExpectFailure, createCollectionExpectFailure, createCollectionExpectSuccess, getCreateCollectionResult, getDetailedCollectionInfo, createCollectionWithPropsExpectSuccess, requirePallets, Pallets} from './util/helpers'; +import {IKeyringPair} from '@polkadot/types/types'; +import {usingPlaygrounds, expect, itSub, Pallets} from './util/playgrounds'; +import {ICollectionCreationOptions, IProperty} from './util/playgrounds/types'; +import {UniqueHelper} from './util/playgrounds/unique'; +async function mintCollectionHelper(helper: UniqueHelper, signer: IKeyringPair, options: ICollectionCreationOptions, type?: 'nft' | 'fungible' | 'refungible') { + let collection; + if (type === 'nft') { + collection = await helper.nft.mintCollection(signer, options); + } else if (type === 'fungible') { + collection = await helper.ft.mintCollection(signer, options, 0); + } else { + collection = await helper.rft.mintCollection(signer, options); + } + const data = await collection.getData(); + expect(data?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(signer.address)); + expect(data?.name).to.be.equal(options.name); + expect(data?.description).to.be.equal(options.description); + expect(data?.raw.tokenPrefix).to.be.equal(options.tokenPrefix); + if (options.properties) { + expect(data?.raw.properties).to.be.deep.equal(options.properties); + } + + if (options.tokenPropertyPermissions) { + expect(data?.raw.tokenPropertyPermissions).to.be.deep.equal(options.tokenPropertyPermissions); + } + + return collection; +} + describe('integration test: ext. createCollection():', () => { - it('Create new NFT collection', async () => { - await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}}); + let alice: IKeyringPair; + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice] = await helper.arrange.createAccounts([100n], donor); + }); }); - it('Create new NFT collection whith collection_name of maximum length (64 bytes)', async () => { - await createCollectionExpectSuccess({name: 'A'.repeat(64)}); + itSub('Create new NFT collection', async ({helper}) => { + await mintCollectionHelper(helper, alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 'nft'); }); - it('Create new NFT collection whith collection_description of maximum length (256 bytes)', async () => { - await createCollectionExpectSuccess({description: 'A'.repeat(256)}); + itSub('Create new NFT collection whith collection_name of maximum length (64 bytes)', async ({helper}) => { + await mintCollectionHelper(helper, alice, {name: 'A'.repeat(64), description: 'descr', tokenPrefix: 'COL'}, 'nft'); }); - it('Create new NFT collection whith token_prefix of maximum length (16 bytes)', async () => { - await createCollectionExpectSuccess({tokenPrefix: 'A'.repeat(16)}); + itSub('Create new NFT collection whith collection_description of maximum length (256 bytes)', async ({helper}) => { + await mintCollectionHelper(helper, alice, {name: 'name', description: 'A'.repeat(256), tokenPrefix: 'COL'}, 'nft'); }); - it('Create new Fungible collection', async () => { - await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); + itSub('Create new NFT collection whith token_prefix of maximum length (16 bytes)', async ({helper}) => { + await mintCollectionHelper(helper, alice, {name: 'name', description: 'descr', tokenPrefix: 'A'.repeat(16)}, 'nft'); }); - it('Create new ReFungible collection', async function() { - await requirePallets(this, [Pallets.ReFungible]); - await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); + itSub('Create new Fungible collection', async ({helper}) => { + await mintCollectionHelper(helper, alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}, 'fungible'); }); - it('create new collection with properties #1', async () => { - await createCollectionWithPropsExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}, - properties: [{key: 'key1', value: 'val1'}], - propPerm: [{key: 'key1', permission: {tokenOwner: true, mutable: false, collectionAdmin: true}}]}); + itSub.ifWithPallets('Create new ReFungible collection', [Pallets.ReFungible], async ({helper}) => { + await mintCollectionHelper(helper, alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}, 'refungible'); }); - it('create new collection with properties #2', async () => { - await createCollectionWithPropsExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}, + itSub('create new collection with properties', async ({helper}) => { + await mintCollectionHelper(helper, alice, { + name: 'name', description: 'descr', tokenPrefix: 'COL', properties: [{key: 'key1', value: 'val1'}], - propPerm: [{key: 'key1', permission: {tokenOwner: true, mutable: false, collectionAdmin: true}}]}); + tokenPropertyPermissions: [{key: 'key1', permission: {tokenOwner: true, mutable: false, collectionAdmin: true}}], + }, 'nft'); }); - it('create new collection with properties #3', async () => { - await createCollectionWithPropsExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}, - properties: [{key: 'key1', value: 'val1'}], - propPerm: [{key: 'key1', permission: {tokenOwner: true, mutable: false, collectionAdmin: true}}]}); - }); + itSub('Create new collection with extra fields', async ({helper}) => { + const collection = await mintCollectionHelper(helper, alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}, 'fungible'); + await collection.setPermissions(alice, {access: 'AllowList'}); + await collection.setLimits(alice, {accountTokenOwnershipLimit: 3}); + const data = await collection.getData(); + const limits = await collection.getEffectiveLimits(); + const raw = data?.raw; - it('Create new collection with extra fields', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const tx = api.tx.unique.createCollectionEx({ - mode: {Fungible: 8}, - permissions: { - access: 'AllowList', - }, - name: [1], - description: [2], - tokenPrefix: '0x000000', - pendingSponsor: bob.address, - limits: { - accountTokenOwnershipLimit: 3, - }, - }); - const events = await submitTransactionAsync(alice, tx); - const result = getCreateCollectionResult(events); + expect(data?.normalizedOwner).to.be.equal(helper.address.normalizeSubstrate(alice.address)); + expect(data?.name).to.be.equal('name'); + expect(data?.description).to.be.equal('descr'); + expect(raw.permissions.access).to.be.equal('AllowList'); + expect(raw.mode).to.be.deep.equal({Fungible: '0'}); + expect(limits.accountTokenOwnershipLimit).to.be.equal(3); + }); - const collection = (await getDetailedCollectionInfo(api, result.collectionId))!; - expect(collection.owner.toString()).to.equal(alice.address); - expect(collection.mode.asFungible.toNumber()).to.equal(8); - expect(collection.permissions.access.toHuman()).to.equal('AllowList'); - expect(collection.name.map(v => v.toNumber())).to.deep.equal([1]); - expect(collection.description.map(v => v.toNumber())).to.deep.equal([2]); - expect(collection.tokenPrefix.toString()).to.equal('0x000000'); - expect(collection.sponsorship.asUnconfirmed.toString()).to.equal(bob.address); - expect(collection.limits.accountTokenOwnershipLimit.unwrap().toNumber()).to.equal(3); - }); + itSub('New collection is not external', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL'}); + const data = await collection.getData(); + expect(data?.raw.readOnly).to.be.false; }); +}); - it('New collection is not external', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const tx = api.tx.unique.createCollectionEx({ }); - const events = await submitTransactionAsync(alice, tx); - const result = getCreateCollectionResult(events); +describe('(!negative test!) integration test: ext. createCollection():', () => { + let alice: IKeyringPair; - const collection = (await getDetailedCollectionInfo(api, result.collectionId))!; - expect(collection.readOnly.toHuman()).to.be.false; + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice] = await helper.arrange.createAccounts([100n], donor); }); }); -}); -describe('(!negative test!) integration test: ext. createCollection():', () => { - it('(!negative test!) create new NFT collection whith incorrect data (collection_name)', async () => { - await createCollectionExpectFailure({name: 'A'.repeat(65), mode: {type: 'NFT'}}); + itSub('(!negative test!) create new NFT collection whith incorrect data (collection_name)', async ({helper}) => { + const mintCollectionTx = async () => helper.nft.mintCollection(alice, {name: 'A'.repeat(65), description: 'descr', tokenPrefix: 'COL'}); + await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error'); }); - it('(!negative test!) create new NFT collection whith incorrect data (collection_description)', async () => { - await createCollectionExpectFailure({description: 'A'.repeat(257), mode: {type: 'NFT'}}); + itSub('(!negative test!) create new NFT collection whith incorrect data (collection_description)', async ({helper}) => { + const mintCollectionTx = async () => helper.nft.mintCollection(alice, {name: 'name', description: 'A'.repeat(257), tokenPrefix: 'COL'}); + await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error'); }); - it('(!negative test!) create new NFT collection whith incorrect data (token_prefix)', async () => { - await createCollectionExpectFailure({tokenPrefix: 'A'.repeat(17), mode: {type: 'NFT'}}); + itSub('(!negative test!) create new NFT collection whith incorrect data (token_prefix)', async ({helper}) => { + const mintCollectionTx = async () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'A'.repeat(17)}); + await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error'); }); - it('fails when bad limits are set', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const tx = api.tx.unique.createCollectionEx({mode: 'NFT', limits: {tokenLimit: 0}}); - await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/^common.CollectionTokenLimitExceeded$/); - }); + + itSub('(!negative test!) fails when bad limits are set', async ({helper}) => { + const mintCollectionTx = async () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', limits: {tokenLimit: 0}}); + await expect(mintCollectionTx()).to.be.rejectedWith(/common\.CollectionTokenLimitExceeded/); }); - it('(!negative test!) create collection with incorrect property limit (64 elements)', async () => { - const props = []; + itSub('(!negative test!) create collection with incorrect property limit (64 elements)', async ({helper}) => { + const props: IProperty[] = []; for (let i = 0; i < 65; i++) { props.push({key: `key${i}`, value: `value${i}`}); } - - await createCollectionWithPropsExpectFailure({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}, properties: props}); + const mintCollectionTx = async () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', properties: props}); + await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error'); }); - it('(!negative test!) create collection with incorrect property limit (40 kb)', async () => { - const props = []; + itSub('(!negative test!) create collection with incorrect property limit (40 kb)', async ({helper}) => { + const props: IProperty[] = []; for (let i = 0; i < 32; i++) { props.push({key: `key${i}`.repeat(80), value: `value${i}`.repeat(80)}); } - await createCollectionWithPropsExpectFailure({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}, properties: props}); + const mintCollectionTx = async () => helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', properties: props}); + await expect(mintCollectionTx()).to.be.rejectedWith('Verification Error'); }); }); --- a/tests/src/createItem.test.ts +++ b/tests/src/createItem.test.ts @@ -14,308 +14,259 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import {default as usingApi, executeTransaction} from './substrate/substrate-api'; -import chai from 'chai'; import {IKeyringPair} from '@polkadot/types/types'; -import { - createCollectionExpectSuccess, - createItemExpectSuccess, - addCollectionAdminExpectSuccess, - createCollectionWithPropsExpectSuccess, - createItemWithPropsExpectSuccess, - createItemWithPropsExpectFailure, - createCollection, - transferExpectSuccess, - itApi, - normalizeAccountId, - getCreateItemResult, - requirePallets, - Pallets, -} from './util/helpers'; +import {usingPlaygrounds, expect, itSub, Pallets} from './util/playgrounds'; +import {IProperty, ICrossAccountId} from './util/playgrounds/types'; +import {UniqueHelper} from './util/playgrounds/unique'; + +async function mintTokenHelper(helper: UniqueHelper, collection: any, signer: IKeyringPair, owner: ICrossAccountId, type: 'nft' | 'fungible' | 'refungible'='nft', properties?: IProperty[]) { + let token; + const itemCountBefore = await helper.collection.getLastTokenId(collection.collectionId); + const itemBalanceBefore = (await helper.callRpc('api.rpc.unique.balance', [collection.collectionId, owner, 0])).toBigInt(); + if (type === 'nft') { + token = await collection.mintToken(signer, owner, properties); + } else if (type === 'fungible') { + await collection.mint(signer, 10n, owner); + } else { + token = await collection.mintToken(signer, 100n, owner, properties); + } + + const itemCountAfter = await helper.collection.getLastTokenId(collection.collectionId); + const itemBalanceAfter = (await helper.callRpc('api.rpc.unique.balance', [collection.collectionId, owner, 0])).toBigInt(); + + if (type === 'fungible') { + expect(itemBalanceAfter - itemBalanceBefore).to.be.equal(10n); + } else { + expect(itemCountAfter).to.be.equal(itemCountBefore + 1); + } + + return token; +} -const expect = chai.expect; -let alice: IKeyringPair; -let bob: IKeyringPair; describe('integration test: ext. ():', () => { + let alice: IKeyringPair; + let bob: IKeyringPair; + before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor); }); }); - it('Create new item in NFT collection', async () => { - const createMode = 'NFT'; - const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}}); - await createItemExpectSuccess(alice, newCollectionID, createMode); + itSub('Create new item in NFT collection', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await mintTokenHelper(helper, collection, alice, {Substrate: alice.address}); }); - it('Create new item in Fungible collection', async () => { - const createMode = 'Fungible'; - const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}}); - await createItemExpectSuccess(alice, newCollectionID, createMode); + itSub('Create new item in Fungible collection', async ({helper}) => { + const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + await mintTokenHelper(helper, collection, alice, {Substrate: alice.address}, 'fungible'); }); - itApi('Check events on create new item in Fungible collection', async ({api}) => { - const createMode = 'Fungible'; - - const newCollectionID = (await createCollection(api, alice, {mode: {type: createMode, decimalPoints: 0}})).collectionId; - - const to = normalizeAccountId(alice); + itSub('Check events on create new item in Fungible collection', async ({helper}) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}, 0); + const to = {Substrate: alice.address}; { const createData = {fungible: {value: 100}}; - const tx = api.tx.unique.createItem(newCollectionID, to, createData as any); - const events = await executeTransaction(api, alice, tx); - const result = getCreateItemResult(events); - expect(result.amount).to.be.equal(100); - expect(result.collectionId).to.be.equal(newCollectionID); - expect(result.recipient).to.be.deep.equal(to); + const events = await helper.executeExtrinsic(alice, 'api.tx.unique.createItem', [collectionId, to, createData as any]); + const result = helper.util.extractTokensFromCreationResult(events); + expect(result.tokens[0].amount).to.be.equal(100n); + expect(result.tokens[0].collectionId).to.be.equal(collectionId); + expect(result.tokens[0].owner).to.be.deep.equal(to); } { const createData = {fungible: {value: 50}}; - const tx = api.tx.unique.createItem(newCollectionID, to, createData as any); - const events = await executeTransaction(api, alice, tx); - const result = getCreateItemResult(events); - expect(result.amount).to.be.equal(50); - expect(result.collectionId).to.be.equal(newCollectionID); - expect(result.recipient).to.be.deep.equal(to); + const events = await helper.executeExtrinsic(alice, 'api.tx.unique.createItem', [collectionId, to, createData as any]); + const result = helper.util.extractTokensFromCreationResult(events); + expect(result.tokens[0].amount).to.be.equal(50n); + expect(result.tokens[0].collectionId).to.be.equal(collectionId); + expect(result.tokens[0].owner).to.be.deep.equal(to); } - }); - it('Create new item in ReFungible collection', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - const createMode = 'ReFungible'; - const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}}); - await createItemExpectSuccess(alice, newCollectionID, createMode); + itSub.ifWithPallets('Create new item in ReFungible collection', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await mintTokenHelper(helper, collection, alice, {Substrate: alice.address}, 'refungible'); }); - it('Create new item in NFT collection with collection admin permissions', async () => { - const createMode = 'NFT'; - const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}}); - await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address); - await createItemExpectSuccess(bob, newCollectionID, createMode); + itSub('Create new item in NFT collection with collection admin permissions', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.addAdmin(alice, {Substrate: bob.address}); + await mintTokenHelper(helper, collection, bob, {Substrate: alice.address}); }); - it('Create new item in Fungible collection with collection admin permissions', async () => { - const createMode = 'Fungible'; - const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}}); - await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address); - await createItemExpectSuccess(bob, newCollectionID, createMode); + itSub('Create new item in Fungible collection with collection admin permissions', async ({helper}) => { + const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + await collection.addAdmin(alice, {Substrate: bob.address}); + await mintTokenHelper(helper, collection, bob, {Substrate: alice.address}, 'fungible'); }); - it('Create new item in ReFungible collection with collection admin permissions', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - const createMode = 'ReFungible'; - const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}}); - await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address); - await createItemExpectSuccess(bob, newCollectionID, createMode); + itSub.ifWithPallets('Create new item in ReFungible collection with collection admin permissions', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await collection.addAdmin(alice, {Substrate: bob.address}); + await mintTokenHelper(helper, collection, bob, {Substrate: alice.address}, 'refungible'); }); - it('Set property Admin', async () => { - const createMode = 'NFT'; - const newCollectionID = await createCollectionWithPropsExpectSuccess({mode: {type: createMode}, - propPerm: [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: false}}]}); - - await createItemWithPropsExpectSuccess(alice, newCollectionID, createMode, [{key: 'k', value: 't2'}]); + itSub('Set property Admin', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', + properties: [{key: 'k', value: 'v'}], + tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: false, mutable: true, collectionAdmin: true}}], + }); + await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'nft', [{key: 'k', value: 'v'}]); }); - it('Set property AdminConst', async () => { - const createMode = 'NFT'; - const newCollectionID = await createCollectionWithPropsExpectSuccess({mode: {type: createMode}, - propPerm: [{key: 'key1', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}}]}); - - await createItemWithPropsExpectSuccess(alice, newCollectionID, createMode, [{key: 'key1', value: 'val1'}]); - }); - - it('Set property itemOwnerOrAdmin', async () => { - const createMode = 'NFT'; - const newCollectionID = await createCollectionWithPropsExpectSuccess({mode: {type: createMode}, - propPerm: [{key: 'key1', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]}); - - await createItemWithPropsExpectSuccess(alice, newCollectionID, createMode, [{key: 'key1', value: 'val1'}]); - }); - - it('Check total pieces of Fungible token', async () => { - await usingApi(async api => { - const createMode = 'Fungible'; - const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}}); - const amountPieces = 10n; - const tokenId = await createItemExpectSuccess(alice, collectionId, createMode, bob.address); - { - const totalPieces = await api.rpc.unique.totalPieces(collectionId, tokenId); - expect(totalPieces.isSome).to.be.true; - expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); - } - - await transferExpectSuccess(collectionId, tokenId, bob, alice, 1, createMode); - { - const totalPieces = await api.rpc.unique.totalPieces(collectionId, tokenId); - expect(totalPieces.isSome).to.be.true; - expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); - } - - const totalPieces = (await api.rpc.unique.tokenData(collectionId, tokenId, [])).pieces; - expect(totalPieces.toBigInt()).to.be.eq(amountPieces); + itSub('Set property AdminConst', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', + properties: [{key: 'k', value: 'v'}], + tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: false, mutable: false, collectionAdmin: true}}], }); + await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'nft', [{key: 'k', value: 'v'}]); }); - it('Check total pieces of NFT token', async () => { - await usingApi(async api => { - const createMode = 'NFT'; - const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}}); - const amountPieces = 1n; - const tokenId = await createItemExpectSuccess(alice, collectionId, createMode, bob.address); - { - const totalPieces = await api.rpc.unique.totalPieces(collectionId, tokenId); - expect(totalPieces.isSome).to.be.true; - expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); - } - - await transferExpectSuccess(collectionId, tokenId, bob, alice, 1, createMode); - { - const totalPieces = await api.rpc.unique.totalPieces(collectionId, tokenId); - expect(totalPieces.isSome).to.be.true; - expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); - } - - const totalPieces = (await api.rpc.unique.tokenData(collectionId, tokenId, [])).pieces; - expect(totalPieces.toBigInt()).to.be.eq(amountPieces); + itSub('Set property itemOwnerOrAdmin', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'name', description: 'descr', tokenPrefix: 'COL', + properties: [{key: 'k', value: 'v'}], + tokenPropertyPermissions: [{key: 'k', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}], }); + await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'nft', [{key: 'k', value: 'v'}]); }); - it('Check total pieces of ReFungible token', async function() { - await requirePallets(this, [Pallets.ReFungible]); + itSub('Check total pieces of Fungible token', async ({helper}) => { + const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + const amount = 10n; + await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'fungible'); + { + const totalPieces = await collection.getTotalPieces(); + expect(totalPieces).to.be.equal(amount); + } + await collection.transfer(bob, {Substrate: alice.address}, 1n); + { + const totalPieces = await collection.getTotalPieces(); + expect(totalPieces).to.be.equal(amount); + } + }); - await usingApi(async api => { - const createMode = 'ReFungible'; - const createCollectionResult = await createCollection(api, alice, {mode: {type: createMode}}); - const collectionId = createCollectionResult.collectionId; - const amountPieces = 100n; - const tokenId = await createItemExpectSuccess(alice, collectionId, createMode, bob.address); - { - const totalPieces = await api.rpc.unique.totalPieces(collectionId, tokenId); - expect(totalPieces.isSome).to.be.true; - expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); - } + itSub('Check total pieces of NFT token', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const amount = 1n; + const token = await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}); + { + const totalPieces = await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, token.tokenId]); + expect(totalPieces?.unwrap().toBigInt()).to.be.equal(amount); + } + await token.transfer(bob, {Substrate: alice.address}); + { + const totalPieces = await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, token.tokenId]); + expect(totalPieces?.unwrap().toBigInt()).to.be.equal(amount); + } + }); - await transferExpectSuccess(collectionId, tokenId, bob, alice, 60n, createMode); - { - const totalPieces = await api.rpc.unique.totalPieces(collectionId, tokenId); - expect(totalPieces.isSome).to.be.true; - expect(totalPieces.unwrap().toBigInt()).to.be.eq(amountPieces); - } - - const totalPieces = (await api.rpc.unique.tokenData(collectionId, tokenId, [])).pieces; - expect(totalPieces.toBigInt()).to.be.eq(amountPieces); - }); + itSub.ifWithPallets('Check total pieces of ReFungible token', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const amount = 100n; + const token = await mintTokenHelper(helper, collection, alice, {Substrate: bob.address}, 'refungible'); + { + const totalPieces = await token.getTotalPieces(); + expect(totalPieces).to.be.equal(amount); + } + await token.transfer(bob, {Substrate: alice.address}, 60n); + { + const totalPieces = await token.getTotalPieces(); + expect(totalPieces).to.be.equal(amount); + } }); }); describe('Negative integration test: ext. createItem():', () => { + let alice: IKeyringPair; + let bob: IKeyringPair; + before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor); }); }); - it('Regular user cannot create new item in NFT collection', async () => { - const createMode = 'NFT'; - const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}}); - await expect(createItemExpectSuccess(bob, newCollectionID, createMode)).to.be.rejected; + itSub('Regular user cannot create new item in NFT collection', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const mintTx = async () => collection.mintToken(bob, {Substrate: bob.address}); + await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/); }); - it('Regular user cannot create new item in Fungible collection', async () => { - const createMode = 'Fungible'; - const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}}); - await expect(createItemExpectSuccess(bob, newCollectionID, createMode)).to.be.rejected; + itSub('Regular user cannot create new item in Fungible collection', async ({helper}) => { + const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + const mintTx = async () => collection.mint(bob, 10n, {Substrate: bob.address}); + await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/); }); - it('Regular user cannot create new item in ReFungible collection', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - const createMode = 'ReFungible'; - const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}}); - await expect(createItemExpectSuccess(bob, newCollectionID, createMode)).to.be.rejected; + itSub.ifWithPallets('Regular user cannot create new item in ReFungible collection', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const mintTx = async () => collection.mintToken(bob, 100n, {Substrate: bob.address}); + await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/); }); - it('No editing rights', async () => { - await usingApi(async () => { - const createMode = 'NFT'; - const newCollectionID = await createCollectionWithPropsExpectSuccess({mode: {type: createMode}, - propPerm: [{key: 'key1', permission: {mutable: false, collectionAdmin: false, tokenOwner: false}}]}); - await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address); - - await createItemWithPropsExpectFailure(bob, newCollectionID, 'NFT', [{key: 'key1', value: 'v'}]); + itSub('No editing rights', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL', + tokenPropertyPermissions: [{key: 'k', permission: {mutable: false, collectionAdmin: false, tokenOwner: false}}], }); + const mintTx = async () => collection.mintToken(alice, {Substrate: bob.address}, [{key: 'k', value: 'v'}]); + await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/); }); - it('User doesnt have editing rights', async () => { - await usingApi(async () => { - const newCollectionID = await createCollectionWithPropsExpectSuccess({propPerm: [{key: 'key1', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}}]}); - await createItemWithPropsExpectFailure(bob, newCollectionID, 'NFT', [{key: 'key1', value: 'v'}]); + itSub('User doesnt have editing rights', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL', + tokenPropertyPermissions: [{key: 'k', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}}], }); + const mintTx = async () => collection.mintToken(alice, {Substrate: bob.address}, [{key: 'k', value: 'v'}]); + await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/); }); - it('Adding property without access rights', async () => { - await usingApi(async () => { - const newCollectionID = await createCollectionWithPropsExpectSuccess(); - await addCollectionAdminExpectSuccess(alice, newCollectionID, bob.address); - - await createItemWithPropsExpectFailure(bob, newCollectionID, 'NFT', [{key: 'k', value: 'v'}]); - }); + itSub('Adding property without access rights', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const mintTx = async () => collection.mintToken(alice, {Substrate: bob.address}, [{key: 'k', value: 'v'}]); + await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/); }); - it('Adding more than 64 prps', async () => { - await usingApi(async () => { - const prps = []; + itSub('Adding more than 64 prps', async ({helper}) => { + const props: IProperty[] = []; - for (let i = 0; i < 65; i++) { - prps.push({key: `key${i}`, value: `value${i}`}); - } + for (let i = 0; i < 65; i++) { + props.push({key: `key${i}`, value: `value${i}`}); + } - const newCollectionID = await createCollectionWithPropsExpectSuccess(); - - await createItemWithPropsExpectFailure(alice, newCollectionID, 'NFT', prps); - }); - }); - it('Trying to add bigger property than allowed', async () => { - await usingApi(async () => { - const newCollectionID = await createCollectionWithPropsExpectSuccess(); - - await createItemWithPropsExpectFailure(alice, newCollectionID, 'NFT', [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]); - }); + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const mintTx = async () => collection.mintToken(alice, {Substrate: bob.address}, props); + await expect(mintTx()).to.be.rejectedWith('Verification Error'); }); - it('Check total pieces for invalid Fungible token', async () => { - await usingApi(async api => { - const createCollectionResult = await createCollection(api, alice, {mode: {type: 'Fungible', decimalPoints: 0}}); - const collectionId = createCollectionResult.collectionId; - const invalidTokenId = 1000_000; - - expect((await api.rpc.unique.totalPieces(collectionId, invalidTokenId)).isNone).to.be.true; - expect((await api.rpc.unique.tokenData(collectionId, invalidTokenId, [])).pieces.toBigInt()).to.be.eq(0n); + itSub('Trying to add bigger property than allowed', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL', + tokenPropertyPermissions: [ + {key: 'k1', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}, + {key: 'k2', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}, + ], }); + const mintTx = async () => collection.mintToken(alice, {Substrate: bob.address}, [ + {key: 'k1', value: 'vvvvvv'.repeat(5000)}, + {key: 'k2', value: 'vvv'.repeat(5000)}, + ]); + await expect(mintTx()).to.be.rejectedWith(/common\.NoSpaceForProperty/); }); - it('Check total pieces for invalid NFT token', async () => { - await usingApi(async api => { - const createCollectionResult = await createCollection(api, alice, {mode: {type: 'NFT'}}); - const collectionId = createCollectionResult.collectionId; - const invalidTokenId = 1000_000; - - expect((await api.rpc.unique.totalPieces(collectionId, invalidTokenId)).isNone).to.be.true; - expect((await api.rpc.unique.tokenData(collectionId, invalidTokenId, [])).pieces.toBigInt()).to.be.eq(0n); - }); + itSub('Check total pieces for invalid Fungible token', async ({helper}) => { + const collection = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + const invalidTokenId = 1_000_000; + expect((await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, invalidTokenId]))?.isNone).to.be.true; + expect((await helper.callRpc('api.rpc.unique.tokenData', [collection.collectionId, invalidTokenId]))?.pieces.toBigInt()).to.be.equal(0n); }); - it('Check total pieces for invalid Refungible token', async function() { - await requirePallets(this, [Pallets.ReFungible]); + itSub('Check total pieces for invalid NFT token', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const invalidTokenId = 1_000_000; + expect((await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, invalidTokenId]))?.isNone).to.be.true; + expect((await helper.callRpc('api.rpc.unique.tokenData', [collection.collectionId, invalidTokenId]))?.pieces.toBigInt()).to.be.equal(0n); + }); - await usingApi(async api => { - const createCollectionResult = await createCollection(api, alice, {mode: {type: 'ReFungible'}}); - const collectionId = createCollectionResult.collectionId; - const invalidTokenId = 1000_000; - - expect((await api.rpc.unique.totalPieces(collectionId, invalidTokenId)).isNone).to.be.true; - expect((await api.rpc.unique.tokenData(collectionId, invalidTokenId, [])).pieces.toBigInt()).to.be.eq(0n); - }); + itSub.ifWithPallets('Check total pieces for invalid Refungible token', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const invalidTokenId = 1_000_000; + expect((await helper.callRpc('api.rpc.unique.totalPieces', [collection.collectionId, invalidTokenId]))?.isNone).to.be.true; + expect((await helper.callRpc('api.rpc.unique.tokenData', [collection.collectionId, invalidTokenId]))?.pieces.toBigInt()).to.be.equal(0n); }); }); --- a/tests/src/createMultipleItems.test.ts +++ b/tests/src/createMultipleItems.test.ts @@ -14,292 +14,151 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import {ApiPromise} from '@polkadot/api'; import {IKeyringPair} from '@polkadot/types/types'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync, executeTransaction} from './substrate/substrate-api'; -import { - createCollectionExpectSuccess, - destroyCollectionExpectSuccess, - getGenericResult, - normalizeAccountId, - setCollectionLimitsExpectSuccess, - addCollectionAdminExpectSuccess, - getBalance, - getTokenOwner, - getLastTokenId, - getCreatedCollectionCount, - createCollectionWithPropsExpectSuccess, - createMultipleItemsWithPropsExpectSuccess, - getTokenProperties, - requirePallets, - Pallets, - checkPalletsPresence, -} from './util/helpers'; +import {usingPlaygrounds, expect, Pallets, itSub} from './util/playgrounds'; -chai.use(chaiAsPromised); -const expect = chai.expect; - describe('Integration Test createMultipleItems(collection_id, owner, items_data):', () => { - it('Create 0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess(); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); + let alice: IKeyringPair; - const alice = privateKeyWrapper('//Alice'); - await submitTransactionAsync( - alice, - api.tx.unique.setTokenPropertyPermissions(collectionId, [{key: 'data', permission: {tokenOwner: true}}]), - ); - - const args = [ - {NFT: {properties: [{key: 'data', value: '1'}]}}, - {NFT: {properties: [{key: 'data', value: '2'}]}}, - {NFT: {properties: [{key: 'data', value: '3'}]}}, - ]; - const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args); - await submitTransactionAsync(alice, createMultipleItemsTx); - const itemsListIndexAfter = await getLastTokenId(api, collectionId); - expect(itemsListIndexAfter).to.be.equal(3); - - expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(alice.address)); - expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address)); - expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address)); - - expect((await getTokenProperties(api, collectionId, 1, ['data']))[0].value).to.be.equal('1'); - expect((await getTokenProperties(api, collectionId, 2, ['data']))[0].value).to.be.equal('2'); - expect((await getTokenProperties(api, collectionId, 3, ['data']))[0].value).to.be.equal('3'); + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice] = await helper.arrange.createAccounts([100n], donor); }); }); - it('Create 0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - const alice = privateKeyWrapper('//Alice'); - const args = [ - {Fungible: {value: 1}}, - {Fungible: {value: 2}}, - {Fungible: {value: 3}}, - ]; - const createMultipleItemsTx = api.tx.unique - .createMultipleItems(collectionId, normalizeAccountId(alice.address), args); - await submitTransactionAsync(alice, createMultipleItemsTx); - const token1Data = await getBalance(api, collectionId, alice.address, 0); - - expect(token1Data).to.be.equal(6n); // 1 + 2 + 3 + itSub('Create 0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ + {key: 'data', permission: {tokenOwner: true, mutable: false, collectionAdmin: false}}, + ], }); + const args = [ + {properties: [{key: 'data', value: '1'}]}, + {properties: [{key: 'data', value: '2'}]}, + {properties: [{key: 'data', value: '3'}]}, + ]; + const tokens = await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); + for (const [i, token] of tokens.entries()) { + const tokenData = await token.getData(); + expect(tokenData?.normalizedOwner.Substrate).to.be.deep.equal(helper.address.normalizeSubstrate(alice.address)); + expect(tokenData?.properties[0].value).to.be.equal(args[i].properties[0].value); + } }); - - it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async function() { - await requirePallets(this, [Pallets.ReFungible]); - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - const alice = privateKeyWrapper('//Alice'); - const args = [ - {ReFungible: {pieces: 1}}, - {ReFungible: {pieces: 2}}, - {ReFungible: {pieces: 3}}, - ]; - const createMultipleItemsTx = api.tx.unique - .createMultipleItems(collectionId, normalizeAccountId(alice.address), args); - await submitTransactionAsync(alice, createMultipleItemsTx); - const itemsListIndexAfter = await getLastTokenId(api, collectionId); - expect(itemsListIndexAfter).to.be.equal(3); - - expect(await getBalance(api, collectionId, alice.address, 1)).to.be.equal(1n); - expect(await getBalance(api, collectionId, alice.address, 2)).to.be.equal(2n); - expect(await getBalance(api, collectionId, alice.address, 3)).to.be.equal(3n); + itSub('Create 0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async ({helper}) => { + const collection = await helper.ft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', }); + const args = [ + {value: 1n}, + {value: 2n}, + {value: 3n}, + ]; + await helper.ft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, args, {Substrate: alice.address}); + expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(6n); }); - - it('Can mint amount of items equals to collection limits', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const collectionId = await createCollectionExpectSuccess(); - await setCollectionLimitsExpectSuccess(alice, collectionId, { - tokenLimit: 2, - }); - const args = [ - {NFT: {}}, - {NFT: {}}, - ]; - const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args); - const events = await submitTransactionAsync(alice, createMultipleItemsTx); - const result = getGenericResult(events); - expect(result.success).to.be.true; + itSub.ifWithPallets('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', }); - }); + const args = [ + {pieces: 1n}, + {pieces: 2n}, + {pieces: 3n}, + ]; + const tokens = await helper.rft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); - it('Create 0x31, 0x32, 0x33 items in active NFT with property Admin', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionWithPropsExpectSuccess({propPerm: [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: false}}]}); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - const alice = privateKeyWrapper('//Alice'); - const args = [ - {NFT: {properties: [{key: 'k', value: 'v1'}]}}, - {NFT: {properties: [{key: 'k', value: 'v2'}]}}, - {NFT: {properties: [{key: 'k', value: 'v3'}]}}, - ]; - - await createMultipleItemsWithPropsExpectSuccess(alice, collectionId, args); - const itemsListIndexAfter = await getLastTokenId(api, collectionId); - expect(itemsListIndexAfter).to.be.equal(3); - - expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(alice.address)); - expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address)); - expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address)); - - expect((await getTokenProperties(api, collectionId, 1, ['k']))[0].value).to.be.equal('v1'); - expect((await getTokenProperties(api, collectionId, 2, ['k']))[0].value).to.be.equal('v2'); - expect((await getTokenProperties(api, collectionId, 3, ['k']))[0].value).to.be.equal('v3'); - }); + for (const [i, token] of tokens.entries()) { + expect(await token.getBalance({Substrate: alice.address})).to.be.equal(BigInt(i + 1)); + } }); - it('Create 0x31, 0x32, 0x33 items in active NFT with property AdminConst', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionWithPropsExpectSuccess({propPerm: [{key: 'k', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}}]}); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - const args = [ - {NFT: {properties: [{key: 'k', value: 'v1'}]}}, - {NFT: {properties: [{key: 'k', value: 'v2'}]}}, - {NFT: {properties: [{key: 'k', value: 'v3'}]}}, - ]; - - await createMultipleItemsWithPropsExpectSuccess(alice, collectionId, args); - const itemsListIndexAfter = await getLastTokenId(api, collectionId); - expect(itemsListIndexAfter).to.be.equal(3); - - expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(alice.address)); - expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address)); - expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address)); - - expect((await getTokenProperties(api, collectionId, 1, ['k']))[0].value).to.be.equal('v1'); - expect((await getTokenProperties(api, collectionId, 2, ['k']))[0].value).to.be.equal('v2'); - expect((await getTokenProperties(api, collectionId, 3, ['k']))[0].value).to.be.equal('v3'); + itSub('Can mint amount of items equals to collection limits', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + limits: { + tokenLimit: 2, + }, }); + const args = [{}, {}]; + await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); }); - it('Create 0x31, 0x32, 0x33 items in active NFT with property itemOwnerOrAdmin', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionWithPropsExpectSuccess({propPerm: [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]}); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - const alice = privateKeyWrapper('//Alice'); - const args = [ - {NFT: {properties: [{key: 'k', value: 'v1'}]}}, - {NFT: {properties: [{key: 'k', value: 'v2'}]}}, - {NFT: {properties: [{key: 'k', value: 'v3'}]}}, - ]; - - await createMultipleItemsWithPropsExpectSuccess(alice, collectionId, args); - const itemsListIndexAfter = await getLastTokenId(api, collectionId); - expect(itemsListIndexAfter).to.be.equal(3); - - expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(alice.address)); - expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(alice.address)); - expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(alice.address)); - - expect((await getTokenProperties(api, collectionId, 1, ['k']))[0].value).to.be.equal('v1'); - expect((await getTokenProperties(api, collectionId, 2, ['k']))[0].value).to.be.equal('v2'); - expect((await getTokenProperties(api, collectionId, 3, ['k']))[0].value).to.be.equal('v3'); + itSub('Create 0x31, 0x32, 0x33 items in active NFT with property Admin', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ + {key: 'data', permission: {tokenOwner: false, mutable: true, collectionAdmin: true}}, + ], }); + const args = [ + {properties: [{key: 'data', value: '1'}]}, + {properties: [{key: 'data', value: '2'}]}, + {properties: [{key: 'data', value: '3'}]}, + ]; + const tokens = await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); + for (const [i, token] of tokens.entries()) { + const tokenData = await token.getData(); + expect(tokenData?.normalizedOwner.Substrate).to.be.deep.equal(helper.address.normalizeSubstrate(alice.address)); + expect(tokenData?.properties[0].value).to.be.equal(args[i].properties[0].value); + } }); -}); -describe('Integration Test createMultipleItems(collection_id, owner, items_data) with collection admin permissions:', () => { - let alice: IKeyringPair; - let bob: IKeyringPair; - - before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); + itSub('Create 0x31, 0x32, 0x33 items in active NFT with property AdminConst', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ + {key: 'data', permission: {tokenOwner: false, mutable: false, collectionAdmin: true}}, + ], }); + const args = [ + {properties: [{key: 'data', value: '1'}]}, + {properties: [{key: 'data', value: '2'}]}, + {properties: [{key: 'data', value: '3'}]}, + ]; + const tokens = await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); + for (const [i, token] of tokens.entries()) { + const tokenData = await token.getData(); + expect(tokenData?.normalizedOwner.Substrate).to.be.deep.equal(helper.address.normalizeSubstrate(alice.address)); + expect(tokenData?.properties[0].value).to.be.equal(args[i].properties[0].value); + } }); - it('Create 0x31, 0x32, 0x33 items in active NFT collection and verify tokens data in chain', async () => { - await usingApi(async (api: ApiPromise) => { - const collectionId = await createCollectionWithPropsExpectSuccess({propPerm: [{key: 'data', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]}); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - const args = [ - {NFT: {properties: [{key: 'data', value: 'v1'}]}}, - {NFT: {properties: [{key: 'data', value: 'v2'}]}}, - {NFT: {properties: [{key: 'data', value: 'v3'}]}}, - ]; - const createMultipleItemsTx = api.tx.unique - .createMultipleItems(collectionId, normalizeAccountId(bob.address), args); - await submitTransactionAsync(bob, createMultipleItemsTx); - const itemsListIndexAfter = await getLastTokenId(api, collectionId); - expect(itemsListIndexAfter).to.be.equal(3); - - expect(await getTokenOwner(api, collectionId, 1)).to.be.deep.equal(normalizeAccountId(bob.address)); - expect(await getTokenOwner(api, collectionId, 2)).to.be.deep.equal(normalizeAccountId(bob.address)); - expect(await getTokenOwner(api, collectionId, 3)).to.be.deep.equal(normalizeAccountId(bob.address)); - - expect((await getTokenProperties(api, collectionId, 1, ['data']))[0].value).to.be.equal('v1'); - expect((await getTokenProperties(api, collectionId, 2, ['data']))[0].value).to.be.equal('v2'); - expect((await getTokenProperties(api, collectionId, 3, ['data']))[0].value).to.be.equal('v3'); + itSub('Create 0x31, 0x32, 0x33 items in active NFT with property itemOwnerOrAdmin', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ + {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}, + ], }); - }); - - it('Create 0x01, 0x02, 0x03 items in active Fungible collection and verify tokens data in chain', async () => { - await usingApi(async (api: ApiPromise) => { - const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - const args = [ - {Fungible: {value: 1}}, - {Fungible: {value: 2}}, - {Fungible: {value: 3}}, - ]; - const createMultipleItemsTx = api.tx.unique - .createMultipleItems(collectionId, normalizeAccountId(bob.address), args); - await submitTransactionAsync(bob, createMultipleItemsTx); - const token1Data = await getBalance(api, collectionId, bob.address, 0); - - expect(token1Data).to.be.equal(6n); // 1 + 2 + 3 - }); - }); - - it('Create 0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - await usingApi(async (api: ApiPromise) => { - const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - const args = [ - {ReFungible: {pieces: 1}}, - {ReFungible: {pieces: 2}}, - {ReFungible: {pieces: 3}}, - ]; - const createMultipleItemsTx = api.tx.unique - .createMultipleItems(collectionId, normalizeAccountId(bob.address), args); - await submitTransactionAsync(bob, createMultipleItemsTx); - const itemsListIndexAfter = await getLastTokenId(api, collectionId); - expect(itemsListIndexAfter).to.be.equal(3); - - expect(await getBalance(api, collectionId, bob.address, 1)).to.be.equal(1n); - expect(await getBalance(api, collectionId, bob.address, 2)).to.be.equal(2n); - expect(await getBalance(api, collectionId, bob.address, 3)).to.be.equal(3n); - }); + const args = [ + {properties: [{key: 'data', value: '1'}]}, + {properties: [{key: 'data', value: '2'}]}, + {properties: [{key: 'data', value: '3'}]}, + ]; + const tokens = await helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); + for (const [i, token] of tokens.entries()) { + const tokenData = await token.getData(); + expect(tokenData?.normalizedOwner.Substrate).to.be.equal(helper.address.normalizeSubstrate(alice.address)); + expect(tokenData?.properties[0].value).to.be.equal(args[i].properties[0].value); + } }); }); @@ -308,238 +167,208 @@ let bob: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor); }); }); - it('Regular user cannot create items in active NFT collection', async () => { - await usingApi(async (api: ApiPromise) => { - const collectionId = await createCollectionExpectSuccess(); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - const args = [{NFT: {}}, - {NFT: {}}, - {NFT: {}}]; - const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args); - await expect(executeTransaction(api, bob, createMultipleItemsTx)).to.be.rejectedWith(/common\.PublicMintingNotAllowed/); + itSub('Regular user cannot create items in active NFT collection', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', }); + const args = [ + {}, + {}, + ]; + const mintTx = async () => helper.nft.mintMultipleTokensWithOneOwner(bob, collection.collectionId, {Substrate: alice.address}, args); + await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/); }); - it('Regular user cannot create items in active Fungible collection', async () => { - await usingApi(async (api: ApiPromise) => { - const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - const args = [ - {Fungible: {value: 1}}, - {Fungible: {value: 2}}, - {Fungible: {value: 3}}, - ]; - const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args); - await expect(executeTransaction(api, bob, createMultipleItemsTx)).to.be.rejectedWith(/common\.PublicMintingNotAllowed/); + itSub('Regular user cannot create items in active Fungible collection', async ({helper}) => { + const collection = await helper.ft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', }); + const args = [ + {value: 1n}, + {value: 2n}, + {value: 3n}, + ]; + const mintTx = async () => helper.ft.mintMultipleTokensWithOneOwner(bob, collection.collectionId, args, {Substrate: alice.address}); + await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/); }); - - it('Regular user cannot create items in active ReFungible collection', async function() { - await requirePallets(this, [Pallets.ReFungible]); - await usingApi(async (api: ApiPromise) => { - const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - const args = [ - {ReFungible: {pieces: 1}}, - {ReFungible: {pieces: 1}}, - {ReFungible: {pieces: 1}}, - ]; - const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args); - await expect(executeTransaction(api, bob, createMultipleItemsTx)).to.be.rejectedWith(/common\.PublicMintingNotAllowed/); + itSub.ifWithPallets('Regular user cannot create items in active ReFungible collection', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', }); + const args = [ + {pieces: 1n}, + {pieces: 1n}, + {pieces: 1n}, + ]; + const mintTx = async () => helper.rft.mintMultipleTokensWithOneOwner(bob, collection.collectionId, {Substrate: alice.address}, args); + await expect(mintTx()).to.be.rejectedWith(/common\.PublicMintingNotAllowed/); }); - it('Create token in not existing collection', async () => { - await usingApi(async (api: ApiPromise) => { - const collectionId = await getCreatedCollectionCount(api) + 1; - const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), ['NFT', 'NFT', 'NFT']); - await expect(executeTransaction(api, alice, createMultipleItemsTx)).to.be.rejectedWith(/common\.CollectionNotFound/); - }); + itSub('Create token in not existing collection', async ({helper}) => { + const collectionId = 1_000_000; + const args = [ + {}, + {}, + ]; + const mintTx = async () => helper.nft.mintMultipleTokensWithOneOwner(bob, collectionId, {Substrate: alice.address}, args); + await expect(mintTx()).to.be.rejectedWith(/common\.CollectionNotFound/); }); - it('Create NFTs that has reached the maximum data limit', async function() { - await usingApi(async (api, privateKeyWrapper) => { - const collectionId = await createCollectionWithPropsExpectSuccess({ - propPerm: [{key: 'key', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}], - }); - const alice = privateKeyWrapper('//Alice'); - const args = [ - {NFT: {properties: [{key: 'key', value: 'A'.repeat(32769)}]}}, - {NFT: {properties: [{key: 'key', value: 'B'.repeat(32769)}]}}, - {NFT: {properties: [{key: 'key', value: 'C'.repeat(32769)}]}}, - ]; - const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args); - await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected; + itSub('Create NFTs that has reached the maximum data limit', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ + {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}, + ], }); + const args = [ + {properties: [{key: 'data', value: 'A'.repeat(32769)}]}, + {properties: [{key: 'data', value: 'B'.repeat(32769)}]}, + {properties: [{key: 'data', value: 'C'.repeat(32769)}]}, + ]; + const mintTx = async () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); + await expect(mintTx()).to.be.rejectedWith('Verification Error'); }); - it('Create Refungible tokens that has reached the maximum data limit', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - await usingApi(async api => { - const collectionIdReFungible = - await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - { - const argsReFungible = [ - {ReFungible: [10, [['key', 'A'.repeat(32769)]]]}, - {ReFungible: [10, [['key', 'B'.repeat(32769)]]]}, - {ReFungible: [10, [['key', 'C'.repeat(32769)]]]}, - ]; - const createMultipleItemsTxFungible = api.tx.unique - .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible); - await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected; - } - { - const argsReFungible = [ - {ReFungible: {properties: [{key: 'key', value: 'A'.repeat(32769)}]}}, - {ReFungible: {properties: [{key: 'key', value: 'B'.repeat(32769)}]}}, - {ReFungible: {properties: [{key: 'key', value: 'C'.repeat(32769)}]}}, - ]; - const createMultipleItemsTxFungible = api.tx.unique - .createMultipleItems(collectionIdReFungible, normalizeAccountId(alice.address), argsReFungible); - await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTxFungible)).to.be.rejected; - } + itSub.ifWithPallets('Create Refungible tokens that has reached the maximum data limit', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ + {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}, + ], }); + const args = [ + {pieces: 10n, properties: [{key: 'data', value: 'A'.repeat(32769)}]}, + {pieces: 10n, properties: [{key: 'data', value: 'B'.repeat(32769)}]}, + {pieces: 10n, properties: [{key: 'data', value: 'C'.repeat(32769)}]}, + ]; + const mintTx = async () => helper.rft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); + await expect(mintTx()).to.be.rejectedWith('Verification Error'); }); - - it('Create tokens with different types', async () => { - await usingApi(async (api: ApiPromise) => { - const collectionId = await createCollectionExpectSuccess(); - const types = ['NFT', 'Fungible']; - - if (await checkPalletsPresence([Pallets.ReFungible])) { - types.push('ReFungible'); - } - - const createMultipleItemsTx = api.tx.unique - .createMultipleItems(collectionId, normalizeAccountId(alice.address), types); - await expect(executeTransaction(api, alice, createMultipleItemsTx)).to.be.rejectedWith(/nonfungible\.NotNonfungibleDataUsedToMintFungibleCollectionToken/); - // garbage collection :-D // lol - await destroyCollectionExpectSuccess(collectionId); + itSub.ifWithPallets('Create tokens with different types', [Pallets.ReFungible], async ({helper}) => { + const {collectionId} = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', }); + + const types = ['NFT', 'Fungible', 'ReFungible']; + await expect(helper.executeExtrinsic( + alice, + 'api.tx.unique.createMultipleItems', + [collectionId, {Substrate: alice.address}, types], + )).to.be.rejectedWith(/nonfungible\.NotNonfungibleDataUsedToMintFungibleCollectionToken/); }); - it('Create tokens with different data limits <> maximum data limit', async () => { - await usingApi(async (api: ApiPromise) => { - const collectionId = await createCollectionWithPropsExpectSuccess({ - propPerm: [{key: 'key', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}], - }); - const args = [ - {NFT: {properties: [{key: 'key', value: 'A'}]}}, - {NFT: {properties: [{key: 'key', value: 'B'.repeat(32769)}]}}, - ]; - const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args); - await expect(submitTransactionExpectFailAsync(alice, createMultipleItemsTx)).to.be.rejected; + itSub('Create tokens with different data limits <> maximum data limit', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ + {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}, + ], }); + const args = [ + {properties: [{key: 'data', value: 'A'}]}, + {properties: [{key: 'data', value: 'B'.repeat(32769)}]}, + ]; + const mintTx = async () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); + await expect(mintTx()).to.be.rejectedWith('Verification Error'); }); - it('Fails when minting tokens exceeds collectionLimits amount', async () => { - await usingApi(async (api) => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionLimitsExpectSuccess(alice, collectionId, { + itSub('Fails when minting tokens exceeds collectionLimits amount', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ + {key: 'data', permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}, + ], + limits: { tokenLimit: 1, - }); - const args = [ - {NFT: {}}, - {NFT: {}}, - ]; - const createMultipleItemsTx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args); - await expect(executeTransaction(api, alice, createMultipleItemsTx)).to.be.rejectedWith(/common\.CollectionTokenLimitExceeded/); + }, }); + const args = [ + {}, + {}, + ]; + const mintTx = async () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); + await expect(mintTx()).to.be.rejectedWith(/common\.CollectionTokenLimitExceeded/); }); - it('User doesnt have editing rights', async () => { - await usingApi(async (api: ApiPromise) => { - const collectionId = await createCollectionWithPropsExpectSuccess({ - propPerm: [{key: 'key1', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}}], - }); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - const args = [ - {NFT: {properties: [{key: 'key1', value: 'v2'}]}}, - {NFT: {}}, - {NFT: {}}, - ]; - - const tx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(bob.address), args); - await expect(executeTransaction(api, bob, tx)).to.be.rejectedWith(/common\.NoPermission/); + itSub('User doesnt have editing rights', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ + {key: 'data', permission: {tokenOwner: false, mutable: true, collectionAdmin: false}}, + ], }); + const args = [ + {properties: [{key: 'data', value: 'A'}]}, + ]; + const mintTx = async () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); + await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/); }); - - it('Adding property without access rights', async () => { - await usingApi(async (api: ApiPromise) => { - const collectionId = await createCollectionWithPropsExpectSuccess({properties: [{key: 'k', value: 'v1'}]}); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - expect(itemsListIndexBefore).to.be.equal(0); - const args = [{NFT: {properties: [{key: 'k', value: 'v'}]}}, - {NFT: {}}, - {NFT: {}}]; - const tx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(bob.address), args); - await expect(executeTransaction(api, bob, tx)).to.be.rejectedWith(/common\.NoPermission/); + itSub('Adding property without access rights', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + properties: [ + { + key: 'data', + value: 'v', + }, + ], }); + const args = [ + {properties: [{key: 'data', value: 'A'}]}, + ]; + const mintTx = async () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); + await expect(mintTx()).to.be.rejectedWith(/common\.NoPermission/); }); - it('Adding more than 64 prps', async () => { - await usingApi(async (api: ApiPromise) => { - const propPerms = [{key: 'key', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]; - for (let i = 0; i < 65; i++) { - propPerms.push({key: `key${i}`, permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}); - } - - const collectionId = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); - - const tx1 = api.tx.unique.setTokenPropertyPermissions(collectionId, propPerms); - await expect(executeTransaction(api, alice, tx1)).to.be.rejectedWith(/common\.PropertyLimitReached/); - - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - - const prps = []; - - for (let i = 0; i < 65; i++) { - prps.push({key: `key${i}`, value: `value${i}`}); - } - - const args = [ - {NFT: {properties: prps}}, - {NFT: {properties: prps}}, - {NFT: {properties: prps}}, - ]; - - // there are no permissions, but will fail anyway because of too much weight for a block - const tx2 = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args); - await expect(submitTransactionExpectFailAsync(alice, tx2)).to.be.rejected; + itSub('Adding more than 64 prps', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', }); - }); + const prps = []; - it('Trying to add bigger property than allowed', async () => { - await usingApi(async (api: ApiPromise) => { - const collectionId = await createCollectionWithPropsExpectSuccess({ - propPerm: [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}], - }); - const itemsListIndexBefore = await getLastTokenId(api, collectionId); - expect(itemsListIndexBefore).to.be.equal(0); - const args = [{NFT: {properties: [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]}}, - {NFT: {properties: [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]}}, - {NFT: {properties: [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}]}}]; + for (let i = 0; i < 65; i++) { + prps.push({key: `key${i}`, value: `value${i}`}); + } + + const args = [ + {properties: prps}, + {properties: prps}, + {properties: prps}, + ]; - const tx = api.tx.unique.createMultipleItems(collectionId, normalizeAccountId(alice.address), args); - await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/common\.NoPermission/); - }); + const mintTx = async () => helper.nft.mintMultipleTokensWithOneOwner(alice, collection.collectionId, {Substrate: alice.address}, args); + await expect(mintTx()).to.be.rejectedWith('Verification Error'); }); }); --- a/tests/src/createMultipleItemsEx.test.ts +++ b/tests/src/createMultipleItemsEx.test.ts @@ -14,382 +14,433 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import {expect} from 'chai'; -import usingApi, {executeTransaction} from './substrate/substrate-api'; -import {addCollectionAdminExpectSuccess, createCollectionExpectSuccess, createCollectionWithPropsExpectSuccess, getBalance, getLastTokenId, getTokenProperties, requirePallets, Pallets} from './util/helpers'; +import {IKeyringPair} from '@polkadot/types/types'; +import {usingPlaygrounds, expect, Pallets, itSub} from './util/playgrounds'; +import {IProperty} from './util/playgrounds/types'; describe('Integration Test: createMultipleItemsEx', () => { - it('can initialize multiple NFT with different owners', async () => { - const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//Charlie'); - const data = [ - { - owner: {substrate: alice.address}, - }, { - owner: {substrate: bob.address}, - }, { - owner: {substrate: charlie.address}, - }, - ]; + let alice: IKeyringPair; + let bob: IKeyringPair; + let charlie: IKeyringPair; + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); + }); + }); - await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, { - NFT: data, - })); - const tokens = await api.query.nonfungible.tokenData.entries(collection); - const json = tokens.map(([, token]) => token.toJSON()); - expect(json).to.be.deep.equal(data); + itSub('can initialize multiple NFT with different owners', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', }); + const args = [ + { + owner: {Substrate: alice.address}, + }, + { + owner: {Substrate: bob.address}, + }, + { + owner: {Substrate: charlie.address}, + }, + ]; + + const tokens = await collection.mintMultipleTokens(alice, args); + for (const [i, token] of tokens.entries()) { + expect(await token.getOwner()).to.be.deep.equal(args[i].owner); + } }); - it('createMultipleItemsEx with property Admin', async () => { - const collection = await createCollectionWithPropsExpectSuccess({mode: {type: 'NFT'}, propPerm: [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: false}}]}); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//Charlie'); - const data = [ + itSub('createMultipleItemsEx with property Admin', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ { - owner: {substrate: alice.address}, - properties: [{key: 'k', value: 'v1'}], - }, { - owner: {substrate: bob.address}, - properties: [{key: 'k', value: 'v2'}], - }, { - owner: {substrate: charlie.address}, - properties: [{key: 'k', value: 'v3'}], + key: 'k', + permission: { + mutable: true, + collectionAdmin: true, + tokenOwner: false, + }, }, - ]; + ], + }); - await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, { - NFT: data, - })); - for (let i = 1; i < 4; i++) { - expect(await api.rpc.unique.tokenProperties(collection, i)).not.to.be.empty; - } - }); + const args = [ + { + owner: {Substrate: alice.address}, + properties: [{key: 'k', value: 'v1'}], + }, + { + owner: {Substrate: bob.address}, + properties: [{key: 'k', value: 'v2'}], + }, + { + owner: {Substrate: charlie.address}, + properties: [{key: 'k', value: 'v3'}], + }, + ]; + + const tokens = await collection.mintMultipleTokens(alice, args); + for (const [i, token] of tokens.entries()) { + expect(await token.getOwner()).to.be.deep.equal(args[i].owner); + expect(await token.getData()).to.not.be.empty; + } }); - it('createMultipleItemsEx with property AdminConst', async () => { - const collection = await createCollectionWithPropsExpectSuccess({mode: {type: 'NFT'}, propPerm: [{key: 'k', permission: {mutable: false, collectionAdmin: true, tokenOwner: false}}]}); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//Charlie'); - const data = [ + itSub('createMultipleItemsEx with property AdminConst', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ { - owner: {substrate: alice.address}, - properties: [{key: 'k', value: 'v1'}], - }, { - owner: {substrate: bob.address}, - properties: [{key: 'k', value: 'v2'}], - }, { - owner: {substrate: charlie.address}, - properties: [{key: 'k', value: 'v3'}], + key: 'k', + permission: { + mutable: false, + collectionAdmin: true, + tokenOwner: false, + }, }, - ]; + ], + }); - await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, { - NFT: data, - })); - for (let i = 1; i < 4; i++) { - expect(await api.rpc.unique.tokenProperties(collection, i)).not.to.be.empty; - } - }); + const args = [ + { + owner: {Substrate: alice.address}, + properties: [{key: 'k', value: 'v1'}], + }, + { + owner: {Substrate: bob.address}, + properties: [{key: 'k', value: 'v2'}], + }, + { + owner: {Substrate: charlie.address}, + properties: [{key: 'k', value: 'v3'}], + }, + ]; + + const tokens = await collection.mintMultipleTokens(alice, args); + for (const [i, token] of tokens.entries()) { + expect(await token.getOwner()).to.be.deep.equal(args[i].owner); + expect(await token.getData()).to.not.be.empty; + } }); - it('createMultipleItemsEx with property itemOwnerOrAdmin', async () => { - const collection = await createCollectionWithPropsExpectSuccess({mode: {type: 'NFT'}, propPerm: [{key: 'k', permission: {mutable: false, collectionAdmin: true, tokenOwner: true}}]}); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//Charlie'); - const data = [ + itSub('createMultipleItemsEx with property itemOwnerOrAdmin', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ { - owner: {substrate: alice.address}, - properties: [{key: 'k', value: 'v1'}], - }, { - owner: {substrate: bob.address}, - properties: [{key: 'k', value: 'v2'}], - }, { - owner: {substrate: charlie.address}, - properties: [{key: 'k', value: 'v3'}], + key: 'k', + permission: { + mutable: false, + collectionAdmin: true, + tokenOwner: true, + }, }, - ]; + ], + }); + + const args = [ + { + owner: {Substrate: alice.address}, + properties: [{key: 'k', value: 'v1'}], + }, + { + owner: {Substrate: bob.address}, + properties: [{key: 'k', value: 'v2'}], + }, + { + owner: {Substrate: charlie.address}, + properties: [{key: 'k', value: 'v3'}], + }, + ]; - await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, { - NFT: data, - })); - for (let i = 1; i < 4; i++) { - expect(await api.rpc.unique.tokenProperties(collection, i)).not.to.be.empty; - } - }); + const tokens = await collection.mintMultipleTokens(alice, args); + for (const [i, token] of tokens.entries()) { + expect(await token.getOwner()).to.be.deep.equal(args[i].owner); + expect(await token.getData()).to.not.be.empty; + } }); - it('can initialize fungible with multiple owners', async () => { - const collection = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); + itSub('can initialize fungible with multiple owners', async ({helper}) => { + const collection = await helper.ft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + }, 0); - await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, { - Fungible: new Map([ - [JSON.stringify({Substrate: alice.address}), 50], - [JSON.stringify({Substrate: bob.address}), 100], - ]), - })); + const api = helper.api; + await helper.signTransaction(alice, api?.tx.unique.createMultipleItemsEx(collection.collectionId, { + Fungible: new Map([ + [JSON.stringify({Substrate: alice.address}), 50], + [JSON.stringify({Substrate: bob.address}), 100], + ]), + })); - expect(await getBalance(api, collection, alice.address, 0)).to.equal(50n); - expect(await getBalance(api, collection, bob.address, 0)).to.equal(100n); + expect(await collection.getBalance({Substrate: alice.address})).to.be.equal(50n); + expect(await collection.getBalance({Substrate: bob.address})).to.be.equal(100n); + }); + + itSub.ifWithPallets('can initialize an RFT with multiple owners', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ + {key: 'k', permission: {tokenOwner: true, mutable: false, collectionAdmin: false}}, + ], }); + + const api = helper.api; + await helper.signTransaction(alice, api?.tx.unique.createMultipleItemsEx(collection.collectionId, { + RefungibleMultipleOwners: { + users: new Map([ + [JSON.stringify({Substrate: alice.address}), 1], + [JSON.stringify({Substrate: bob.address}), 2], + ]), + properties: [ + {key: 'k', value: 'v'}, + ], + }, + })); + const tokenId = await collection.getLastTokenId(); + expect(tokenId).to.be.equal(1); + expect(await collection.getTokenBalance(1, {Substrate: alice.address})).to.be.equal(1n); + expect(await collection.getTokenBalance(1, {Substrate: bob.address})).to.be.equal(2n); }); - it('can initialize an RFT with multiple owners', async function() { - await requirePallets(this, [Pallets.ReFungible]); + itSub.ifWithPallets('can initialize multiple RFTs with the same owner', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ + {key: 'k', permission: {tokenOwner: true, mutable: false, collectionAdmin: false}}, + ], + }); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - await executeTransaction( - api, - alice, - api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'data', permission: {tokenOwner: true}}]), - ); + const api = helper.api; - await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, { - RefungibleMultipleOwners: { - users: new Map([ - [JSON.stringify({Substrate: alice.address}), 1], - [JSON.stringify({Substrate: bob.address}), 2], - ]), + await helper.signTransaction(alice, api?.tx.unique.createMultipleItemsEx(collection.collectionId, { + RefungibleMultipleItems: [ + { + user: {Substrate: alice.address}, pieces: 1, properties: [ - {key: 'data', value: 'testValue'}, + {key: 'k', value: 'v1'}, ], }, - })); - - const itemsListIndexAfter = await getLastTokenId(api, collection); - expect(itemsListIndexAfter).to.be.equal(1); - - expect(await getBalance(api, collection, alice.address, 1)).to.be.equal(1n); - expect(await getBalance(api, collection, bob.address, 1)).to.be.equal(2n); - expect((await getTokenProperties(api, collection, 1, ['data']))[0].value).to.be.equal('testValue'); - }); - }); - - it('can initialize multiple RFTs with the same owner', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const collection = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - await executeTransaction( - api, - alice, - api.tx.unique.setTokenPropertyPermissions(collection, [{key: 'data', permission: {tokenOwner: true}}]), - ); + { + user: {Substrate: alice.address}, pieces: 3, + properties: [ + {key: 'k', value: 'v2'}, + ], + }, + ], + })); - await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, { - RefungibleMultipleItems: [ - { - user: {Substrate: alice.address}, pieces: 1, - properties: [ - {key: 'data', value: 'testValue1'}, - ], - }, - { - user: {Substrate: alice.address}, pieces: 3, - properties: [ - {key: 'data', value: 'testValue2'}, - ], - }, - ], - })); + expect(await collection.getLastTokenId()).to.be.equal(2); + expect(await collection.getTokenBalance(1, {Substrate: alice.address})).to.be.equal(1n); + expect(await collection.getTokenBalance(2, {Substrate: alice.address})).to.be.equal(3n); - const itemsListIndexAfter = await getLastTokenId(api, collection); - expect(itemsListIndexAfter).to.be.equal(2); + const tokenData1 = await helper.rft.getToken(collection.collectionId, 1); + expect(tokenData1).to.not.be.null; + expect(tokenData1?.properties[0]).to.be.deep.equal({key: 'k', value: 'v1'}); - expect(await getBalance(api, collection, alice.address, 1)).to.be.equal(1n); - expect(await getBalance(api, collection, alice.address, 2)).to.be.equal(3n); - expect((await getTokenProperties(api, collection, 1, ['data']))[0].value).to.be.equal('testValue1'); - expect((await getTokenProperties(api, collection, 2, ['data']))[0].value).to.be.equal('testValue2'); - }); + const tokenData2 = await helper.rft.getToken(collection.collectionId, 2); + expect(tokenData2).to.not.be.null; + expect(tokenData2?.properties[0]).to.be.deep.equal({key: 'k', value: 'v2'}); }); }); describe('Negative test: createMultipleItemsEx', () => { - it('No editing rights', async () => { - const collection = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}], - propPerm: [{key: 'key1', permission: {mutable: true, collectionAdmin: false, tokenOwner: false}}]}); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//Charlie'); - await addCollectionAdminExpectSuccess(alice, collection, bob.address); - const data = [ - { - owner: {substrate: alice.address}, - properties: [{key: 'key1', value: 'v2'}], - }, { - owner: {substrate: bob.address}, - properties: [{key: 'key1', value: 'v2'}], - }, { - owner: {substrate: charlie.address}, - properties: [{key: 'key1', value: 'v2'}], - }, - ]; + let alice: IKeyringPair; + let bob: IKeyringPair; + let charlie: IKeyringPair; - const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data}); - // await executeTransaction(api, alice, tx); - - //await submitTransactionExpectFailAsync(alice, tx); - await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/common\.NoPermission/); + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); }); - it('User doesnt have editing rights', async () => { - const collection = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}], - propPerm: [{key: 'key1', permission: {mutable: false, collectionAdmin: false, tokenOwner: false}}]}); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - await addCollectionAdminExpectSuccess(alice, collection, bob.address); - const data = [ + itSub('No editing rights', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ { - owner: {substrate: alice.address}, - properties: [{key: 'key1', value: 'v2'}], - }, { - owner: {substrate: alice.address}, - properties: [{key: 'key1', value: 'v2'}], - }, { - owner: {substrate: alice.address}, - properties: [{key: 'key1', value: 'v2'}], + key: 'k', + permission: { + mutable: true, + collectionAdmin: false, + tokenOwner: false, + }, }, - ]; + ], + }); - const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data}); - // await executeTransaction(api, alice, tx); + const args = [ + { + owner: {Substrate: alice.address}, + properties: [{key: 'k', value: 'v1'}], + }, + { + owner: {Substrate: bob.address}, + properties: [{key: 'k', value: 'v2'}], + }, + { + owner: {Substrate: charlie.address}, + properties: [{key: 'k', value: 'v3'}], + }, + ]; - //await submitTransactionExpectFailAsync(alice, tx); - await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/common\.NoPermission/); - }); + await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith(/common\.NoPermission/); }); - it('Adding property without access rights', async () => { - const collection = await createCollectionWithPropsExpectSuccess({properties: [{key: 'key1', value: 'v'}]}); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//Charlie'); - await addCollectionAdminExpectSuccess(alice, collection, bob.address); - const data = [ + itSub('User doesnt have editing rights', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ { - owner: {substrate: alice.address}, - properties: [{key: 'key1', value: 'v2'}], - }, { - owner: {substrate: bob.address}, - properties: [{key: 'key1', value: 'v2'}], - }, { - owner: {substrate: charlie.address}, - properties: [{key: 'key1', value: 'v2'}], + key: 'k', + permission: { + mutable: false, + collectionAdmin: false, + tokenOwner: false, + }, }, - ]; + ], + }); - const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data}); + const args = [ + { + owner: {Substrate: alice.address}, + properties: [{key: 'k', value: 'v1'}], + }, + { + owner: {Substrate: bob.address}, + properties: [{key: 'k', value: 'v2'}], + }, + { + owner: {Substrate: charlie.address}, + properties: [{key: 'k', value: 'v3'}], + }, + ]; - await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/common\.NoPermission/); - //await submitTransactionExpectFailAsync(alice, tx); - }); + await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith(/common\.NoPermission/); }); - it('Adding more than 64 properties', async () => { - const propPerms = [{key: 'key', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]; + itSub('Adding property without access rights', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + }); - for (let i = 0; i < 65; i++) { - propPerms.push({key: `key${i}`, permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}); - } + const args = [ + { + owner: {Substrate: alice.address}, + properties: [{key: 'k', value: 'v1'}], + }, + { + owner: {Substrate: bob.address}, + properties: [{key: 'k', value: 'v2'}], + }, + { + owner: {Substrate: charlie.address}, + properties: [{key: 'k', value: 'v3'}], + }, + ]; - const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - await expect(executeTransaction(api, alice, api.tx.unique.setTokenPropertyPermissions(collection, propPerms))).to.be.rejectedWith(/common\.PropertyLimitReached/); - }); + await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith(/common\.NoPermission/); }); - it('Trying to add bigger property than allowed', async () => { - const collection = await createCollectionWithPropsExpectSuccess({propPerm: [{key: 'k', permission: {mutable: true, collectionAdmin: true, tokenOwner: true}}]}); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//Charlie'); - await addCollectionAdminExpectSuccess(alice, collection, bob.address); - const data = [ + itSub('Adding more than 64 properties', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ { - owner: {substrate: alice.address}, properties: [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}], - }, { - owner: {substrate: bob.address}, properties: [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}], - }, { - owner: {substrate: charlie.address}, properties: [{key: 'k', value: 'vvvvvv'.repeat(5000)}, {key: 'k2', value: 'vvv'.repeat(5000)}], + key: 'k', + permission: { + mutable: true, + collectionAdmin: true, + tokenOwner: true, + }, }, - ]; + ], + }); + + const properties: IProperty[] = []; + + for (let i = 0; i < 65; i++) { + properties.push({key: `k${i}`, value: `v${i}`}); + } - const tx = api.tx.unique.createMultipleItemsEx(collection, {NFT: data}); + const args = [ + { + owner: {Substrate: alice.address}, + properties: properties, + }, + { + owner: {Substrate: bob.address}, + properties: properties, + }, + { + owner: {Substrate: charlie.address}, + properties: properties, + }, + ]; - //await submitTransactionExpectFailAsync(alice, tx); - await expect(executeTransaction(api, alice, tx)).to.be.rejectedWith(/common\.NoPermission/); - }); + await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith('Verification Error'); }); - it('can initialize multiple NFT with different owners', async () => { - const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//Charlie'); - const data = [ + itSub('Trying to add bigger property than allowed', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'name', + description: 'descr', + tokenPrefix: 'COL', + tokenPropertyPermissions: [ { - owner: {substrate: alice.address}, - }, { - owner: {substrate: bob.address}, - }, { - owner: {substrate: charlie.address}, + key: 'k', + permission: { + mutable: true, + collectionAdmin: true, + tokenOwner: true, + }, }, - ]; - - await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, { - NFT: data, - })); - const tokens = await api.query.nonfungible.tokenData.entries(collection); - const json = tokens.map(([, token]) => token.toJSON()); - expect(json).to.be.deep.equal(data); + ], }); - }); - it('can initialize multiple NFT with different owners', async () => { - const collection = await createCollectionExpectSuccess({mode: {type: 'NFT'}}); - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - const charlie = privateKeyWrapper('//Charlie'); - const data = [ - { - owner: {substrate: alice.address}, - }, { - owner: {substrate: bob.address}, - }, { - owner: {substrate: charlie.address}, - }, - ]; + const args = [ + { + owner: {Substrate: alice.address}, + properties: [{key: 'k', value: 'A'.repeat(32769)}], + }, + { + owner: {Substrate: bob.address}, + properties: [{key: 'k', value: 'A'.repeat(32769)}], + }, + { + owner: {Substrate: charlie.address}, + properties: [{key: 'k', value: 'A'.repeat(32769)}], + }, + ]; - await executeTransaction(api, alice, api.tx.unique.createMultipleItemsEx(collection, { - NFT: data, - })); - const tokens = await api.query.nonfungible.tokenData.entries(collection); - const json = tokens.map(([, token]) => token.toJSON()); - expect(json).to.be.deep.equal(data); - }); + await expect(collection.mintMultipleTokens(alice, args)).to.be.rejectedWith('Verification Error'); }); }); --- a/tests/src/creditFeesToTreasury.test.ts +++ b/tests/src/creditFeesToTreasury.test.ts @@ -15,32 +15,15 @@ // along with Unique Network. If not, see . import './interfaces/augment-api-consts'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api'; import {IKeyringPair} from '@polkadot/types/types'; -import { - createCollectionExpectSuccess, - createItemExpectSuccess, - getGenericResult, - transferExpectSuccess, - UNIQUE, -} from './util/helpers'; - -import {default as waitNewBlocks} from './substrate/wait-new-blocks'; import {ApiPromise} from '@polkadot/api'; - -chai.use(chaiAsPromised); -const expect = chai.expect; +import {usingPlaygrounds, expect, itSub} from './util/playgrounds'; const TREASURY = '5EYCAe5ijiYfyeZ2JJCGq56LmPyNRAKzpG4QkoQkkQNB5e6Z'; const saneMinimumFee = 0.05; const saneMaximumFee = 0.5; const createCollectionDeposit = 100; -let alice: IKeyringPair; -let bob: IKeyringPair; - // Skip the inflation block pauses if the block is close to inflation block // until the inflation happens /*eslint no-async-promise-executor: "off"*/ @@ -62,129 +45,121 @@ } describe('integration test: Fees must be credited to Treasury:', () => { + let alice: IKeyringPair; + let bob: IKeyringPair; + before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor); }); }); - it('Total issuance does not change', async () => { - await usingApi(async (api) => { - await skipInflationBlock(api); - await waitNewBlocks(api, 1); + itSub('Total issuance does not change', async ({helper}) => { + const api = helper.api!; + await skipInflationBlock(api); + await helper.wait.newBlocks(1); - const totalBefore = (await api.query.balances.totalIssuance()).toBigInt(); + const totalBefore = (await api.query.balances.totalIssuance()).toBigInt(); - const amount = 1n; - const transfer = api.tx.balances.transfer(bob.address, amount); + await helper.balance.transferToSubstrate(alice, bob.address, 1n); - const result = getGenericResult(await submitTransactionAsync(alice, transfer)); + const totalAfter = (await api.query.balances.totalIssuance()).toBigInt(); - const totalAfter = (await api.query.balances.totalIssuance()).toBigInt(); + expect(totalAfter).to.be.equal(totalBefore); + }); - expect(result.success).to.be.true; - expect(totalAfter).to.be.equal(totalBefore); - }); - }); + itSub('Sender balance decreased by fee+sent amount, Treasury balance increased by fee', async ({helper}) => { + await skipInflationBlock(helper.api!); + await helper.wait.newBlocks(1); - it('Sender balance decreased by fee+sent amount, Treasury balance increased by fee', async () => { - await usingApi(async (api) => { - await skipInflationBlock(api); - await waitNewBlocks(api, 1); + const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY); + const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address); - const treasuryBalanceBefore: bigint = (await api.query.system.account(TREASURY)).data.free.toBigInt(); - const aliceBalanceBefore: bigint = (await api.query.system.account(alice.address)).data.free.toBigInt(); + const amount = 1n; + await helper.balance.transferToSubstrate(alice, bob.address, amount); - const amount = 1n; - const transfer = api.tx.balances.transfer(bob.address, amount); - const result = getGenericResult(await submitTransactionAsync(alice, transfer)); + const treasuryBalanceAfter = await helper.balance.getSubstrate(TREASURY); + const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address); - const treasuryBalanceAfter: bigint = (await api.query.system.account(TREASURY)).data.free.toBigInt(); - const aliceBalanceAfter: bigint = (await api.query.system.account(alice.address)).data.free.toBigInt(); - const fee = aliceBalanceBefore - aliceBalanceAfter - amount; - const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore; + const fee = aliceBalanceBefore - aliceBalanceAfter - amount; + const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore; - expect(result.success).to.be.true; - expect(treasuryIncrease).to.be.equal(fee); - }); + expect(treasuryIncrease).to.be.equal(fee); }); - it('Treasury balance increased by failed tx fee', async () => { - await usingApi(async (api) => { - //await skipInflationBlock(api); - await waitNewBlocks(api, 1); + itSub('Treasury balance increased by failed tx fee', async ({helper}) => { + const api = helper.api!; + await helper.wait.newBlocks(1); - const treasuryBalanceBefore = (await api.query.system.account(TREASURY)).data.free.toBigInt(); - const bobBalanceBefore = (await api.query.system.account(bob.address)).data.free.toBigInt(); + const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY); + const bobBalanceBefore = await helper.balance.getSubstrate(bob.address); - const badTx = api.tx.balances.setBalance(alice.address, 0, 0); - await expect(submitTransactionExpectFailAsync(bob, badTx)).to.be.rejected; + await expect(helper.signTransaction(bob, api.tx.balances.setBalance(alice.address, 0, 0))).to.be.rejected; + + const treasuryBalanceAfter = await helper.balance.getSubstrate(TREASURY); + const bobBalanceAfter = await helper.balance.getSubstrate(bob.address); - const treasuryBalanceAfter = (await api.query.system.account(TREASURY)).data.free.toBigInt(); - const bobBalanceAfter = (await api.query.system.account(bob.address)).data.free.toBigInt(); - const fee = bobBalanceBefore - bobBalanceAfter; - const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore; + const fee = bobBalanceBefore - bobBalanceAfter; + const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore; - expect(treasuryIncrease).to.be.equal(fee); - }); + expect(treasuryIncrease).to.be.equal(fee); }); - it('NFT Transactions also send fees to Treasury', async () => { - await usingApi(async (api) => { - await skipInflationBlock(api); - await waitNewBlocks(api, 1); + itSub('NFT Transactions also send fees to Treasury', async ({helper}) => { + await skipInflationBlock(helper.api!); + await helper.wait.newBlocks(1); - const treasuryBalanceBefore = (await api.query.system.account(TREASURY)).data.free.toBigInt(); - const aliceBalanceBefore = (await api.query.system.account(alice.address)).data.free.toBigInt(); + const treasuryBalanceBefore = await helper.balance.getSubstrate(TREASURY); + const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address); - await createCollectionExpectSuccess(); + await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}); - const treasuryBalanceAfter = (await api.query.system.account(TREASURY)).data.free.toBigInt(); - const aliceBalanceAfter = (await api.query.system.account(alice.address)).data.free.toBigInt(); - const fee = aliceBalanceBefore - aliceBalanceAfter; - const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore; + const treasuryBalanceAfter = await helper.balance.getSubstrate(TREASURY); + const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address); + const fee = aliceBalanceBefore - aliceBalanceAfter; + const treasuryIncrease = treasuryBalanceAfter - treasuryBalanceBefore; - expect(treasuryIncrease).to.be.equal(fee); - }); + expect(treasuryIncrease).to.be.equal(fee); }); - it('Fees are sane', async () => { - await usingApi(async (api) => { - await skipInflationBlock(api); - await waitNewBlocks(api, 1); + itSub('Fees are sane', async ({helper}) => { + const unique = helper.balance.getOneTokenNominal(); + await skipInflationBlock(helper.api!); + await helper.wait.newBlocks(1); - const aliceBalanceBefore: bigint = (await api.query.system.account(alice.address)).data.free.toBigInt(); + const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address); - await createCollectionExpectSuccess(); + await helper.nft.mintCollection(alice, {name: 'test', description: 'test', tokenPrefix: 'test'}); - const aliceBalanceAfter: bigint = (await api.query.system.account(alice.address)).data.free.toBigInt(); - const fee = aliceBalanceBefore - aliceBalanceAfter; + const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address); + const fee = aliceBalanceBefore - aliceBalanceAfter; - expect(fee / UNIQUE < BigInt(Math.ceil(saneMaximumFee + createCollectionDeposit))).to.be.true; - expect(fee / UNIQUE < BigInt(Math.ceil(saneMinimumFee + createCollectionDeposit))).to.be.true; - }); + expect(fee / unique < BigInt(Math.ceil(saneMaximumFee + createCollectionDeposit))).to.be.true; + expect(fee / unique < BigInt(Math.ceil(saneMinimumFee + createCollectionDeposit))).to.be.true; }); - it('NFT Transfer fee is close to 0.1 Unique', async () => { - await usingApi(async (api) => { - await skipInflationBlock(api); - await waitNewBlocks(api, 1); + itSub('NFT Transfer fee is close to 0.1 Unique', async ({helper}) => { + await skipInflationBlock(helper.api!); + await helper.wait.newBlocks(1); - const collectionId = await createCollectionExpectSuccess(); - const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT'); + const collection = await helper.nft.mintCollection(alice, { + name: 'test', + description: 'test', + tokenPrefix: 'test', + }); + // const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT'); + const token = await collection.mintToken(alice, {Substrate: alice.address}); - const aliceBalanceBefore: bigint = (await api.query.system.account(alice.address)).data.free.toBigInt(); - await transferExpectSuccess(collectionId, tokenId, alice, bob, 1, 'NFT'); - const aliceBalanceAfter: bigint = (await api.query.system.account(alice.address)).data.free.toBigInt(); + const aliceBalanceBefore = await helper.balance.getSubstrate(alice.address); + await token.transfer(alice, {Substrate: bob.address}); + const aliceBalanceAfter = await helper.balance.getSubstrate(alice.address); - const fee = Number(aliceBalanceBefore - aliceBalanceAfter) / Number(UNIQUE); - const expectedTransferFee = 0.1; - // fee drifts because of NextFeeMultiplier - const tolerance = 0.001; + const fee = Number(aliceBalanceBefore - aliceBalanceAfter) / Number(helper.balance.getOneTokenNominal()); + const expectedTransferFee = 0.1; + // fee drifts because of NextFeeMultiplier + const tolerance = 0.001; - expect(Math.abs(fee - expectedTransferFee)).to.be.lessThan(tolerance); - }); + expect(Math.abs(fee - expectedTransferFee)).to.be.lessThan(tolerance); }); - }); --- a/tests/src/destroyCollection.test.ts +++ b/tests/src/destroyCollection.test.ts @@ -15,36 +15,44 @@ // along with Unique Network. If not, see . import {IKeyringPair} from '@polkadot/types/types'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import {default as usingApi} from './substrate/substrate-api'; -import {createCollectionExpectSuccess, - destroyCollectionExpectSuccess, - destroyCollectionExpectFailure, - setCollectionLimitsExpectSuccess, - addCollectionAdminExpectSuccess, - getCreatedCollectionCount, - createItemExpectSuccess, - requirePallets, - Pallets, -} from './util/helpers'; +import {itSub, expect, usingPlaygrounds, Pallets} from './util/playgrounds'; -chai.use(chaiAsPromised); - describe('integration test: ext. destroyCollection():', () => { - it('NFT collection can be destroyed', async () => { - const collectionId = await createCollectionExpectSuccess(); - await destroyCollectionExpectSuccess(collectionId); - }); - it('Fungible collection can be destroyed', async () => { - const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - await destroyCollectionExpectSuccess(collectionId); + let alice: IKeyringPair; + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice] = await helper.arrange.createAccounts([100n], donor); + }); }); - it('ReFungible collection can be destroyed', async function() { - await requirePallets(this, [Pallets.ReFungible]); - const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - await destroyCollectionExpectSuccess(collectionId); + itSub('NFT collection can be destroyed', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'test', + description: 'test', + tokenPrefix: 'test', + }); + await collection.burn(alice); + expect(await collection.getData()).to.be.null; + }); + itSub('Fungible collection can be destroyed', async ({helper}) => { + const collection = await helper.ft.mintCollection(alice, { + name: 'test', + description: 'test', + tokenPrefix: 'test', + }, 0); + await collection.burn(alice); + expect(await collection.getData()).to.be.null; + }); + itSub.ifWithPallets('ReFungible collection can be destroyed', [Pallets.ReFungible], async ({helper}) => { + const collection = await helper.rft.mintCollection(alice, { + name: 'test', + description: 'test', + tokenPrefix: 'test', + }); + await collection.burn(alice); + expect(await collection.getData()).to.be.null; }); }); @@ -53,44 +61,60 @@ let bob: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor); }); }); - it('(!negative test!) Destroy a collection that never existed', async () => { - await usingApi(async (api) => { - // Find the collection that never existed - const collectionId = await getCreatedCollectionCount(api) + 1; - await destroyCollectionExpectFailure(collectionId); + itSub('(!negative test!) Destroy a collection that never existed', async ({helper}) => { + const collectionId = 1_000_000; + await expect(helper.collection.burn(alice, collectionId)).to.be.rejectedWith(/common\.CollectionNotFound/); + }); + itSub('(!negative test!) Destroy a collection that has already been destroyed', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'test', + description: 'test', + tokenPrefix: 'test', }); - }); - it('(!negative test!) Destroy a collection that has already been destroyed', async () => { - const collectionId = await createCollectionExpectSuccess(); - await destroyCollectionExpectSuccess(collectionId); - await destroyCollectionExpectFailure(collectionId); + await collection.burn(alice); + await expect(collection.burn(alice)).to.be.rejectedWith(/common\.CollectionNotFound/); }); - it('(!negative test!) Destroy a collection using non-owner account', async () => { - const collectionId = await createCollectionExpectSuccess(); - await destroyCollectionExpectFailure(collectionId, '//Bob'); - await destroyCollectionExpectSuccess(collectionId, '//Alice'); + itSub('(!negative test!) Destroy a collection using non-owner account', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'test', + description: 'test', + tokenPrefix: 'test', + }); + await expect(collection.burn(bob)).to.be.rejectedWith(/common\.NoPermission/); }); - it('(!negative test!) Destroy a collection using collection admin account', async () => { - const collectionId = await createCollectionExpectSuccess(); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - await destroyCollectionExpectFailure(collectionId, '//Bob'); + itSub('(!negative test!) Destroy a collection using collection admin account', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'test', + description: 'test', + tokenPrefix: 'test', + }); + await collection.addAdmin(alice, {Substrate: bob.address}); + await expect(collection.burn(bob)).to.be.rejectedWith(/common\.NoPermission/); }); - it('fails when OwnerCanDestroy == false', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanDestroy: false}); - - await destroyCollectionExpectFailure(collectionId, '//Alice'); + itSub('fails when OwnerCanDestroy == false', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'test', + description: 'test', + tokenPrefix: 'test', + limits: { + ownerCanDestroy: false, + }, + }); + await expect(collection.burn(alice)).to.be.rejectedWith(/common\.NoPermission/); }); - it('fails when a collection still has a token', async () => { - const collectionId = await createCollectionExpectSuccess(); - await createItemExpectSuccess(alice, collectionId, 'NFT'); - - await destroyCollectionExpectFailure(collectionId, '//Alice'); + itSub('fails when a collection still has a token', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'test', + description: 'test', + tokenPrefix: 'test', + }); + await collection.mintToken(alice, {Substrate: alice.address}); + await expect(collection.burn(alice)).to.be.rejectedWith(/common\.CantDestroyNotEmptyCollection/); }); }); --- a/tests/src/enableDisableTransfer.test.ts +++ b/tests/src/enableDisableTransfer.test.ts @@ -14,61 +14,69 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; -import usingApi from './substrate/substrate-api'; -import { - createItemExpectSuccess, - createCollectionExpectSuccess, - transferExpectSuccess, - transferExpectFailure, - setTransferFlagExpectSuccess, - setTransferFlagExpectFailure, -} from './util/helpers'; - -chai.use(chaiAsPromised); +import {IKeyringPair} from '@polkadot/types/types'; +import {itSub, usingPlaygrounds, expect} from './util/playgrounds'; describe('Enable/Disable Transfers', () => { - it('User can transfer token with enabled transfer flag', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - // nft - const nftCollectionId = await createCollectionExpectSuccess(); - const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT'); + let alice: IKeyringPair; + let bob: IKeyringPair; - // explicitely set transfer flag - await setTransferFlagExpectSuccess(alice, nftCollectionId, true); + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor); + }); + }); - await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 1); + itSub('User can transfer token with enabled transfer flag', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'test', + description: 'test', + tokenPrefix: 'test', + limits: { + transfersEnabled: true, + }, }); + const token = await collection.mintToken(alice, {Substrate: alice.address}); + await token.transfer(alice, {Substrate: bob.address}); + expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address}); }); - it('User can\'n transfer token with disabled transfer flag', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const alice = privateKeyWrapper('//Alice'); - const bob = privateKeyWrapper('//Bob'); - // nft - const nftCollectionId = await createCollectionExpectSuccess(); - const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT'); - - // explicitely set transfer flag - await setTransferFlagExpectSuccess(alice, nftCollectionId, false); - - await transferExpectFailure(nftCollectionId, newNftTokenId, alice, bob, 1); + itSub('User can\'n transfer token with disabled transfer flag', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'test', + description: 'test', + tokenPrefix: 'test', + limits: { + transfersEnabled: false, + }, }); + const token = await collection.mintToken(alice, {Substrate: alice.address}); + await expect(token.transfer(alice, {Substrate: bob.address})).to.be.rejectedWith(/common\.TransferNotAllowed/); }); }); describe('Negative Enable/Disable Transfers', () => { - it('Non-owner cannot change transfer flag', async () => { - await usingApi(async (api, privateKeyWrapper) => { - const bob = privateKeyWrapper('//Bob'); - // nft - const nftCollectionId = await createCollectionExpectSuccess(); + let alice: IKeyringPair; + let bob: IKeyringPair; + + before(async () => { + await usingPlaygrounds(async (helper, privateKey) => { + const donor = privateKey('//Alice'); + [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor); + }); + }); - // Change transfer flag - await setTransferFlagExpectFailure(bob, nftCollectionId, false); + itSub('Non-owner cannot change transfer flag', async ({helper}) => { + const collection = await helper.nft.mintCollection(alice, { + name: 'test', + description: 'test', + tokenPrefix: 'test', + limits: { + transfersEnabled: true, + }, }); + + await expect(collection.setLimits(bob, {transfersEnabled: false})).to.be.rejectedWith(/common\.NoPermission/); }); }); --- a/tests/src/nesting/properties.test.ts +++ b/tests/src/nesting/properties.test.ts @@ -666,7 +666,6 @@ `on adding property #${i} by signer #${j}`, ).to.be.fulfilled; } - } const properties = await nestedToken.getProperties(propertyKeys); --- a/tests/src/refungible.test.ts +++ b/tests/src/refungible.test.ts @@ -124,7 +124,7 @@ const token = await collection.mintToken(alice, 100n); expect(await collection.isTokenExists(token.tokenId)).to.be.true; expect(await token.getBalance({Substrate: alice.address})).to.be.equal(100n); - expect((await token.burn(alice, 99n)).success).to.be.true; + expect(await token.burn(alice, 99n)).to.be.true; expect(await collection.isTokenExists(token.tokenId)).to.be.true; expect(await token.getBalance({Substrate: alice.address})).to.be.equal(1n); }); @@ -136,7 +136,7 @@ expect(await collection.isTokenExists(token.tokenId)).to.be.true; expect(await token.getBalance({Substrate: alice.address})).to.be.equal(100n); - expect((await token.burn(alice, 100n)).success).to.be.true; + expect(await token.burn(alice, 100n)).to.be.true; expect(await collection.isTokenExists(token.tokenId)).to.be.false; }); @@ -152,17 +152,17 @@ expect(await token.getBalance({Substrate: alice.address})).to.be.equal(40n); expect(await token.getBalance({Substrate: bob.address})).to.be.equal(60n); - expect((await token.burn(alice, 40n)).success).to.be.true; + expect(await token.burn(alice, 40n)).to.be.true; expect(await collection.isTokenExists(token.tokenId)).to.be.true; expect(await token.getBalance({Substrate: alice.address})).to.be.equal(0n); - expect((await token.burn(bob, 59n)).success).to.be.true; + expect(await token.burn(bob, 59n)).to.be.true; expect(await token.getBalance({Substrate: bob.address})).to.be.equal(1n); expect(await collection.isTokenExists(token.tokenId)).to.be.true; - expect((await token.burn(bob, 1n)).success).to.be.true; + expect(await token.burn(bob, 1n)).to.be.true; expect(await collection.isTokenExists(token.tokenId)).to.be.false; }); --- a/tests/src/util/playgrounds/unique.ts +++ b/tests/src/util/playgrounds/unique.ts @@ -141,7 +141,7 @@ return keyring.addFromUri(seed); } - static extractCollectionIdFromCreationResult(creationResult: ITransactionResult) { + static extractCollectionIdFromCreationResult(creationResult: ITransactionResult): number { if (creationResult.status !== this.transactionStatus.SUCCESS) { throw Error('Unable to create collection!'); } @@ -160,12 +160,15 @@ return collectionId; } - static extractTokensFromCreationResult(creationResult: ITransactionResult) { + static extractTokensFromCreationResult(creationResult: ITransactionResult): { + success: boolean, + tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[], + } { if (creationResult.status !== this.transactionStatus.SUCCESS) { throw Error('Unable to create tokens!'); } let success = false; - const tokens = [] as any; + const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[]; creationResult.result.events.forEach(({event: {data, method, section}}) => { if (method === 'ExtrinsicSuccess') { success = true; @@ -173,19 +176,23 @@ tokens.push({ collectionId: parseInt(data[0].toString(), 10), tokenId: parseInt(data[1].toString(), 10), - owner: data[2].toJSON(), + owner: data[2].toHuman(), + amount: data[3].toBigInt(), }); } }); return {success, tokens}; } - static extractTokensFromBurnResult(burnResult: ITransactionResult) { + static extractTokensFromBurnResult(burnResult: ITransactionResult): { + success: boolean, + tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[], + } { if (burnResult.status !== this.transactionStatus.SUCCESS) { throw Error('Unable to burn tokens!'); } let success = false; - const tokens = [] as any; + const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[]; burnResult.result.events.forEach(({event: {data, method, section}}) => { if (method === 'ExtrinsicSuccess') { success = true; @@ -193,14 +200,15 @@ tokens.push({ collectionId: parseInt(data[0].toString(), 10), tokenId: parseInt(data[1].toString(), 10), - owner: data[2].toJSON(), + owner: data[2].toHuman(), + amount: data[3].toBigInt(), }); } }); return {success, tokens}; } - static findCollectionInEvents(events: {event: IEvent}[], collectionId: number, expectedSection: string, expectedMethod: string) { + static findCollectionInEvents(events: {event: IEvent}[], collectionId: number, expectedSection: string, expectedMethod: string): boolean { let eventId = null; events.forEach(({event: {data, method, section}}) => { if ((section === expectedSection) && (method === expectedMethod)) { @@ -1022,12 +1030,9 @@ * @param tokenId ID of token * @param amount amount of tokens to be burned. For NFT must be set to 1n * @example burnToken(aliceKeyring, 10, 5); - * @returns ```true``` and burnt token number is extrinsic success. Otherwise ```false``` and ```null``` + * @returns ```true``` if the extrinsic is successful, otherwise ```false``` */ - async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount=1n): Promise<{ - success: boolean, - token: number | null - }> { + async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount=1n): Promise { const burnResult = await this.helper.executeExtrinsic( signer, 'api.tx.unique.burnItem', [collectionId, tokenId, amount], @@ -1035,7 +1040,7 @@ ); const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult); if (burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens'); - return {success: burnedTokens.success, token: burnedTokens.tokens.length > 0 ? burnedTokens.tokens[0] : null}; + return burnedTokens.success; } /** @@ -1161,7 +1166,9 @@ if (tokenData === null || tokenData.owner === null) return null; const owner = {} as any; for (const key of Object.keys(tokenData.owner)) { - owner[key.toLocaleLowerCase()] = new CrossAccountId(tokenData.owner[key]).withNormalizedSubstrate(); + owner[key.toLocaleLowerCase()] = key.toLocaleLowerCase() == 'substrate' + ? CrossAccountId.normalizeSubstrateAddress(tokenData.owner[key]) + : tokenData.owner[key]; } tokenData.normalizedOwner = CrossAccountId.fromLowerCaseKeys(owner); return tokenData; @@ -1711,9 +1718,9 @@ * @param tokenId ID of token * @param amount number of pieces to be burnt * @example burnToken(aliceKeyring, 10, 5); - * @returns ```true``` and burnt token number, if extrinsic is successful. Otherwise ```false``` and ```null``` + * @returns ```true``` if the extrinsic is successful, otherwise ```false``` */ - async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount=1n): Promise<{ success: boolean; token: number | null; }> { + async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount=1n): Promise { return await super.burnToken(signer, collectionId, tokenId, amount); } @@ -1919,7 +1926,7 @@ * @returns ```true``` if extrinsic success, otherwise ```false``` */ async burnTokens(signer: IKeyringPair, collectionId: number, amount=1n): Promise { - return (await super.burnToken(signer, collectionId, 0, amount)).success; + return await super.burnToken(signer, collectionId, 0, amount); } /** -- gitstuff