From 147c8928fe2f407a17ea1dccb5e3451745875ef4 Mon Sep 17 00:00:00 2001 From: str-mv <51784859+str-mv@users.noreply.github.com> Date: Thu, 14 Jan 2021 14:11:45 +0000 Subject: [PATCH] Merge pull request #61 from usetech-llc/feature/NFTPAR-236_burn_item Feature/nftpar 236 burn item --- --- /dev/null +++ b/tests/src/burnItem.test.ts @@ -0,0 +1,237 @@ +import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api'; +import { Keyring } from "@polkadot/api"; +import { IKeyringPair } from "@polkadot/types/types"; +import { + createCollectionExpectSuccess, + createItemExpectSuccess, + getGenericResult, + destroyCollectionExpectSuccess +} from './util/helpers'; +import { nullPublicKey } from "./accounts"; + +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +chai.use(chaiAsPromised); +const expect = chai.expect; + +let alice: IKeyringPair; +let bob: IKeyringPair; + +describe('integration test: ext. burnItem():', () => { + before(async () => { + await usingApi(async (api) => { + const keyring = new Keyring({ type: 'sr25519' }); + alice = keyring.addFromUri(`//Alice`); + bob = keyring.addFromUri(`//Bob`); + }); + }); + + it('Burn item in NFT collection', async () => { + const createMode = 'NFT'; + const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}}); + const tokenId = await createItemExpectSuccess(alice, collectionId, createMode); + + await usingApi(async (api) => { + const tx = api.tx.nft.burnItem(collectionId, tokenId, 0); + const events = await submitTransactionAsync(alice, tx); + const result = getGenericResult(events); + + // Get the item + const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON(); + + // What to expect + expect(result.success).to.be.true; + expect(item).to.be.not.null; + expect(item.Owner).to.be.equal(nullPublicKey); + }); + + }); + it('Burn item in Fungible collection', async () => { + const createMode = 'Fungible'; + const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0 }}); + await createItemExpectSuccess(alice, collectionId, createMode); // Helper creates 10 fungible tokens + const tokenId = 0; // ignored + + await usingApi(async (api) => { + // Destroy 1 of 10 + const tx = api.tx.nft.burnItem(collectionId, tokenId, 1); + const events = await submitTransactionAsync(alice, tx); + const result = getGenericResult(events); + + // Get alice balance + const balance: any = (await api.query.nft.fungibleItemList(collectionId, alice.address)).toJSON(); + + // What to expect + expect(result.success).to.be.true; + expect(balance).to.be.not.null; + expect(balance.Value).to.be.equal(9); + }); + + }); + it('Burn item in ReFungible collection', async () => { + const createMode = 'ReFungible'; + const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 2 }}); + const tokenId = await createItemExpectSuccess(alice, collectionId, createMode); + + await usingApi(async (api) => { + const tx = api.tx.nft.burnItem(collectionId, tokenId, 1); + const events = await submitTransactionAsync(alice, tx); + const result = getGenericResult(events); + + // Get alice balance + const balance: any = (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON(); + + // What to expect + expect(result.success).to.be.true; + expect(balance).to.be.not.null; + expect(balance.Owner.length).to.be.equal(0); + }); + + }); + + it('Burn owned portion of item in ReFungible collection', async () => { + const createMode = 'ReFungible'; + const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 2 }}); + const tokenId = await createItemExpectSuccess(alice, collectionId, createMode); + + await usingApi(async (api) => { + // Transfer 1/100 of the token to Bob + const transfertx = api.tx.nft.transfer(bob.address, collectionId, tokenId, 1); + const events1 = await submitTransactionAsync(alice, transfertx); + const result1 = getGenericResult(events1); + + // Get balances + const balanceBefore: any = (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON(); + + // Bob burns his portion + const tx = api.tx.nft.burnItem(collectionId, tokenId, 0); + const events2 = await submitTransactionAsync(bob, tx); + const result2 = getGenericResult(events2); + + // Get balances + const balance: any = (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON(); + // console.log(balance); + + // What to expect before burning + expect(result1.success).to.be.true; + expect(balanceBefore).to.be.not.null; + expect(balanceBefore.Owner.length).to.be.equal(2); + expect(balanceBefore.Owner[0].Owner).to.be.equal(alice.address); + expect(balanceBefore.Owner[0].Fraction).to.be.equal(99); + expect(balanceBefore.Owner[1].Owner).to.be.equal(bob.address); + expect(balanceBefore.Owner[1].Fraction).to.be.equal(1); + + // What to expect after burning + expect(result2.success).to.be.true; + expect(balance).to.be.not.null; + expect(balance.Owner.length).to.be.equal(1); + expect(balance.Owner[0].Fraction).to.be.equal(99); + expect(balance.Owner[0].Owner).to.be.equal(alice.address); + }); + + }); + +}); + +describe('Negative integration test: ext. burnItem():', () => { + before(async () => { + await usingApi(async (api) => { + const keyring = new Keyring({ type: 'sr25519' }); + alice = keyring.addFromUri(`//Alice`); + bob = keyring.addFromUri(`//Bob`); + }); + }); + + it('Burn a token in a destroyed collection', async () => { + const createMode = 'NFT'; + const collectionId = await createCollectionExpectSuccess({mode: {type: createMode }}); + const tokenId = await createItemExpectSuccess(alice, collectionId, createMode); + await destroyCollectionExpectSuccess(collectionId); + + await usingApi(async (api) => { + const tx = api.tx.nft.burnItem(collectionId, tokenId, 0); + const badTransaction = async function () { + await submitTransactionExpectFailAsync(alice, tx); + }; + await expect(badTransaction()).to.be.rejected; + }); + + }); + + it('Burn a token that was never created', async () => { + const createMode = 'NFT'; + const collectionId = await createCollectionExpectSuccess({mode: {type: createMode }}); + const tokenId = 10; + + await usingApi(async (api) => { + const tx = api.tx.nft.burnItem(collectionId, tokenId, 0); + const badTransaction = async function () { + await submitTransactionExpectFailAsync(alice, tx); + }; + await expect(badTransaction()).to.be.rejected; + }); + + }); + + it('Burn a token using the address that does not own it', async () => { + const createMode = 'NFT'; + const collectionId = await createCollectionExpectSuccess({mode: {type: createMode }}); + const tokenId = await createItemExpectSuccess(alice, collectionId, createMode); + + await usingApi(async (api) => { + const tx = api.tx.nft.burnItem(collectionId, tokenId, 0); + const badTransaction = async function () { + await submitTransactionExpectFailAsync(bob, tx); + }; + await expect(badTransaction()).to.be.rejected; + }); + + }); + + it('Transfer a burned a token', async () => { + const createMode = 'NFT'; + const collectionId = await createCollectionExpectSuccess({mode: {type: createMode }}); + const tokenId = await createItemExpectSuccess(alice, collectionId, createMode); + + await usingApi(async (api) => { + + const burntx = api.tx.nft.burnItem(collectionId, tokenId, 0); + const events1 = await submitTransactionAsync(alice, burntx); + const result1 = getGenericResult(events1); + expect(result1.success).to.be.true; + + const tx = api.tx.nft.transfer(bob.address, collectionId, tokenId, 0); + const badTransaction = async function () { + await submitTransactionExpectFailAsync(alice, tx); + }; + await expect(badTransaction()).to.be.rejected; + }); + + }); + + it('Burn more than owned in Fungible collection', async () => { + const createMode = 'Fungible'; + const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0 }}); + // Helper creates 10 fungible tokens + await createItemExpectSuccess(alice, collectionId, createMode); + const tokenId = 0; // ignored + + await usingApi(async (api) => { + // Destroy 11 of 10 + const tx = api.tx.nft.burnItem(collectionId, tokenId, 11); + const badTransaction = async function () { + await submitTransactionExpectFailAsync(alice, tx); + }; + await expect(badTransaction()).to.be.rejected; + + // Get alice balance + const balance: any = (await api.query.nft.fungibleItemList(collectionId, alice.address)).toJSON(); + + // What to expect + expect(balance).to.be.not.null; + expect(balance.Value).to.be.equal(10); + }); + + }); + +}); --- a/tests/src/confirmSponsorship.test.ts +++ b/tests/src/confirmSponsorship.test.ts @@ -89,7 +89,7 @@ }); it('Fungible: Transfer fees are paid by the sponsor after confirmation', async () => { - const collectionId = await createCollectionExpectSuccess({mode: 'Fungible'}); + const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0 }}); await setCollectionSponsorExpectSuccess(collectionId, bob.address); await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); @@ -115,7 +115,7 @@ }); it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async () => { - const collectionId = await createCollectionExpectSuccess({mode: 'ReFungible'}); + const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0 }}); await setCollectionSponsorExpectSuccess(collectionId, bob.address); await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); @@ -210,7 +210,7 @@ }); it('Fungible: Sponsoring is rate limited', async () => { - const collectionId = await createCollectionExpectSuccess({mode: 'Fungible'}); + const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0 }}); await setCollectionSponsorExpectSuccess(collectionId, bob.address); await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); @@ -247,7 +247,7 @@ }); it('ReFungible: Sponsoring is rate limited', async () => { - const collectionId = await createCollectionExpectSuccess({mode: 'ReFungible'}); + const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0 }}); await setCollectionSponsorExpectSuccess(collectionId, bob.address); await confirmSponsorshipExpectSuccess(collectionId, '//Bob'); --- a/tests/src/createCollection.test.ts +++ b/tests/src/createCollection.test.ts @@ -6,14 +6,14 @@ import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; import { default as usingApi } from "./substrate/substrate-api"; -import { createCollectionExpectSuccess, createCollectionExpectFailure, CollectionMode } from "./util/helpers"; +import { createCollectionExpectSuccess, createCollectionExpectFailure } from "./util/helpers"; chai.use(chaiAsPromised); const expect = chai.expect; describe('integration test: ext. createCollection():', () => { it('Create new NFT collection', async () => { - await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: 'NFT'}); + await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}}); }); it('Create new NFT collection whith collection_name of maximum length (64 bytes)', async () => { await createCollectionExpectSuccess({name: 'A'.repeat(64)}); @@ -25,10 +25,10 @@ await createCollectionExpectSuccess({tokenPrefix: 'A'.repeat(16)}); }); it('Create new Fungible collection', async () => { - await createCollectionExpectSuccess({mode: 'Fungible'}); + await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); }); it('Create new ReFungible collection', async () => { - await createCollectionExpectSuccess({mode: 'ReFungible'}); + await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}}); }); }); @@ -38,7 +38,7 @@ const AcollectionCount = parseInt((await api.query.nft.collectionCount()).toString()); const badTransaction = async function () { - await createCollectionExpectSuccess({mode: 'BadMode' as CollectionMode}); + await createCollectionExpectSuccess({mode: {type: 'Invalid'}}); }; expect(badTransaction()).to.be.rejected; --- a/tests/src/createItem.test.ts +++ b/tests/src/createItem.test.ts @@ -18,17 +18,17 @@ it('Create new item in NFT collection', async () => { const createMode = 'NFT'; - const newCollectionID = await createCollectionExpectSuccess({mode: createMode}); + const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}}); await createItemExpectSuccess(alice, newCollectionID, createMode); }); it('Create new item in Fungible collection', async () => { const createMode = 'Fungible'; - const newCollectionID = await createCollectionExpectSuccess({mode: createMode}); + const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}}); await createItemExpectSuccess(alice, newCollectionID, createMode); }); it('Create new item in ReFungible collection', async () => { const createMode = 'ReFungible'; - const newCollectionID = await createCollectionExpectSuccess({mode: createMode}); + const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}}); await createItemExpectSuccess(alice, newCollectionID, createMode); }); }); --- a/tests/src/destroyCollection.test.ts +++ b/tests/src/destroyCollection.test.ts @@ -14,11 +14,11 @@ await destroyCollectionExpectSuccess(collectionId); }); it('Fungible collection can be destroyed', async () => { - const collectionId = await createCollectionExpectSuccess({ mode: 'Fungible' }); + const collectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); await destroyCollectionExpectSuccess(collectionId); }); it('ReFungible collection can be destroyed', async () => { - const collectionId = await createCollectionExpectSuccess({ mode: 'ReFungible' }); + const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}}); await destroyCollectionExpectSuccess(collectionId); }); }); --- a/tests/src/setCollectionLimits.test.ts +++ b/tests/src/setCollectionLimits.test.ts @@ -32,7 +32,7 @@ }); it('choose or create collection for testing', async () => { await usingApi(async () => { - collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: 'NFT'}); + collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}}); }); }); }); --- a/tests/src/setCollectionSponsor.test.ts +++ b/tests/src/setCollectionSponsor.test.ts @@ -30,11 +30,11 @@ await setCollectionSponsorExpectSuccess(collectionId, bob.address); }); it('Set Fungible collection sponsor', async () => { - const collectionId = await createCollectionExpectSuccess({ mode: 'Fungible' }); + const collectionId = await createCollectionExpectSuccess({ mode: {type: 'Fungible', decimalPoints: 0} }); await setCollectionSponsorExpectSuccess(collectionId, bob.address); }); it('Set ReFungible collection sponsor', async () => { - const collectionId = await createCollectionExpectSuccess({ mode: 'ReFungible' }); + const collectionId = await createCollectionExpectSuccess({ mode: {type: 'ReFungible', decimalPoints: 0} }); await setCollectionSponsorExpectSuccess(collectionId, bob.address); }); --- a/tests/src/setSchemaVersion.test.ts +++ b/tests/src/setSchemaVersion.test.ts @@ -35,7 +35,7 @@ }); it('choose or create collection for testing', async () => { await usingApi(async () => { - collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: 'NFT'}); + collectionIdForTesting = await createCollectionExpectSuccess({name: 'A', description: 'B', tokenPrefix: 'C', mode: {type: 'NFT'}}); }); }); }); --- a/tests/src/util/helpers.ts +++ b/tests/src/util/helpers.ts @@ -88,7 +88,26 @@ return result; } -export type CollectionMode = 'NFT' | 'Fungible' | 'ReFungible'; +interface Invalid { + type: 'Invalid' +} + +interface Nft { + type: 'NFT' +} + +interface Fungible { + type: 'Fungible', + decimalPoints: number +} + +interface ReFungible { + type: 'ReFungible', + decimalPoints: number +} + +type CollectionMode = Nft | Fungible | ReFungible | Invalid; + export type CreateCollectionParams = { mode: CollectionMode, name: string, @@ -99,7 +118,7 @@ const defaultCreateCollectionParams: CreateCollectionParams = { name: 'name', description: 'description', - mode: 'NFT', + mode: { type: "NFT" }, tokenPrefix: 'prefix' } @@ -113,7 +132,22 @@ // Run the CreateCollection transaction const alicePrivateKey = privateKey('//Alice'); - const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), mode); + + let modeprm = {}; + if (mode.type == 'NFT') { + modeprm = {nft: null}; + } + else if (mode.type == 'Fungible') { + modeprm = {fungible: mode.decimalPoints}; + } + else if (mode.type == 'ReFungible') { + modeprm = {refungible: mode.decimalPoints}; + } + else if (mode.type == 'Invalid') { + modeprm = {invalid: null}; + } + + const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm); const events = await submitTransactionAsync(alicePrivateKey, tx); const result = getCreateCollectionResult(events); -- gitstuff