--- a/tests/package.json +++ b/tests/package.json @@ -49,6 +49,7 @@ "testRemoveCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionAdmin.test.ts", "testRemoveCollectionSponsor": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionSponsor.test.ts", "testRemoveFromAllowList": "mocha --timeout 9999999 -r ts-node/register ./**/removeFromAllowList.test.ts", + "testAllowLists": "mocha --timeout 9999999 -r ts-node/register ./**/allowLists.test.ts", "testConnection": "mocha --timeout 9999999 -r ts-node/register ./**/connection.test.ts", "testContracts": "mocha --timeout 9999999 -r ts-node/register ./**/contracts.test.ts", "testCreateItem": "mocha --timeout 9999999 -r ts-node/register ./**/createItem.test.ts", --- a/tests/src/adminTransferAndBurn.test.ts +++ b/tests/src/adminTransferAndBurn.test.ts @@ -17,56 +17,63 @@ 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, - createItemExpectSuccess, - transferExpectFailure, - transferFromExpectSuccess, - burnItemExpectFailure, - burnFromExpectSuccess, - setCollectionLimitsExpectSuccess, -} from './util/helpers'; +import {usingPlaygrounds} from './util/playgrounds'; chai.use(chaiAsPromised); const expect = chai.expect; +let donor: IKeyringPair; + +before(async () => { + await usingPlaygrounds(async (_, privateKey) => { + donor = privateKey('//Alice'); + }); +}); + describe('Integration Test: ownerCanTransfer allows admins to use only transferFrom/burnFrom:', () => { let alice: IKeyringPair; let bob: IKeyringPair; let charlie: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie] = await helper.arrange.createAccounts([10n, 10n, 10n], donor); }); }); it('admin transfers other user\'s token', async () => { - await usingApi(async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true}); - - const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', {Substrate: bob.address}); + 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; - await transferExpectFailure(collectionId, tokenId, alice, charlie); + 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 transferFromExpectSuccess(collectionId, tokenId, alice, bob, charlie, 1); + 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 usingApi(async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true}); + 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; - const tokenId = await createItemExpectSuccess(alice, collectionId, 'NFT', {Substrate: bob.address}); + const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: bob.address}); + const burnTxFailed = async () => helper.nft.burnToken(alice, collectionId, tokenId); - await burnItemExpectFailure(alice, collectionId, tokenId); + await expect(burnTxFailed()).to.be.rejected; - await burnFromExpectSuccess(alice, bob, collectionId, tokenId); + 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 @@ -17,31 +17,19 @@ import {IKeyringPair} from '@polkadot/types/types'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import usingApi, {submitTransactionExpectFailAsync} from './substrate/substrate-api'; -import { - addToAllowListExpectSuccess, - createCollectionExpectSuccess, - createItemExpectSuccess, - destroyCollectionExpectSuccess, - enableAllowListExpectSuccess, - normalizeAccountId, - addCollectionAdminExpectSuccess, - addToAllowListExpectFail, - removeFromAllowListExpectSuccess, - removeFromAllowListExpectFailure, - addToAllowListAgainExpectSuccess, - transferExpectFailure, - approveExpectSuccess, - approveExpectFail, - transferExpectSuccess, - transferFromExpectSuccess, - setMintPermissionExpectSuccess, - createItemExpectFailure, -} from './util/helpers'; +import {usingPlaygrounds} from './util/playgrounds'; chai.use(chaiAsPromised); const expect = chai.expect; +let donor: IKeyringPair; + +before(async () => { + await usingPlaygrounds(async (_, privateKey) => { + donor = privateKey('//Alice'); + }); +}); + let alice: IKeyringPair; let bob: IKeyringPair; let charlie: IKeyringPair; @@ -49,266 +37,348 @@ describe('Integration Test ext. Allow list tests', () => { before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); }); it('Owner can add address to allow list', async () => { - const collectionId = await createCollectionExpectSuccess(); - await addToAllowListExpectSuccess(alice, collectionId, bob.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address}); + const allowList = await helper.nft.getAllowList(collectionId); + expect(allowList).to.be.deep.contains({Substrate: bob.address}); + }); }); it('Admin can add address to allow list', async () => { - const collectionId = await createCollectionExpectSuccess(); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - await addToAllowListExpectSuccess(bob, collectionId, charlie.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.addAdmin(alice, collectionId, {Substrate: bob.address}); + + await helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address}); + const allowList = await helper.nft.getAllowList(collectionId); + expect(allowList).to.be.deep.contains({Substrate: charlie.address}); + }); }); it('Non-privileged user cannot add address to allow list', async () => { - const collectionId = await createCollectionExpectSuccess(); - await addToAllowListExpectFail(bob, collectionId, charlie.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const addToAllowListTx = async () => helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address}); + await expect(addToAllowListTx()).to.be.rejected; + }); }); it('Nobody can add address to allow list of non-existing collection', async () => { const collectionId = (1<<32) - 1; - await addToAllowListExpectFail(alice, collectionId, bob.address); + await usingPlaygrounds(async (helper) => { + const addToAllowListTx = async () => helper.nft.addToAllowList(bob, collectionId, {Substrate: charlie.address}); + await expect(addToAllowListTx()).to.be.rejected; + }); }); it('Nobody can add address to allow list of destroyed collection', async () => { - const collectionId = await createCollectionExpectSuccess(); - await destroyCollectionExpectSuccess(collectionId, '//Alice'); - await addToAllowListExpectFail(alice, collectionId, bob.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.collection.burn(alice, collectionId); + const addToAllowListTx = async () => helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address}); + await expect(addToAllowListTx()).to.be.rejected; + }); }); it('If address is already added to allow list, nothing happens', async () => { - const collectionId = await createCollectionExpectSuccess(); - await addToAllowListExpectSuccess(alice, collectionId, bob.address); - await addToAllowListAgainExpectSuccess(alice, collectionId, bob.address); + await usingPlaygrounds(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.nft.addToAllowList(alice, collectionId, {Substrate: bob.address}); + const allowList = await helper.nft.getAllowList(collectionId); + expect(allowList).to.be.deep.contains({Substrate: bob.address}); + }); }); it('Owner can remove address from allow list', async () => { - const collectionId = await createCollectionExpectSuccess(); - await addToAllowListExpectSuccess(alice, collectionId, bob.address); - await removeFromAllowListExpectSuccess(alice, collectionId, normalizeAccountId(bob)); + await usingPlaygrounds(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.removeFromAllowList(alice, collectionId, {Substrate: bob.address}); + + const allowList = await helper.nft.getAllowList(collectionId); + + expect(allowList).to.be.not.deep.contains({Substrate: bob.address}); + }); }); it('Admin can remove address from allow list', async () => { - const collectionId = await createCollectionExpectSuccess(); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - await addToAllowListExpectSuccess(alice, collectionId, charlie.address); - await removeFromAllowListExpectSuccess(bob, collectionId, normalizeAccountId(charlie)); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.addAdmin(alice, collectionId, {Substrate: charlie.address}); + await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address}); + await helper.collection.removeFromAllowList(charlie, collectionId, {Substrate: bob.address}); + + const allowList = await helper.nft.getAllowList(collectionId); + + expect(allowList).to.be.not.deep.contains({Substrate: bob.address}); + }); }); it('Non-privileged user cannot remove address from allow list', async () => { - const collectionId = await createCollectionExpectSuccess(); - await addToAllowListExpectSuccess(alice, collectionId, charlie.address); - await removeFromAllowListExpectFailure(bob, collectionId, normalizeAccountId(charlie)); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.addToAllowList(alice, collectionId, {Substrate: charlie.address}); + const removeTx = async () => helper.collection.removeFromAllowList(bob, collectionId, {Substrate: charlie.address}); + await expect(removeTx()).to.be.rejected; + const allowList = await helper.nft.getAllowList(collectionId); + + expect(allowList).to.be.deep.contains({Substrate: charlie.address}); + }); }); it('Nobody can remove address from allow list of non-existing collection', async () => { const collectionId = (1<<32) - 1; - await removeFromAllowListExpectFailure(alice, collectionId, normalizeAccountId(charlie)); + await usingPlaygrounds(async (helper) => { + const removeTx = async () => helper.collection.removeFromAllowList(bob, collectionId, {Substrate: charlie.address}); + await expect(removeTx()).to.be.rejected; + }); }); it('Nobody can remove address from allow list of deleted collection', async () => { - const collectionId = await createCollectionExpectSuccess(); - await addToAllowListExpectSuccess(alice, collectionId, charlie.address); - await destroyCollectionExpectSuccess(collectionId, '//Alice'); - await removeFromAllowListExpectFailure(alice, collectionId, normalizeAccountId(charlie)); + await usingPlaygrounds(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); + const removeTx = async () => helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address}); + + await expect(removeTx()).to.be.rejected; + }); }); it('If address is already removed from allow list, nothing happens', async () => { - const collectionId = await createCollectionExpectSuccess(); - await addToAllowListExpectSuccess(alice, collectionId, charlie.address); - await removeFromAllowListExpectSuccess(alice, collectionId, normalizeAccountId(charlie)); - await removeFromAllowListExpectSuccess(alice, collectionId, normalizeAccountId(charlie)); + await usingPlaygrounds(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.removeFromAllowList(alice, collectionId, {Substrate: bob.address}); + const allowListBefore = await helper.nft.getAllowList(collectionId); + expect(allowListBefore).to.be.not.deep.contains({Substrate: bob.address}); + + await helper.collection.removeFromAllowList(alice, collectionId, {Substrate: bob.address}); + + const allowListAfter = await helper.nft.getAllowList(collectionId); + expect(allowListAfter).to.be.not.deep.contains({Substrate: bob.address}); + }); }); it('If Public Access mode is set to AllowList, tokens can’t be transferred from a non-allowlisted address with transfer or transferFrom. Test1', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - await enableAllowListExpectSuccess(alice, collectionId); - await addToAllowListExpectSuccess(alice, collectionId, charlie.address); + await usingPlaygrounds(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: charlie.address}); - await transferExpectFailure( - collectionId, - itemId, - alice, - charlie, - 1, - ); + const transferResult = async () => helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}); + await expect(transferResult()).to.be.rejected; + }); }); it('If Public Access mode is set to AllowList, tokens can’t be transferred from a non-allowlisted address with transfer or transferFrom. Test2', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - await enableAllowListExpectSuccess(alice, collectionId); - await addToAllowListExpectSuccess(alice, collectionId, alice.address); - await addToAllowListExpectSuccess(alice, collectionId, charlie.address); - await approveExpectSuccess(collectionId, itemId, alice, charlie.address); - await removeFromAllowListExpectSuccess(alice, collectionId, normalizeAccountId(alice)); + await usingPlaygrounds(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 transferExpectFailure( - collectionId, - itemId, - alice, - charlie, - 1, - ); + const transferResult = async () => helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}); + await expect(transferResult()).to.be.rejected; + }); }); it('If Public Access mode is set to AllowList, tokens can’t be transferred to a non-allowlisted address with transfer or transferFrom. Test1', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - await enableAllowListExpectSuccess(alice, collectionId); - await addToAllowListExpectSuccess(alice, collectionId, alice.address); + await usingPlaygrounds(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 transferExpectFailure( - collectionId, - itemId, - alice, - charlie, - 1, - ); + const transferResult = async () => helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}); + await expect(transferResult()).to.be.rejected; + }); }); it('If Public Access mode is set to AllowList, tokens can’t be transferred to a non-allowlisted address with transfer or transferFrom. Test2', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - await enableAllowListExpectSuccess(alice, collectionId); - await addToAllowListExpectSuccess(alice, collectionId, alice.address); - await addToAllowListExpectSuccess(alice, collectionId, charlie.address); - await approveExpectSuccess(collectionId, itemId, alice, charlie.address); - await removeFromAllowListExpectSuccess(alice, collectionId, normalizeAccountId(alice)); + await usingPlaygrounds(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 transferExpectFailure( - collectionId, - itemId, - alice, - charlie, - 1, - ); + const transferResult = async () => helper.nft.transferToken(alice, collectionId, tokenId, {Substrate: charlie.address}); + await expect(transferResult()).to.be.rejected; + }); }); it('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 () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - await enableAllowListExpectSuccess(alice, collectionId); - - await usingApi(async (api) => { - const tx = api.tx.unique.burnItem(collectionId, itemId, /*normalizeAccountId(Alice.address),*/ 11); - const badTransaction = async function () { - await submitTransactionExpectFailAsync(alice, tx); - }; - await expect(badTransaction()).to.be.rejected; + await usingPlaygrounds(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'}); + const burnTx = async () => helper.nft.burnToken(bob, collectionId, tokenId); + await expect(burnTx()).to.be.rejected; }); }); it('If Public Access mode is set to AllowList, token transfers can’t be Approved by a non-allowlisted address (see Approve method)', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - await enableAllowListExpectSuccess(alice, collectionId); - await approveExpectFail(collectionId, itemId, alice, bob); + await usingPlaygrounds(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'}); + const approveTx = async () => helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}); + await expect(approveTx()).to.be.rejected; + }); }); it('If Public Access mode is set to AllowList, tokens can be transferred to a allowlisted address with transfer.', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - await enableAllowListExpectSuccess(alice, collectionId); - await addToAllowListExpectSuccess(alice, collectionId, alice.address); - await addToAllowListExpectSuccess(alice, collectionId, charlie.address); - await transferExpectSuccess(collectionId, itemId, alice, charlie, 1, 'NFT'); + await usingPlaygrounds(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); + }); }); - it('If Public Access mode is set to AllowList, tokens can be transferred to a alowlisted address with transferFrom.', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - await enableAllowListExpectSuccess(alice, collectionId); - await addToAllowListExpectSuccess(alice, collectionId, alice.address); - await addToAllowListExpectSuccess(alice, collectionId, charlie.address); - await approveExpectSuccess(collectionId, itemId, alice, charlie.address); - await transferFromExpectSuccess(collectionId, itemId, alice, alice, charlie, 1, 'NFT'); + it('If Public Access mode is set to AllowList, tokens can be transferred to a allowlisted address with transferFrom.', async () => { + await usingPlaygrounds(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.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); + }); }); it('If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transfer', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - await enableAllowListExpectSuccess(alice, collectionId); - await addToAllowListExpectSuccess(alice, collectionId, alice.address); - await addToAllowListExpectSuccess(alice, collectionId, charlie.address); - await transferExpectSuccess(collectionId, itemId, alice, charlie, 1, 'NFT'); + await usingPlaygrounds(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); + }); }); it('If Public Access mode is set to AllowList, tokens can be transferred from a allowlisted address with transferFrom', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - await enableAllowListExpectSuccess(alice, collectionId); - await addToAllowListExpectSuccess(alice, collectionId, alice.address); - await addToAllowListExpectSuccess(alice, collectionId, charlie.address); - await approveExpectSuccess(collectionId, itemId, alice, charlie.address); - await transferFromExpectSuccess(collectionId, itemId, alice, alice, charlie, 1, 'NFT'); + await usingPlaygrounds(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.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); + }); }); it('If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by owner', async () => { - const collectionId = await createCollectionExpectSuccess(); - await enableAllowListExpectSuccess(alice, collectionId); - await setMintPermissionExpectSuccess(alice, collectionId, false); - await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: false}); + const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address}); + const token = await helper.nft.getToken(collectionId, tokenId); + expect(token).to.be.not.null; + }); }); it('If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens can be created by admin', async () => { - const collectionId = await createCollectionExpectSuccess(); - await enableAllowListExpectSuccess(alice, collectionId); - await setMintPermissionExpectSuccess(alice, collectionId, false); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - await createItemExpectSuccess(bob, collectionId, 'NFT', bob.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: false}); + await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address}); + const {tokenId} = await helper.nft.mintToken(bob, {collectionId: collectionId, owner: bob.address}); + const token = await helper.nft.getToken(collectionId, tokenId); + expect(token).to.be.not.null; + }); }); it('If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and allow-listed address', async () => { - const collectionId = await createCollectionExpectSuccess(); - await enableAllowListExpectSuccess(alice, collectionId); - await setMintPermissionExpectSuccess(alice, collectionId, false); - await addToAllowListExpectSuccess(alice, collectionId, bob.address); - await createItemExpectFailure(bob, collectionId, 'NFT', bob.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: false}); + await helper.collection.addToAllowList(alice, collectionId, {Substrate: bob.address}); + const mintTokenTx = async () => helper.nft.mintToken(bob, {collectionId: collectionId, owner: bob.address}); + await expect(mintTokenTx()).to.be.rejected; + }); }); it('If Public Access mode is set to AllowList, and Mint Permission is set to false, tokens cannot be created by non-privileged and non-allow listed address', async () => { - const collectionId = await createCollectionExpectSuccess(); - await enableAllowListExpectSuccess(alice, collectionId); - await setMintPermissionExpectSuccess(alice, collectionId, false); - await createItemExpectFailure(bob, collectionId, 'NFT', bob.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: false}); + const mintTokenTx = async () => helper.nft.mintToken(bob, {collectionId: collectionId, owner: bob.address}); + await expect(mintTokenTx()).to.be.rejected; + }); }); it('If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by owner', async () => { - const collectionId = await createCollectionExpectSuccess(); - await enableAllowListExpectSuccess(alice, collectionId); - await setMintPermissionExpectSuccess(alice, collectionId, true); - await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: true}); + const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address}); + const owner = await helper.nft.getTokenOwner(collectionId, tokenId); + expect(owner.Substrate).to.be.equal(alice.address); + }); }); it('If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by admin', async () => { - const collectionId = await createCollectionExpectSuccess(); - await enableAllowListExpectSuccess(alice, collectionId); - await setMintPermissionExpectSuccess(alice, collectionId, true); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - await createItemExpectSuccess(bob, collectionId, 'NFT', bob.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: true}); + await helper.nft.addAdmin(alice, collectionId, {Substrate: bob.address}); + const {tokenId} = await helper.nft.mintToken(bob, {collectionId: collectionId, owner: bob.address}); + const owner = await helper.nft.getTokenOwner(collectionId, tokenId); + expect(owner.Substrate).to.be.equal(bob.address); + }); }); it('If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens cannot be created by non-privileged and non-allow listed address', async () => { - const collectionId = await createCollectionExpectSuccess(); - await enableAllowListExpectSuccess(alice, collectionId); - await setMintPermissionExpectSuccess(alice, collectionId, true); - await createItemExpectFailure(bob, collectionId, 'NFT', bob.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: true}); + const mintTokenTx = async () => helper.nft.mintToken(bob, {collectionId: collectionId, owner: bob.address}); + await expect(mintTokenTx()).to.be.rejected; + }); }); it('If Public Access mode is set to AllowList, and Mint Permission is set to true, tokens can be created by non-privileged and allow listed address', async () => { - const collectionId = await createCollectionExpectSuccess(); - await enableAllowListExpectSuccess(alice, collectionId); - await setMintPermissionExpectSuccess(alice, collectionId, true); - await addToAllowListExpectSuccess(alice, collectionId, bob.address); - await createItemExpectSuccess(bob, collectionId, 'NFT', bob.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.setPermissions(alice, collectionId, {access: 'AllowList', mintMode: true}); + await helper.nft.addToAllowList(alice, collectionId, {Substrate: bob.address}); + const {tokenId} = await helper.nft.mintToken(bob, {collectionId: collectionId, owner: bob.address}); + const owner = await helper.nft.getTokenOwner(collectionId, tokenId); + expect(owner.Substrate).to.be.equal(bob.address); + }); }); }); --- a/tests/src/approve.test.ts +++ b/tests/src/approve.test.ts @@ -15,28 +15,26 @@ // along with Unique Network. If not, see . import {IKeyringPair} from '@polkadot/types/types'; -import {ApiPromise} from '@polkadot/api'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import {default as usingApi} from './substrate/substrate-api'; import { approveExpectFail, approveExpectSuccess, createCollectionExpectSuccess, createItemExpectSuccess, - destroyCollectionExpectSuccess, - setCollectionLimitsExpectSuccess, - transferExpectSuccess, - addCollectionAdminExpectSuccess, - adminApproveFromExpectFail, - getCreatedCollectionCount, - transferFromExpectSuccess, - transferFromExpectFail, - requirePallets, - Pallets, } from './util/helpers'; +import {usingPlaygrounds} from './util/playgrounds'; + +let donor: IKeyringPair; + +before(async () => { + await usingPlaygrounds(async (_, privateKey) => { + donor = privateKey('//Alice'); + }); +}); chai.use(chaiAsPromised); +const expect = chai.expect; describe('Integration Test approve(spender, collection_id, item_id, amount):', () => { let alice: IKeyringPair; @@ -44,63 +42,89 @@ let charlie: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); }); it('[nft] Execute the extrinsic and check approvedList', async () => { - const nftCollectionId = await createCollectionExpectSuccess(); - const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT'); - await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address); + await usingPlaygrounds(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.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}); + expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true; + }); }); it('[fungible] Execute the extrinsic and check approvedList', async () => { - const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible'); - await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + await helper.ft.mintTokens(alice, collectionId, alice.address, 10n); + const tokenId = await helper.ft.getLastTokenId(collectionId); + await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}); + const amount = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + expect(amount).to.be.equal(BigInt(1)); + }); }); it('[refungible] Execute the extrinsic and check approvedList', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - const reFungibleCollectionId = - await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible'); - await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n}); + await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}); + const amount = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + expect(amount).to.be.equal(BigInt(1)); + }); }); it('[nft] Remove approval by using 0 amount', async () => { - const nftCollectionId = await createCollectionExpectSuccess(); - const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT'); - await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address, 1); - await approveExpectSuccess(nftCollectionId, newNftTokenId, alice, bob.address, 0); + await usingPlaygrounds(async (helper) => { + const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const collectionId = collection.collectionId; + const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: alice.address}); + await helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}); + expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true; + await helper.signTransaction(alice, helper.api?.tx.unique.approve({Substrate: bob.address}, collectionId, tokenId, 0)); + expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false; + }); }); it('[fungible] Remove approval by using 0 amount', async () => { - const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible'); - await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address, 1); - await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address, 0); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + await helper.ft.mintTokens(alice, collectionId, alice.address, 10n); + const tokenId = await helper.ft.getLastTokenId(collectionId); + await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}); + const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + expect(amountBefore).to.be.equal(BigInt(1)); + + await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 0n); + const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + expect(amountAfter).to.be.equal(BigInt(0)); + }); }); it('[refungible] Remove approval by using 0 amount', async function() { - await requirePallets(this, [Pallets.ReFungible]); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n}); + await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}); + const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + expect(amountBefore).to.be.equal(BigInt(1)); - const reFungibleCollectionId = - await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible'); - await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 1); - await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 0); + await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 0n); + const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + expect(amountAfter).to.be.equal(BigInt(0)); + }); }); it('can`t be called by collection owner on non-owned item when OwnerCanTransfer == false', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address); - - await adminApproveFromExpectFail(collectionId, itemId, alice, bob.address, charlie.address); + await usingPlaygrounds(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: bob.address}); + const approveTokenTx = async () => helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address}); + await expect(approveTokenTx()).to.be.rejected; + }); }); }); @@ -110,31 +134,39 @@ let charlie: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); - }); + }); it('NFT', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address); - await approveExpectSuccess(collectionId, itemId, bob, charlie.address); + await usingPlaygrounds(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: bob.address}); + await helper.nft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}); + expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.true; + }); }); it('Fungible up to an approved amount', async () => { - const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}}); - const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', bob.address); - await approveExpectSuccess(collectionId, itemId, bob, charlie.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + await helper.ft.mintTokens(alice, collectionId, bob.address, 10n); + const tokenId = await helper.ft.getLastTokenId(collectionId); + await helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}); + const amount = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: charlie.address}, {Substrate: bob.address}); + expect(amount).to.be.equal(BigInt(1)); + }); }); it('ReFungible up to an approved amount', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}}); - const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', bob.address); - await approveExpectSuccess(collectionId, itemId, bob, charlie.address); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: bob.address, pieces: 100n}); + await helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}, 100n); + const amount = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: charlie.address}, {Substrate: bob.address}); + expect(amount).to.be.equal(BigInt(100n)); + }); }); }); @@ -144,34 +176,45 @@ let charlie: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); - }); + }); it('NFT', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address); - await approveExpectSuccess(collectionId, itemId, bob, charlie.address); - await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'NFT'); + await usingPlaygrounds(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: bob.address}); + await helper.nft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}); + await helper.nft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + const owner = await helper.nft.getTokenOwner(collectionId, tokenId); + expect(owner.Substrate).to.be.equal(alice.address); + }); }); it('Fungible up to an approved amount', async () => { - const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}}); - const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', bob.address); - await approveExpectSuccess(collectionId, itemId, bob, charlie.address); - await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'Fungible'); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + await helper.ft.mintTokens(alice, collectionId, bob.address, 10n); + const tokenId = await helper.ft.getLastTokenId(collectionId); + await helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}); + const before = await helper.ft.getBalance(collectionId, {Substrate: alice.address}); + await helper.ft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}, 1n); + const after = await helper.ft.getBalance(collectionId, {Substrate: alice.address}); + expect(after - before).to.be.equal(BigInt(1)); + }); }); it('ReFungible up to an approved amount', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}}); - const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', bob.address); - await approveExpectSuccess(collectionId, itemId, bob, charlie.address); - await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'ReFungible'); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: bob.address, pieces: 100n}); + await helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}); + const before = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address}); + await helper.rft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}, 1n); + const after = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address}); + expect(after - before).to.be.equal(BigInt(1)); + }); }); }); @@ -181,37 +224,52 @@ let charlie: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); - }); + }); it('NFT', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address); - await approveExpectSuccess(collectionId, itemId, bob, charlie.address); - await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'NFT'); - await transferFromExpectFail(collectionId, itemId, charlie, bob, alice, 1); + await usingPlaygrounds(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: bob.address}); + await helper.nft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}); + await helper.nft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + const owner = await helper.nft.getTokenOwner(collectionId, tokenId); + expect(owner.Substrate).to.be.equal(alice.address); + const transferTokenFromTx = async () => helper.nft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + await expect(transferTokenFromTx()).to.be.rejected; + }); }); it('Fungible up to an approved amount', async () => { - const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}}); - const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', bob.address); - await approveExpectSuccess(collectionId, itemId, bob, charlie.address); - await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'Fungible'); - await transferFromExpectFail(collectionId, itemId, charlie, bob, alice, 1); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + await helper.ft.mintTokens(alice, collectionId, bob.address, 10n); + const tokenId = await helper.ft.getLastTokenId(collectionId); + await helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}); + const before = await helper.ft.getBalance(collectionId, {Substrate: alice.address}); + await helper.ft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}, 1n); + const after = await helper.ft.getBalance(collectionId, {Substrate: alice.address}); + expect(after - before).to.be.equal(BigInt(1)); + + const transferTokenFromTx = async () => helper.ft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}, 1n); + await expect(transferTokenFromTx()).to.be.rejected; + }); }); it('ReFungible up to an approved amount', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}}); - const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', bob.address); - await approveExpectSuccess(collectionId, itemId, bob, charlie.address); - await transferFromExpectSuccess(collectionId, itemId, charlie, bob, alice, 1, 'ReFungible'); - await transferFromExpectFail(collectionId, itemId, charlie, bob, alice, 1); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: bob.address, pieces: 100n}); + await helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}, 100n); + const before = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address}); + await helper.rft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}, 100n); + const after = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address}); + expect(after - before).to.be.equal(BigInt(100)); + const transferTokenFromTx = async () => helper.rft.transferTokenFrom(charlie, collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}, 100n); + await expect(transferTokenFromTx()).to.be.rejected; + }); }); }); @@ -222,20 +280,28 @@ let dave: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); - dave = privateKeyWrapper('//Dave'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor); }); - }); + }); it('If a user B is approved to transfer 10 Fungible tokens from user A, they can transfer 2 tokens to user C, which will result in decreasing approval from 10 to 8. Then user B can transfer 8 tokens to user D.', async () => { - const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}}); - const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', alice.address); - await approveExpectSuccess(collectionId, itemId, alice, bob.address, 10); - await transferFromExpectSuccess(collectionId, itemId, bob, alice, charlie, 2, 'Fungible'); - await transferFromExpectSuccess(collectionId, itemId, bob, alice, dave, 8, 'Fungible'); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + await helper.ft.mintTokens(alice, collectionId, alice.address, 10n); + const tokenId = await helper.ft.getLastTokenId(collectionId); + await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 10n); + + const charlieBefore = await helper.ft.getBalance(collectionId, {Substrate: charlie.address}); + await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: alice.address}, {Substrate: charlie.address}, 2n); + const charlieAfter = await helper.ft.getBalance(collectionId, {Substrate: charlie.address}); + expect(charlieAfter - charlieBefore).to.be.equal(BigInt(2)); + + const daveBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address}); + await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: alice.address}, {Substrate: dave.address}, 8n); + const daveAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address}); + expect(daveAfter - daveBefore).to.be.equal(BigInt(8)); + }); }); }); @@ -245,38 +311,57 @@ let charlie: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); }); it('NFT', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT'); - await approveExpectSuccess(collectionId, itemId, alice, bob.address, 1); - await approveExpectSuccess(collectionId, itemId, alice, bob.address, 0); - await transferFromExpectFail(collectionId, itemId, bob, bob, charlie, 1); + await usingPlaygrounds(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.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}); + expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true; + await helper.signTransaction(alice, helper.api?.tx.unique.approve({Substrate: bob.address}, collectionId, tokenId, 0)); + expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false; + const transferTokenFromTx = async () => helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: bob.address}, {Substrate: bob.address}); + await expect(transferTokenFromTx()).to.be.rejected; + }); }); it('Fungible', async () => { - const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible'); - await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address, 1); - await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, alice, bob.address, 0); - await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, bob, bob, charlie, 1); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + await helper.ft.mintTokens(alice, collectionId, alice.address, 10n); + const tokenId = await helper.ft.getLastTokenId(collectionId); + await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}); + const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + expect(amountBefore).to.be.equal(BigInt(1)); + + await helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 0n); + const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + expect(amountAfter).to.be.equal(BigInt(0)); + + const transferTokenFromTx = async () => helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: bob.address}, {Substrate: charlie.address}, 1n); + await expect(transferTokenFromTx()).to.be.rejected; + }); }); it('ReFungible', async function() { - await requirePallets(this, [Pallets.ReFungible]); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n}); + await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}); + const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + expect(amountBefore).to.be.equal(BigInt(1)); - const reFungibleCollectionId = - await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible'); - await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 1); - await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, alice, bob.address, 0); - await transferFromExpectFail(reFungibleCollectionId, newReFungibleTokenId, bob, bob, charlie, 1); + await helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 0n); + const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, {Substrate: alice.address}); + expect(amountAfter).to.be.equal(BigInt(0)); + + const transferTokenFromTx = async () => helper.rft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: bob.address}, {Substrate: charlie.address}, 100n); + await expect(transferTokenFromTx()).to.be.rejected; + }); }); }); @@ -286,31 +371,38 @@ let charlie: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); }); it('1 for NFT', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address); - await approveExpectFail(collectionId, itemId, bob, charlie, 2); + await usingPlaygrounds(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: bob.address}); + const approveTx = async () => helper.signTransaction(bob, helper.api?.tx.unique.approve({Substrate: charlie.address}, collectionId, tokenId, 2)); + await expect(approveTx()).to.be.rejected; + expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.false; + }); }); it('Fungible', async () => { - const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible'); - await approveExpectFail(fungibleCollectionId, newFungibleTokenId, bob, charlie, 11); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + await helper.ft.mintTokens(alice, collectionId, alice.address, 10n); + const tokenId = await helper.ft.getLastTokenId(collectionId); + const approveTx = async () => helper.ft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 11n); + await expect(approveTx()).to.be.rejected; + }); }); it('ReFungible', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible'); - await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, bob, charlie, 101); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n}); + const approveTx = async () => helper.rft.approveToken(alice, collectionId, tokenId, {Substrate: bob.address}, 101n); + await expect(approveTx()).to.be.rejected; + }); }); }); @@ -321,41 +413,67 @@ let dave: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); - dave = privateKeyWrapper('//Dave'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor); }); - }); + }); it('NFT', async () => { - const collectionId = await createCollectionExpectSuccess(); - await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true}); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', charlie.address); - await transferFromExpectSuccess(collectionId, itemId, alice, charlie, dave, 1, 'NFT'); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - await transferFromExpectSuccess(collectionId, itemId, bob, dave, alice, 1, 'NFT'); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true}); + const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: charlie.address}); + + await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}); + const owner1 = await helper.nft.getTokenOwner(collectionId, tokenId); + expect(owner1.Substrate).to.be.equal(dave.address); + + await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address}); + await helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}); + const owner2 = await helper.nft.getTokenOwner(collectionId, tokenId); + expect(owner2.Substrate).to.be.equal(alice.address); + }); }); it('Fungible up to an approved amount', async () => { - const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}}); - await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true}); - const itemId = await createItemExpectSuccess(alice, collectionId, 'Fungible', charlie.address); - await transferFromExpectSuccess(collectionId, itemId, alice, charlie, dave, 1, 'Fungible'); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - await transferFromExpectSuccess(collectionId, itemId, bob, dave, alice, 1, 'Fungible'); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0); + await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true}); + await helper.ft.mintTokens(alice, collectionId, charlie.address, 10n); + const tokenId = await helper.ft.getLastTokenId(collectionId); + + const daveBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address}); + await helper.ft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n); + const daveBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address}); + expect(daveBalanceAfter - daveBalanceBefore).to.be.equal(BigInt(1)); + + await helper.collection.addAdmin(alice ,collectionId, {Substrate: bob.address}); + + const aliceBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: alice.address}); + await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n); + const aliceBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: alice.address}); + expect(aliceBalanceAfter - aliceBalanceBefore).to.be.equal(BigInt(1)); + }); }); it('ReFungible up to an approved amount', async function() { - await requirePallets(this, [Pallets.ReFungible]); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true}); + const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: charlie.address, pieces: 100n}); + + const daveBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address}); + await helper.rft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n); + const daveAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address}); + expect(daveAfter - daveBefore).to.be.equal(BigInt(1)); - const collectionId = await createCollectionExpectSuccess({mode:{type: 'ReFungible'}}); - await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: true}); - const itemId = await createItemExpectSuccess(alice, collectionId, 'ReFungible', charlie.address); - await transferFromExpectSuccess(collectionId, itemId, alice, charlie, dave, 1, 'ReFungible'); - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - await transferFromExpectSuccess(collectionId, itemId, bob, dave, alice, 1, 'ReFungible'); + await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address}); + + const aliceBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address}); + await helper.rft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n); + const aliceAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address}); + expect(aliceAfter - aliceBefore).to.be.equal(BigInt(1)); + }); }); }); @@ -366,13 +484,10 @@ let dave: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); - dave = privateKeyWrapper('//Dave'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor); }); - }); + }); it.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. Fungible', async () => { const collectionId = await createCollectionExpectSuccess({mode:{type: 'Fungible', decimalPoints: 0}}); @@ -417,19 +532,19 @@ let charlie: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); }); it('can be called by collection admin on non-owned item', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', alice.address); - - await addCollectionAdminExpectSuccess(alice, collectionId, bob.address); - await adminApproveFromExpectFail(collectionId, itemId, bob, alice.address, charlie.address); + await usingPlaygrounds(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.collection.addAdmin(alice, collectionId, {Substrate: bob.address}); + const approveTx = async () => helper.nft.approveToken(bob, collectionId, tokenId, {Substrate: charlie.address}); + await expect(approveTx()).to.be.rejected; + }); }); }); @@ -439,114 +554,139 @@ let charlie: IKeyringPair; before(async () => { - await usingApi(async (api, privateKeyWrapper) => { - alice = privateKeyWrapper('//Alice'); - bob = privateKeyWrapper('//Bob'); - charlie = privateKeyWrapper('//Charlie'); + await usingPlaygrounds(async (helper) => { + [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor); }); }); it('[nft] Approve for a collection that does not exist', async () => { - await usingApi(async (api: ApiPromise) => { - const nftCollectionCount = await getCreatedCollectionCount(api); - await approveExpectFail(nftCollectionCount + 1, 1, alice, bob); + await usingPlaygrounds(async (helper) => { + const collectionId = 1 << 32 - 1; + const approveTx = async () => helper.nft.approveToken(bob, collectionId, 1, {Substrate: charlie.address}); + await expect(approveTx()).to.be.rejected; }); }); it('[fungible] Approve for a collection that does not exist', async () => { - await usingApi(async (api: ApiPromise) => { - const fungibleCollectionCount = await getCreatedCollectionCount(api); - await approveExpectFail(fungibleCollectionCount + 1, 0, alice, bob); + await usingPlaygrounds(async (helper) => { + const collectionId = 1 << 32 - 1; + const approveTx = async () => helper.ft.approveToken(bob, collectionId, 1, {Substrate: charlie.address}); + await expect(approveTx()).to.be.rejected; }); }); it('[refungible] Approve for a collection that does not exist', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - await usingApi(async (api: ApiPromise) => { - const reFungibleCollectionCount = await getCreatedCollectionCount(api); - await approveExpectFail(reFungibleCollectionCount + 1, 1, alice, bob); + await usingPlaygrounds(async (helper) => { + const collectionId = 1 << 32 - 1; + const approveTx = async () => helper.rft.approveToken(bob, collectionId, 1, {Substrate: charlie.address}); + await expect(approveTx()).to.be.rejected; }); }); it('[nft] Approve for a collection that was destroyed', async () => { - const nftCollectionId = await createCollectionExpectSuccess(); - await destroyCollectionExpectSuccess(nftCollectionId); - await approveExpectFail(nftCollectionId, 1, alice, bob); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.nft.burn(alice, collectionId); + const approveTx = async () => helper.nft.approveToken(alice, collectionId, 1, {Substrate: bob.address}); + await expect(approveTx()).to.be.rejected; + }); }); - it('Approve for a collection that was destroyed', async () => { - const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - await destroyCollectionExpectSuccess(fungibleCollectionId); - await approveExpectFail(fungibleCollectionId, 0, alice, bob); + it('[fungible] Approve for a collection that was destroyed', async () => { + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.ft.burn(alice, collectionId); + const approveTx = async () => helper.ft.approveToken(alice, collectionId, 1, {Substrate: bob.address}); + await expect(approveTx()).to.be.rejected; + }); }); it('[refungible] Approve for a collection that was destroyed', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - const reFungibleCollectionId = - await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - await destroyCollectionExpectSuccess(reFungibleCollectionId); - await approveExpectFail(reFungibleCollectionId, 1, alice, bob); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.rft.burn(alice, collectionId); + const approveTx = async () => helper.rft.approveToken(alice, collectionId, 1, {Substrate: bob.address}); + await expect(approveTx()).to.be.rejected; + }); }); it('[nft] Approve transfer of a token that does not exist', async () => { - const nftCollectionId = await createCollectionExpectSuccess(); - await approveExpectFail(nftCollectionId, 2, alice, bob); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const approveTx = async () => helper.nft.approveToken(alice, collectionId, 2, {Substrate: bob.address}); + await expect(approveTx()).to.be.rejected; + }); }); it('[refungible] Approve transfer of a token that does not exist', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - const reFungibleCollectionId = - await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - await approveExpectFail(reFungibleCollectionId, 2, alice, bob); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const approveTx = async () => helper.rft.approveToken(alice, collectionId, 2, {Substrate: bob.address}); + await expect(approveTx()).to.be.rejected; + }); }); it('[nft] Approve using the address that does not own the approved token', async () => { - const nftCollectionId = await createCollectionExpectSuccess(); - const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'NFT'); - await approveExpectFail(nftCollectionId, newNftTokenId, bob, alice); + await usingPlaygrounds(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}); + const approveTx = async () => helper.nft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}); + await expect(approveTx()).to.be.rejected; + }); }); it('[fungible] Approve using the address that does not own the approved token', async () => { - const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - const newFungibleTokenId = await createItemExpectSuccess(alice, fungibleCollectionId, 'Fungible'); - await approveExpectFail(fungibleCollectionId, newFungibleTokenId, bob, alice); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.ft.mintTokens(alice, collectionId, alice.address, 10n); + const tokenId = await helper.ft.getLastTokenId(collectionId); + const approveTx = async () => helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}); + await expect(approveTx()).to.be.rejected; + }); }); it('[refungible] Approve using the address that does not own the approved token', async function() { - await requirePallets(this, [Pallets.ReFungible]); - - const reFungibleCollectionId = - await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - const newReFungibleTokenId = await createItemExpectSuccess(alice, reFungibleCollectionId, 'ReFungible'); - await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, bob, alice); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n}); + const approveTx = async () => helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}); + await expect(approveTx()).to.be.rejected; + }); }); it('should fail if approved more ReFungibles than owned', async function() { - await requirePallets(this, [Pallets.ReFungible]); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n}); + await helper.rft.transferToken(alice, collectionId, tokenId, {Substrate: bob.address}, 100n); + await helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, 100n); - const nftCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}}); - const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'ReFungible'); - await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 100, 'ReFungible'); - await approveExpectSuccess(nftCollectionId, newNftTokenId, bob, alice.address, 100); - await approveExpectFail(nftCollectionId, newNftTokenId, bob, alice, 101); + const approveTx = async () => helper.rft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, 101n); + await expect(approveTx()).to.be.rejected; + }); }); it('should fail if approved more Fungibles than owned', async () => { - const nftCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); - const newNftTokenId = await createItemExpectSuccess(alice, nftCollectionId, 'Fungible'); - await transferExpectSuccess(nftCollectionId, newNftTokenId, alice, bob, 10, 'Fungible'); - await approveExpectSuccess(nftCollectionId, newNftTokenId, bob, alice.address, 10); - await approveExpectFail(nftCollectionId, newNftTokenId, bob, alice, 11); + await usingPlaygrounds(async (helper) => { + const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}); + await helper.ft.mintTokens(alice, collectionId, alice.address, 10n); + const tokenId = await helper.ft.getLastTokenId(collectionId); + + await helper.ft.transferToken(alice, collectionId, tokenId, {Substrate: bob.address}, 10n); + await helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, 10n); + const approveTx = async () => helper.ft.approveToken(bob, collectionId, tokenId, {Substrate: alice.address}, 11n); + await expect(approveTx()).to.be.rejected; + }); }); it('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async () => { - const collectionId = await createCollectionExpectSuccess(); - const itemId = await createItemExpectSuccess(alice, collectionId, 'NFT', bob.address); - await setCollectionLimitsExpectSuccess(alice, collectionId, {ownerCanTransfer: false}); + await usingPlaygrounds(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: bob.address}); + await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: false}); - await approveExpectFail(collectionId, itemId, alice, charlie); + const approveTx = async () => helper.nft.approveToken(alice, collectionId, tokenId, {Substrate: charlie.address}); + await expect(approveTx()).to.be.rejected; + }); }); }); --- a/tests/src/util/playgrounds/unique.ts +++ b/tests/src/util/playgrounds/unique.ts @@ -255,9 +255,9 @@ return network; } - static async createConnection(wsEndpoint: string, listeners?: IApiListeners, network?: TUniqueNetworks | null): Promise<{ - api: ApiPromise; - network: TUniqueNetworks; + static async createConnection(wsEndpoint: string, listeners?: IApiListeners, network?: TUniqueNetworks | null): Promise<{ + api: ApiPromise; + network: TUniqueNetworks; }> { if(typeof network === 'undefined' || network === null) network = 'opal'; const supportedRPC = { @@ -444,7 +444,7 @@ if(this.api === null) throw Error('API not initialized'); return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase()); } - + fetchMissingPalletNames(requiredPallets: string[]): string[] { const palletNames = this.fetchAllPalletNames(); return requiredPallets.filter(p => !palletNames.includes(p)); @@ -477,7 +477,7 @@ /** * Get the number of created collections. - * + * * @returns number of created collections */ async getTotalCount(): Promise { @@ -485,10 +485,10 @@ } /** - * Get information about the collection with additional data, - * including the number of tokens it contains, its administrators, + * Get information about the collection with additional data, + * including the number of tokens it contains, its administrators, * the normalized address of the collection's owner, and decoded name and description. - * + * * @param collectionId ID of collection * @example await getData(2) * @returns collection information object @@ -515,8 +515,8 @@ collectionData[key] = this.helper.util.vec2str(humanCollection[key]); } - collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode)) - ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId) + collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode)) + ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId) : 0; collectionData.admins = await this.getAdmins(collectionId); @@ -525,7 +525,7 @@ /** * Get the addresses of the collection's administrators, optionally normalized. - * + * * @param collectionId ID of collection * @param normalize whether to normalize the addresses to the default ss58 format * @example await getAdmins(1) @@ -539,7 +539,7 @@ return address.Substrate ? {Substrate: this.helper.address.normalizeSubstrate(address.Substrate)} : address; - }) + }) : admins; } @@ -557,13 +557,13 @@ return address.Substrate ? {Substrate: this.helper.address.normalizeSubstrate(address.Substrate)} : address; - }) + }) : allowListed; } /** * Get the effective limits of the collection instead of null for default values - * + * * @param collectionId ID of collection * @example await getEffectiveLimits(2) * @returns object of collection limits @@ -574,7 +574,7 @@ /** * Burns the collection if the signer has sufficient permissions and collection is empty. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @example await helper.collection.burn(aliceKeyring, 3); @@ -592,7 +592,7 @@ /** * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param sponsorAddress Sponsor substrate address @@ -611,7 +611,7 @@ /** * Confirms consent to sponsor the collection on behalf of the signer. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @example confirmSponsorship(aliceKeyring, 10) @@ -629,7 +629,7 @@ /** * Removes the sponsor of a collection, regardless if it consented or not. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @example removeSponsor(aliceKeyring, 10) @@ -647,7 +647,7 @@ /** * Sets the limits of the collection. At least one limit must be specified for a correct call. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param limits collection limits object @@ -674,7 +674,7 @@ /** * Changes the owner of the collection to the new Substrate address. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param ownerAddress substrate address of new owner @@ -692,8 +692,8 @@ } /** - * Adds a collection administrator. - * + * Adds a collection administrator. + * * @param signer keyring of signer * @param collectionId ID of collection * @param adminAddressObj Administrator address (substrate or ethereum) @@ -712,7 +712,7 @@ /** * Removes a collection administrator. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param adminAddressObj Administrator address (substrate or ethereum) @@ -730,7 +730,7 @@ } /** - * Adds an address to allow list + * Adds an address to allow list * @param signer keyring of signer * @param collectionId ID of collection * @param addressObj address to add to the allow list @@ -747,8 +747,8 @@ } /** - * Removes an address from allow list - * + * Removes an address from allow list + * * @param signer keyring of signer * @param collectionId ID of collection * @param addressObj address to remove from the allow list @@ -766,7 +766,7 @@ /** * Sets onchain permissions for selected collection. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param permissions collection permissions object @@ -785,7 +785,7 @@ /** * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param permissions nesting permissions object @@ -798,7 +798,7 @@ /** * Disables nesting for selected collection. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @example disableNesting(aliceKeyring, 10); @@ -810,7 +810,7 @@ /** * Sets onchain properties to the collection. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param properties array of property objects @@ -829,7 +829,7 @@ /** * Deletes onchain properties from the collection. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param propertyKeys array of property keys to delete @@ -848,7 +848,7 @@ /** * Changes the owner of the token. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token @@ -868,9 +868,9 @@ } /** - * - * Change ownership of a token(s) on behalf of the owner. - * + * + * Change ownership of a token(s) on behalf of the owner. + * * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token @@ -890,9 +890,9 @@ } /** - * + * * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token @@ -916,7 +916,7 @@ /** * Destroys a concrete instance of NFT on behalf of the owner - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param fromAddressObj address on behalf of which the token will be burnt @@ -937,7 +937,7 @@ /** * Set, change, or remove approved address to transfer the ownership of the NFT. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token @@ -947,7 +947,7 @@ */ async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) { const approveResult = await this.helper.executeExtrinsic( - signer, + signer, 'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount], true, // `Unable to approve token for ${label}`, ); @@ -957,7 +957,7 @@ /** * Get the amount of token pieces approved to transfer or burn. Normally 0. - * + * * @param collectionId ID of collection * @param tokenId ID of token * @param toAccountObj address which is approved to use token pieces @@ -971,7 +971,7 @@ /** * Get the last created token ID in a collection - * + * * @param collectionId ID of collection * @example getLastTokenId(10); * @returns id of the last created token @@ -982,7 +982,7 @@ /** * Check if token exists - * + * * @param collectionId ID of collection * @param tokenId ID of token * @example isTokenExists(10, 20); @@ -996,7 +996,7 @@ class NFTnRFT extends CollectionGroup { /** * Get tokens owned by account - * + * * @param collectionId ID of collection * @param addressObj tokens owner * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."}) @@ -1008,13 +1008,13 @@ /** * Get token data - * + * * @param collectionId ID of collection * @param tokenId ID of token * @param propertyKeys optionally filter the token properties to only these keys * @param blockHashAt optionally query the data at some block with this hash * @example getToken(10, 5); - * @returns human readable token data + * @returns human readable token data */ async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{ properties: IProperty[]; @@ -1045,7 +1045,7 @@ /** * Set permissions to change token properties - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param permissions permissions to change a property by the collection owner or admin @@ -1066,7 +1066,7 @@ /** * Set token properties - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token @@ -1089,7 +1089,7 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token - * @param propertyKeys property keys to be deleted + * @param propertyKeys property keys to be deleted * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"]) * @returns ```true``` if extrinsic success, otherwise ```false``` */ @@ -1105,9 +1105,9 @@ /** * Mint new collection - * + * * @param signer keyring of signer - * @param collectionOptions basic collection options and properties + * @param collectionOptions basic collection options and properties * @param mode NFT or RFT type of a collection * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT") * @returns object of the created collection @@ -1189,7 +1189,7 @@ /** * Changes the owner of the token. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token @@ -1202,9 +1202,9 @@ } /** - * - * Change ownership of a NFT on behalf of the owner. - * + * + * Change ownership of a NFT on behalf of the owner. + * * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token @@ -1221,7 +1221,7 @@ * Recursively find the address that owns the token * @param collectionId ID of collection * @param tokenId ID of token - * @param blockHashAt + * @param blockHashAt * @example getTokenTopmostOwner(10, 5); * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."} */ @@ -1246,7 +1246,7 @@ * @param tokenId ID of token * @param blockHashAt optionally query the data at the block with this hash * @example getTokenChildren(10, 5); - * @returns tokens whose depth of nesting is <= 5 + * @returns tokens whose depth of nesting is <= 5 */ async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise { let children; @@ -1283,7 +1283,7 @@ * @param signer keyring of signer * @param tokenObj token to unnest * @param rootTokenObj parent of a token - * @param toAddressObj address of a new token owner + * @param toAddressObj address of a new token owner * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."}); * @returns ```true``` if extrinsic success, otherwise ```false``` */ @@ -1300,7 +1300,7 @@ * Mint new collection * @param signer keyring of signer * @param collectionOptions Collection options - * @example + * @example * mintCollection(aliceKeyring, { * name: 'New', * description: 'New collection', @@ -1339,7 +1339,7 @@ * @param signer keyring of signer * @param collectionId ID of collection * @param tokens array of tokens with owner and properties - * @example + * @example * mintMultipleTokens(aliceKeyring, 10, [{ * owner: {Substrate: "5DyN4Y92vZCjv38fg..."}, * properties: [{key: "gender", value: "male"},{key: "age", value: "45"}], @@ -1390,23 +1390,11 @@ ); const collection = this.getCollectionObject(collectionId); return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId)); - } - - /** - * Destroys a concrete instance of NFT. - * @param signer keyring of signer - * @param collectionId ID of collection - * @param tokenId ID of token - * @example burnToken(aliceKeyring, 10, 5); - * @returns ```true``` and burnt token number is extrinsic success. Otherwise ```false``` and ```null``` - */ - async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number): Promise<{ success: boolean; token: number | null; }> { - return await super.burnToken(signer, collectionId, tokenId, 1n); } /** * Set, change, or remove approved address to transfer the ownership of the NFT. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token @@ -1443,7 +1431,7 @@ } /** - * Get top 10 token owners with the largest number of pieces + * Get top 10 token owners with the largest number of pieces * @param collectionId ID of collection * @param tokenId ID of token * @example getTokenTop10Owners(10, 5); @@ -1480,7 +1468,7 @@ } /** - * Change ownership of some pieces of RFT on behalf of the owner. + * Change ownership of some pieces of RFT on behalf of the owner. * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token @@ -1584,7 +1572,7 @@ /** * Set, change, or remove approved address to transfer the ownership of the RFT. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param tokenId ID of token @@ -1645,7 +1633,7 @@ * Mint new fungible collection * @param signer keyring of signer * @param collectionOptions Collection options - * @param decimalPoints number of token decimals + * @param decimalPoints number of token decimals * @example * mintCollection(aliceKeyring, { * name: 'New', @@ -1676,7 +1664,7 @@ * @param owner address owner of new tokens * @param amount amount of tokens to be meanted * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n); - * @returns ```true``` if extrinsic success, otherwise ```false``` + * @returns ```true``` if extrinsic success, otherwise ```false``` */ async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise { const creationResult = await this.helper.executeExtrinsic( @@ -1697,7 +1685,7 @@ * @param collectionId ID of collection * @param owner tokens owner * @param tokens array of tokens with properties and pieces - * @returns ```true``` if extrinsic success, otherwise ```false``` + * @returns ```true``` if extrinsic success, otherwise ```false``` */ async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: {value: bigint}[], owner: ICrossAccountId): Promise { const rawTokens = []; @@ -1714,7 +1702,7 @@ } /** - * Get the top 10 owners with the largest balance for the Fungible collection + * Get the top 10 owners with the largest balance for the Fungible collection * @param collectionId ID of collection * @example getTop10Owners(10); * @returns array of ```ICrossAccountId``` @@ -1741,7 +1729,7 @@ * @param toAddressObj address recipient * @param amount amount of tokens to be sent * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n); - * @returns ```true``` if extrinsic success, otherwise ```false``` + * @returns ```true``` if extrinsic success, otherwise ```false``` */ async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) { return await super.transferToken(signer, collectionId, 0, toAddressObj, amount); @@ -1755,7 +1743,7 @@ * @param toAddressObj address where token to be sent * @param amount number of tokens to be sent * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n); - * @returns ```true``` if extrinsic success, otherwise ```false``` + * @returns ```true``` if extrinsic success, otherwise ```false``` */ async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) { return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount); @@ -1767,7 +1755,7 @@ * @param collectionId ID of collection * @param amount amount of tokens to be destroyed * @example burnTokens(aliceKeyring, 10, 1000n); - * @returns ```true``` if extrinsic success, otherwise ```false``` + * @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; @@ -1780,7 +1768,7 @@ * @param fromAddressObj address on behalf of which tokens will be burnt * @param amount amount of tokens to be burnt * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n); - * @returns ```true``` if extrinsic success, otherwise ```false``` + * @returns ```true``` if extrinsic success, otherwise ```false``` */ async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise { return await super.burnTokenFrom(signer, collectionId, fromAddressObj, 0, amount); @@ -1788,8 +1776,8 @@ /** * Get total collection supply - * @param collectionId - * @returns + * @param collectionId + * @returns */ async getTotalPieces(collectionId: number): Promise { return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt(); @@ -1797,13 +1785,13 @@ /** * Set, change, or remove approved address to transfer tokens. - * + * * @param signer keyring of signer * @param collectionId ID of collection * @param toAddressObj address to be approved * @param amount amount of tokens to be approved * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n) - * @returns ```true``` if extrinsic success, otherwise ```false``` + * @returns ```true``` if extrinsic success, otherwise ```false``` */ async approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) { return super.approveToken(signer, collectionId, 0, toAddressObj, amount); @@ -1901,7 +1889,7 @@ /** * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved * @param address substrate address - * @returns + * @returns */ async getSubstrateFull(address: TSubstrateAccount): Promise { const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data; @@ -2022,7 +2010,7 @@ async unstake(signer: TSigner, label?: string): Promise { if(typeof label === 'undefined') label = `${signer.address}`; const unstakeResult = await this.helper.executeExtrinsic( - signer, 'api.tx.appPromotion.unstake', + signer, 'api.tx.appPromotion.unstake', [], true, ); // TODO extract block number fron events @@ -2041,7 +2029,7 @@ async getPendingUnstake(address: ICrossAccountId): Promise { return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt(); } - + async getPendingUnstakePerBlock(address: ICrossAccountId): Promise { return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address])).map(([block, amount]: any[]) => [block.toBigInt(), amount.toBigInt()]); } @@ -2067,7 +2055,7 @@ this.rft = new RFTGroup(this); this.ft = new FTGroup(this); this.staking = new StakingGroup(this); - } + } }