From 07025d803c3e3aebc6cc6d10f45ec3490405be72 Mon Sep 17 00:00:00 2001 From: Greg Zaitsev Date: Mon, 18 Jan 2021 11:15:06 +0000 Subject: [PATCH] Merge pull request #63 from usetech-llc/feature/NFTPAR-235-258 Feature/nftpar 235 258 --- --- a/tests/package.json +++ b/tests/package.json @@ -22,7 +22,10 @@ "testSetCollectionLimits": "mocha --timeout 9999999 -r ts-node/register ./**/setCollectionLimits.test.ts", "testRemoveCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/removeCollectionAdmin.test.ts", "testConnection": "mocha --timeout 9999999 -r ts-node/register ./**/connection.test.ts", - "testCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts" + "testCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts", + "testApprove": "mocha --timeout 9999999 -r ts-node/register ./**/approve.test.ts", + "testTransferFrom": "mocha --timeout 9999999 -r ts-node/register ./**/transferFrom.test.ts", + "testCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts" }, "author": "", "license": "Apache 2.0", --- /dev/null +++ b/tests/src/approve.test.ts @@ -0,0 +1,140 @@ +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// +import { ApiPromise } from '@polkadot/api'; +import BN from 'bn.js'; +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import privateKey from './substrate/privateKey'; +import { default as usingApi } from './substrate/substrate-api'; +import { + approveExpectFail, + approveExpectSuccess, + createCollectionExpectSuccess, + createItemExpectSuccess, + destroyCollectionExpectSuccess, +} from './util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +describe('Integration Test approve(spender, collection_id, item_id, amount):', () => { + it('Execute the extrinsic and check approvedList', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + const nftCollectionId = await createCollectionExpectSuccess(); + // nft + const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT'); + await approveExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob); + // fungible + const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); + const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible'); + await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob); + // reFungible + const reFungibleCollectionId = + await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}}); + const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible'); + await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob); + }); + }); + + it('Remove approval by using 0 amount', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + const nftCollectionId = await createCollectionExpectSuccess(); + // nft + const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT'); + await approveExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob, 1); + await approveExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob, 0); + // fungible + const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); + const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible'); + await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1); + await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 0); + // reFungible + const reFungibleCollectionId = + await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}}); + const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible'); + await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 1); + await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 0); + }); + }); +}); + +describe('Negative Integration Test approve(spender, collection_id, item_id, amount):', () => { + it('Approve for a collection that does not exist', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + // nft + const nftCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number; + await approveExpectFail(nftCollectionCount + 1, 1, Alice, Bob); + // fungible + const fungibleCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number; + await approveExpectFail(fungibleCollectionCount + 1, 1, Alice, Bob); + // reFungible + const reFungibleCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number; + await approveExpectFail(reFungibleCollectionCount + 1, 1, Alice, Bob); + }); + }); + + it('Approve for a collection that was destroyed', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + // nft + const nftCollectionId = await createCollectionExpectSuccess(); + await destroyCollectionExpectSuccess(nftCollectionId); + await approveExpectFail(nftCollectionId, 1, Alice, Bob); + // fungible + const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); + await destroyCollectionExpectSuccess(fungibleCollectionId); + await approveExpectFail(fungibleCollectionId, 1, Alice, Bob); + // reFungible + const reFungibleCollectionId = + await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}}); + await destroyCollectionExpectSuccess(reFungibleCollectionId); + await approveExpectFail(reFungibleCollectionId, 1, Alice, Bob); + }); + }); + + it('Approve transfer of a token that does not exist', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + // nft + const nftCollectionId = await createCollectionExpectSuccess(); + await approveExpectFail(nftCollectionId, 2, Alice, Bob); + // fungible + const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); + await approveExpectFail(fungibleCollectionId, 2, Alice, Bob); + // reFungible + const reFungibleCollectionId = + await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}}); + await approveExpectFail(reFungibleCollectionId, 2, Alice, Bob); + }); + }); + + it('Approve using the address that does not own the approved token', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + const nftCollectionId = await createCollectionExpectSuccess(); + // nft + const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT'); + await approveExpectFail(nftCollectionId, newNftTokenId, Bob, Alice); + // fungible + const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); + const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible'); + await approveExpectFail(fungibleCollectionId, newFungibleTokenId, Bob, Alice); + // reFungible + const reFungibleCollectionId = + await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}}); + const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible'); + await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, Bob, Alice); + }); + }); +}); --- a/tests/src/createCollection.test.ts +++ b/tests/src/createCollection.test.ts @@ -5,8 +5,8 @@ import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import { default as usingApi } from "./substrate/substrate-api"; -import { createCollectionExpectSuccess, createCollectionExpectFailure } from "./util/helpers"; +import { default as usingApi } from './substrate/substrate-api'; +import { createCollectionExpectFailure, createCollectionExpectSuccess } from './util/helpers'; chai.use(chaiAsPromised); const expect = chai.expect; @@ -35,24 +35,25 @@ describe('(!negative test!) integration test: ext. createCollection():', () => { it('(!negative test!) create new NFT collection whith incorrect data (mode)', async () => { await usingApi(async (api) => { - const AcollectionCount = parseInt((await api.query.nft.collectionCount()).toString()); + const AcollectionCount = parseInt((await api.query.nft.collectionCount()).toString(), 10); - const badTransaction = async function () { + const badTransaction = async () => { await createCollectionExpectSuccess({mode: {type: 'Invalid'}}); }; + // tslint:disable-next-line:no-unused-expression expect(badTransaction()).to.be.rejected; - const BcollectionCount = parseInt((await api.query.nft.collectionCount()).toString()); + const BcollectionCount = parseInt((await api.query.nft.collectionCount()).toString(), 10); expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Incorrect collection created.'); }); }); it('(!negative test!) create new NFT collection whith incorrect data (collection_name)', async () => { - await createCollectionExpectFailure({name: 'A'.repeat(65)}); + await createCollectionExpectFailure({ name: 'A'.repeat(65), mode: {type: 'NFT'}}); }); it('(!negative test!) create new NFT collection whith incorrect data (collection_description)', async () => { - await createCollectionExpectFailure({description: 'A'.repeat(257)}); + await createCollectionExpectFailure({ description: 'A'.repeat(257), mode: { type: 'NFT' }}); }); it('(!negative test!) create new NFT collection whith incorrect data (token_prefix)', async () => { - await createCollectionExpectFailure({tokenPrefix: 'A'.repeat(17)}); + await createCollectionExpectFailure({tokenPrefix: 'A'.repeat(17), mode: {type: 'NFT'}}); }); }); --- a/tests/src/substrate/substrate-api.ts +++ b/tests/src/substrate/substrate-api.ts @@ -90,7 +90,6 @@ res(rec); console.error = consoleError; console.log = consoleLog; - }); }; const reject = (errror: any) => { @@ -104,6 +103,8 @@ await transaction.signAndSend(sender, ({ events = [], status }) => { const transactionStatus = getTransactionStatus(events, status); + console.log('transactionStatus', transactionStatus, 'events', events); + if (transactionStatus == TransactionStatus.Success) { resolve(events); } else if (transactionStatus == TransactionStatus.Fail) { @@ -114,4 +115,4 @@ reject(e); } }); -} \ No newline at end of file +} --- /dev/null +++ b/tests/src/transferFrom.test.ts @@ -0,0 +1,188 @@ +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// +import { ApiPromise } from '@polkadot/api'; +import chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import privateKey from './substrate/privateKey'; +import { default as usingApi } from './substrate/substrate-api'; +import { + approveExpectFail, + approveExpectSuccess, + createCollectionExpectSuccess, + createItemExpectSuccess, + destroyCollectionExpectSuccess, + transferFromExpectFail, + transferFromExpectSuccess, +} from './util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +describe('Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => { + it('Execute the extrinsic and check nftItemList - owner of token', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + const Charlie = privateKey('//CHARLIE'); + // nft + const nftCollectionId = await createCollectionExpectSuccess(); + const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT'); + await approveExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob); + + await transferFromExpectSuccess(nftCollectionId, newNftTokenId, Bob, Alice, Charlie, 1, 'NFT'); + + // fungible + const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); + const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible'); + await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob); + await transferFromExpectSuccess(fungibleCollectionId, newFungibleTokenId, Bob, Alice, Charlie, 1, 'Fungible'); + // reFungible + const reFungibleCollectionId = await + createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}}); + const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible'); + await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob); + await transferFromExpectSuccess(reFungibleCollectionId, + newReFungibleTokenId, Bob, Alice, Charlie, 1, 'ReFungible'); + }); + }); +}); + +describe('Negative Integration Test transferFrom(from, recipient, collection_id, item_id, value):', () => { + it('transferFrom for a collection that does not exist', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + const Charlie = privateKey('//CHARLIE'); + // nft + const nftCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number; + await approveExpectFail(nftCollectionCount + 1, 1, Alice, Bob); + + await transferFromExpectFail(nftCollectionCount + 1, 1, Bob, Alice, Charlie, 1); + + // fungible + const fungibleCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number; + await approveExpectFail(fungibleCollectionCount + 1, 1, Alice, Bob); + + await transferFromExpectFail(fungibleCollectionCount + 1, 1, Bob, Alice, Charlie, 1); + // reFungible + const reFungibleCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number; + await approveExpectFail(reFungibleCollectionCount + 1, 1, Alice, Bob); + + await transferFromExpectFail(reFungibleCollectionCount + 1, 1, Bob, Alice, Charlie, 1); + }); + }); + + /* it('transferFrom for a collection that was destroyed', async () => { + await usingApi(async (api: ApiPromise) => { + this test copies approve negative test + }); + }); */ + + /* it('transferFrom a token that does not exist', async () => { + await usingApi(async (api: ApiPromise) => { + this test copies approve negative test + }); + }); */ + + /* it('transferFrom a token that was deleted', async () => { + await usingApi(async (api: ApiPromise) => { + this test copies approve negative test + }); + }); */ + + it('transferFrom for not approved address', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + const Charlie = privateKey('//CHARLIE'); + // nft + const nftCollectionId = await createCollectionExpectSuccess(); + const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT'); + + await transferFromExpectFail(nftCollectionId, newNftTokenId, Bob, Alice, Charlie, 1); + + // fungible + const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); + const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible'); + await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, Bob, Alice, Charlie, 1); + // reFungible + const reFungibleCollectionId = await + createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}}); + const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible'); + await transferFromExpectFail(reFungibleCollectionId, + newReFungibleTokenId, Bob, Alice, Charlie, 1); + }); + }); + + it('transferFrom incorrect token count', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + const Charlie = privateKey('//CHARLIE'); + // nft + const nftCollectionId = await createCollectionExpectSuccess(); + const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT'); + await approveExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob); + + await transferFromExpectFail(nftCollectionId, newNftTokenId, Bob, Alice, Charlie, 2); + + // fungible + const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); + const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible'); + await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob); + await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, Bob, Alice, Charlie, 2); + // reFungible + const reFungibleCollectionId = await + createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}}); + const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible'); + await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob); + await transferFromExpectFail(reFungibleCollectionId, + newReFungibleTokenId, Bob, Alice, Charlie, 2); + }); + }); + + it('execute transferFrom from account that is not owner of collection', async () => { + await usingApi(async (api: ApiPromise) => { + const Alice = privateKey('//Alice'); + const Bob = privateKey('//Bob'); + const Charlie = privateKey('//CHARLIE'); + const Dave = privateKey('//DAVE'); + // nft + const nftCollectionId = await createCollectionExpectSuccess(); + const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT'); + try { + await approveExpectFail(nftCollectionId, newNftTokenId, Dave, Bob); + await transferFromExpectFail(nftCollectionId, newNftTokenId, Dave, Alice, Charlie, 1); + } catch (e) { + // tslint:disable-next-line:no-unused-expression + expect(e).to.be.exist; + } + + // await transferFromExpectFail(nftCollectionId, newNftTokenId, Dave, Alice, Charlie, 1); + + // fungible + const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}}); + const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible'); + try { + await approveExpectFail(fungibleCollectionId, newFungibleTokenId, Dave, Bob); + await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, Dave, Alice, Charlie, 1); + } catch (e) { + // tslint:disable-next-line:no-unused-expression + expect(e).to.be.exist; + } + // reFungible + const reFungibleCollectionId = await + createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}}); + const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible'); + try { + await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, Dave, Bob); + await transferFromExpectFail(reFungibleCollectionId, newReFungibleTokenId, Dave, Alice, Charlie, 1); + } catch (e) { + // tslint:disable-next-line:no-unused-expression + expect(e).to.be.exist; + } + }); + }); +}); --- a/tests/src/util/helpers.ts +++ b/tests/src/util/helpers.ts @@ -3,20 +3,20 @@ // file 'LICENSE', which is part of this source code package. // +import { ApiPromise, Keyring } from '@polkadot/api'; +import { Enum, Struct } from '@polkadot/types/codec'; +import type { AccountId, EventRecord } from '@polkadot/types/interfaces'; +import { u128 } from '@polkadot/types/primitive'; +import { IKeyringPair } from '@polkadot/types/types'; +import { BigNumber } from 'bignumber.js'; +import BN from 'bn.js'; import chai from 'chai'; import chaiAsPromised from 'chai-as-promised'; -import type { AccountId, EventRecord } from '@polkadot/types/interfaces'; -import { ApiPromise, Keyring } from "@polkadot/api"; -import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from "../substrate/substrate-api"; +import { alicesPublicKey, nullPublicKey } from '../accounts'; import privateKey from '../substrate/privateKey'; -import { alicesPublicKey, nullPublicKey } from "../accounts"; -import { strToUTF16, utf16ToStr, hexToStr } from './util'; -import { IKeyringPair } from '@polkadot/types/types'; -import { BigNumber } from 'bignumber.js'; -import { Struct, Enum } from '@polkadot/types/codec'; -import { u128 } from '@polkadot/types/primitive'; +import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api'; import { ICollectionInterface } from '../types'; -import BN from "bn.js"; +import { hexToStr, strToUTF16, utf16ToStr } from './util'; chai.use(chaiAsPromised); const expect = chai.expect; @@ -25,24 +25,45 @@ success: boolean, }; -type CreateCollectionResult = { - success: boolean, - collectionId: number -}; +interface CreateCollectionResult { + success: boolean; + collectionId: number; +} -type CreateItemResult = { - success: boolean, - collectionId: number, - itemId: number -}; +interface CreateItemResult { + success: boolean; + collectionId: number; + itemId: number; +} + +interface IReFungibleOwner { + Fraction: BN; + Owner: number[]; +} + +interface ITokenDataType { + Owner: number[]; + ConstData: number[]; + VariableData: number[]; +} +interface IFungibleTokenDataType { + Value: BN; +} + +interface IReFungibleTokenDataType { + Owner: IReFungibleOwner[]; + ConstData: number[]; + VariableData: number[]; +} + export function getGenericResult(events: EventRecord[]): GenericResult { - let result: GenericResult = { - success: false - } + const result: GenericResult = { + success: false, + }; events.forEach(({ phase, event: { data, method, section } }) => { // console.log(` ${phase}: ${section}.${method}:: ${data}`); - if (method == 'ExtrinsicSuccess') { + if (method === 'ExtrinsicSuccess') { result.success = true; } }); @@ -60,10 +81,10 @@ collectionId = parseInt(data[0].toString()); } }); - let result: CreateCollectionResult = { + const result: CreateCollectionResult = { success, - collectionId - } + collectionId, + }; return result; } @@ -80,19 +101,33 @@ itemId = parseInt(data[1].toString()); } }); - let result: CreateItemResult = { + const result: CreateItemResult = { success, collectionId, - itemId - } + itemId, + }; return result; } interface Invalid { - type: 'Invalid' + type: 'Invalid'; } interface Nft { + type: 'NFT'; +} + +interface Fungible { + type: 'Fungible'; + decimalPoints: number; +} + +interface ReFungible { + type: 'ReFungible'; + decimalPoints: number; +} + +interface Nft { type: 'NFT' } @@ -112,14 +147,14 @@ mode: CollectionMode, name: string, description: string, - tokenPrefix: string + tokenPrefix: string, }; const defaultCreateCollectionParams: CreateCollectionParams = { - name: 'name', description: 'description', - mode: { type: "NFT" }, - tokenPrefix: 'prefix' + mode: { type: 'NFT' }, + name: 'name', + tokenPrefix: 'prefix', } export async function createCollectionExpectSuccess(params: Partial = {}): Promise { @@ -128,22 +163,19 @@ let collectionId: number = 0; await usingApi(async (api) => { // Get number of collections before the transaction - const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString()); + const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10); // Run the CreateCollection transaction const alicePrivateKey = privateKey('//Alice'); let modeprm = {}; - if (mode.type == 'NFT') { + if (mode.type === 'NFT') { modeprm = {nft: null}; - } - else if (mode.type == 'Fungible') { + } else if (mode.type === 'Fungible') { modeprm = {fungible: mode.decimalPoints}; - } - else if (mode.type == 'ReFungible') { + } else if (mode.type === 'ReFungible') { modeprm = {refungible: mode.decimalPoints}; - } - else if (mode.type == 'Invalid') { + } else if (mode.type === 'Invalid') { modeprm = {invalid: null}; } @@ -152,16 +184,18 @@ const result = getCreateCollectionResult(events); // Get number of collections after the transaction - const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString()); + const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10); - // Get the collection + // Get the collection const collection: any = (await api.query.nft.collection(result.collectionId)).toJSON(); // What to expect + // tslint:disable-next-line:no-unused-expression expect(result.success).to.be.true; expect(result.collectionId).to.be.equal(BcollectionCount); + // tslint:disable-next-line:no-unused-expression expect(collection).to.be.not.null; - expect(BcollectionCount).to.be.equal(AcollectionCount+1, 'Error: NFT collection NOT created.'); + expect(BcollectionCount).to.be.equal(AcollectionCount + 1, 'Error: NFT collection NOT created.'); expect(collection.Owner).to.be.equal(alicesPublicKey); expect(utf16ToStr(collection.Name)).to.be.equal(name); expect(utf16ToStr(collection.Description)).to.be.equal(description); @@ -172,17 +206,28 @@ return collectionId; } - + export async function createCollectionExpectFailure(params: Partial = {}) { const {name, description, mode, tokenPrefix } = {...defaultCreateCollectionParams, ...params}; + 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}; + } + await usingApi(async (api) => { // Get number of collections before the transaction const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString()); // Run the CreateCollection transaction const alicePrivateKey = privateKey('//Alice'); - const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), mode); + const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm); const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected; const result = getCreateCollectionResult(events); @@ -190,11 +235,12 @@ const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString()); // What to expect + // tslint:disable-next-line:no-unused-expression expect(result.success).to.be.false; expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.'); }); } - + export async function findUnusedAddress(api: ApiPromise): Promise { let bal = new BigNumber(0); let unused; @@ -204,7 +250,7 @@ unused = keyring.addFromUri(`//${randomSeed}`); bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString()); } while (bal.toFixed() != '0'); - return unused; + return unused; } function getDestroyResult(events: EventRecord[]): boolean { @@ -235,7 +281,7 @@ const events = await submitTransactionAsync(alicePrivateKey, tx); const result = getDestroyResult(events); - // Get the collection + // Get the collection const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); // What to expect @@ -254,7 +300,7 @@ const events = await submitTransactionAsync(alicePrivateKey, tx); const result = getGenericResult(events); - // Get the collection + // Get the collection const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); // What to expect @@ -273,7 +319,7 @@ const events = await submitTransactionAsync(alicePrivateKey, tx); const result = getGenericResult(events); - // Get the collection + // Get the collection const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); // What to expect @@ -312,7 +358,7 @@ const events = await submitTransactionAsync(sender, tx); const result = getGenericResult(events); - // Get the collection + // Get the collection const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); // What to expect @@ -334,48 +380,131 @@ export interface CreateFungibleData extends Struct { readonly value: u128; -}; +} -export interface CreateReFungibleData extends Struct {}; -export interface CreateNftData extends Struct {}; +export interface CreateReFungibleData extends Struct {} +export interface CreateNftData extends Struct {} export interface CreateItemData extends Enum { - NFT: CreateNftData, - Fungible: CreateFungibleData, - ReFungible: CreateReFungibleData -}; + NFT: CreateNftData; + Fungible: CreateFungibleData; + ReFungible: CreateReFungibleData; +} + +export async function +approveExpectSuccess(collectionId: number, + tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number = 1) { + await usingApi(async (api: ApiPromise) => { + const allowanceBefore = + await api.query.nft.allowances(collectionId, [tokenId, owner.address, approved.address]) as unknown as BN; + const approveNftTx = await api.tx.nft.approve(approved.address, collectionId, tokenId, amount); + const events = await submitTransactionAsync(owner, approveNftTx); + const result = getCreateItemResult(events); + // tslint:disable-next-line:no-unused-expression + expect(result.success).to.be.true; + const allowanceAfter = + await api.query.nft.allowances(collectionId, [tokenId, owner.address, approved.address]) as unknown as BN; + expect(allowanceAfter.toNumber() - allowanceBefore.toNumber()).to.be.equal(amount); + }); +} + +export async function +transferFromExpectSuccess(collectionId: number, + tokenId: number, + accountApproved: IKeyringPair, + accountFrom: IKeyringPair, + accountTo: IKeyringPair, + value: number = 1, + type: string = 'NFT') { + await usingApi(async (api: ApiPromise) => { + let balanceBefore = new BN(0); + if (type === 'Fungible') { + balanceBefore = await api.query.nft.balance(collectionId, accountTo.address) as unknown as BN; + } + const transferFromTx = await api.tx.nft.transferFrom( + accountFrom.address, accountTo.address, collectionId, tokenId, value); + const events = await submitTransactionAsync(accountFrom, transferFromTx); + const result = getCreateItemResult(events); + // tslint:disable-next-line:no-unused-expression + expect(result.success).to.be.true; + if (type === 'NFT') { + const nftItemData = await api.query.nft.nftItemList(collectionId, tokenId) as unknown as ITokenDataType; + expect(nftItemData.Owner.toString()).to.be.equal(accountTo.address); + } + if (type === 'Fungible') { + const balanceAfter = await api.query.nft.balance(collectionId, accountTo.address) as unknown as BN; + expect(balanceAfter.sub(balanceBefore).toNumber()).to.be.equal(value); + } + if (type === 'ReFungible') { + const nftItemData = + await api.query.nft.reFungibleItemList(collectionId, tokenId) as unknown as IReFungibleTokenDataType; + expect(nftItemData.Owner[0].Owner.toString()).to.be.equal(accountTo.address); + expect(nftItemData.Owner[0].Fraction.toNumber()).to.be.equal(value); + } + }); +} + +export async function +transferFromExpectFail(collectionId: number, + tokenId: number, + accountApproved: IKeyringPair, + accountFrom: IKeyringPair, + accountTo: IKeyringPair, + value: number = 1) { + await usingApi(async (api: ApiPromise) => { + const transferFromTx = await api.tx.nft.transferFrom( + accountFrom.address, accountTo.address, collectionId, tokenId, value); + const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected; + const result = getCreateCollectionResult(events); + // tslint:disable-next-line:no-unused-expression + expect(result.success).to.be.false; + }); +} + +export async function +approveExpectFail(collectionId: number, + tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number = 1) { + await usingApi(async (api: ApiPromise) => { + const approveNftTx = await api.tx.nft.approve(approved.address, collectionId, tokenId, amount); + const events = await expect(submitTransactionExpectFailAsync(owner, approveNftTx)).to.be.rejected; + const result = getCreateCollectionResult(events); + // tslint:disable-next-line:no-unused-expression + expect(result.success).to.be.false; + }); +} export async function createItemExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, owner: string = '') { let newItemId: number = 0; await usingApi(async (api) => { - const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString()); - const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON(); + const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10); + const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON(); const AItemBalance = new BigNumber(Aitem.Value); - if (owner === '') owner = sender.address; + if (owner === '') { + owner = sender.address; + } let tx; - if (createMode == 'Fungible') { - let createData = {fungible: {value: 10}}; + if (createMode === 'Fungible') { + const createData = {fungible: {value: 10}}; tx = api.tx.nft.createItem(collectionId, owner, createData); - } - else { + } else { tx = api.tx.nft.createItem(collectionId, owner, createMode); } const events = await submitTransactionAsync(sender, tx); const result = getCreateItemResult(events); - const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString()); - const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON(); + const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10); + const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON(); const BItemBalance = new BigNumber(Bitem.Value); // What to expect + // tslint:disable-next-line:no-unused-expression expect(result.success).to.be.true; - if (createMode == 'Fungible') { + if (createMode === 'Fungible') { expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10); - } - else { - expect(BItemCount).to.be.equal(AItemCount+1); + } else { + expect(BItemCount).to.be.equal(AItemCount + 1); } expect(collectionId).to.be.equal(result.collectionId); expect(BItemCount).to.be.equal(result.itemId); @@ -392,7 +521,7 @@ const events = await submitTransactionAsync(sender, tx); const result = getGenericResult(events); - // Get the collection + // Get the collection const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); // What to expect @@ -409,7 +538,7 @@ const events = await submitTransactionAsync(sender, tx); const result = getGenericResult(events); - // Get the collection + // Get the collection const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); // What to expect @@ -426,7 +555,7 @@ const events = await submitTransactionAsync(sender, tx); const result = getGenericResult(events); - // Get the collection + // Get the collection const collection: any = (await api.query.nft.collection(collectionId)).toJSON(); // What to expect -- gitstuff