git.delta.rocks / unique-network / refs/commits / 570880cf1d2e

difftreelog

CORE-180. burnItem

str-mv2021-08-03parent: #b255f4b.patch.diff
in: master

9 files changed

modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -987,12 +987,12 @@
 		/// * item_id: ID of NFT to burn.
 		#[weight = <SelfWeightOf<T>>::burn_item()]
 		#[transactional]
-		pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {
+		pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, item_owner: T::CrossAccountId, value: u128) -> DispatchResult {
 
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
 			let target_collection = Self::get_collection(collection_id)?;
 
-			Self::burn_item_internal(&sender, &target_collection, item_id, value)?;
+			Self::burn_item_internal(&sender, &target_collection, item_id, &item_owner, value)?;
 
 			target_collection.submit_logs()
 		}
@@ -1596,6 +1596,7 @@
 		sender: &T::CrossAccountId,
 		collection: &CollectionHandle<T>,
 		item_id: TokenId,
+		item_owner: &T::CrossAccountId,
 		value: u128,
 	) -> DispatchResult {
 		ensure!(
@@ -1611,8 +1612,11 @@
 
 		match collection.mode {
 			CollectionMode::NFT => Self::burn_nft_item(collection, item_id)?,
-			CollectionMode::Fungible(_) => Self::burn_fungible_item(sender, collection, value)?,
-			CollectionMode::ReFungible => Self::burn_refungible_item(collection, item_id, sender)?,
+			CollectionMode::Fungible(_) => Self::burn_fungible_item(collection, item_owner, value)?,
+			CollectionMode::ReFungible => {
+				Self::burn_refungible_item(collection, item_id, item_owner)?
+			}
+			_ => (),
 		};
 
 		Ok(())
@@ -1947,8 +1951,8 @@
 	}
 
 	fn burn_fungible_item(
-		owner: &T::CrossAccountId,
 		collection: &CollectionHandle<T>,
+		owner: &T::CrossAccountId,
 		value: u128,
 	) -> DispatchResult {
 		let collection_id = collection.id;
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -707,9 +707,15 @@
 		assert_eq!(TemplateModule::balance_count(1, 1), 1);
 
 		// burn item
-		assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 5));
+		assert_ok!(TemplateModule::burn_item(
+			origin1.clone(),
+			1,
+			1,
+			account(1),
+			5
+		));
 		assert_noop!(
-			TemplateModule::burn_item(origin1, 1, 1, 5),
+			TemplateModule::burn_item(origin1, 1, 1, account(1), 5),
 			Error::<Test>::TokenNotFound
 		);
 
@@ -736,9 +742,15 @@
 		assert_eq!(TemplateModule::balance_count(1, 1), 5);
 
 		// burn item
-		assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 5));
+		assert_ok!(TemplateModule::burn_item(
+			origin1.clone(),
+			1,
+			1,
+			account(1),
+			5
+		));
 		assert_noop!(
-			TemplateModule::burn_item(origin1, 1, 1, 5),
+			TemplateModule::burn_item(origin1, 1, 1, account(1), 5),
 			Error::<Test>::TokenValueNotEnough
 		);
 
@@ -781,9 +793,15 @@
 		assert_eq!(TemplateModule::balance_count(1, 1), 1023);
 
 		// burn item
-		assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 1023));
+		assert_ok!(TemplateModule::burn_item(
+			origin1.clone(),
+			1,
+			1,
+			account(1),
+			1023
+		));
 		assert_noop!(
-			TemplateModule::burn_item(origin1, 1, 1, 1023),
+			TemplateModule::burn_item(origin1, 1, 1, account(1), 1023),
 			Error::<Test>::TokenNotFound
 		);
 
@@ -1378,7 +1396,7 @@
 			AccessMode::WhiteList
 		));
 		assert_noop!(
-			TemplateModule::burn_item(origin1, 1, 1, 5),
+			TemplateModule::burn_item(origin1.clone(), 1, 1, account(1), 5),
 			Error::<Test>::AddresNotInWhiteList
 		);
 	});
modifiedtests/src/burnItem.test.tsdiffbeforeafterboth
--- a/tests/src/burnItem.test.ts
+++ b/tests/src/burnItem.test.ts
@@ -38,7 +38,7 @@
     const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
 
     await usingApi(async (api) => {
-      const tx = api.tx.nft.burnItem(collectionId, tokenId, 0);
+      const tx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(alice.address), 0);
       const events = await submitTransactionAsync(alice, tx);
       const result = getGenericResult(events);
       // Get the item
@@ -59,7 +59,7 @@
 
     await usingApi(async (api) => {
       // Destroy 1 of 10
-      const tx = api.tx.nft.burnItem(collectionId, tokenId, 1);
+      const tx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(alice.address), 1);
       const events = await submitTransactionAsync(alice, tx);
       const result = getGenericResult(events);
   
@@ -79,7 +79,7 @@
     const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
 
     await usingApi(async (api) => {
-      const tx = api.tx.nft.burnItem(collectionId, tokenId, 1);
+      const tx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(alice.address), 1);
       const events = await submitTransactionAsync(alice, tx);
       const result = getGenericResult(events);
   
@@ -107,7 +107,7 @@
       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 tx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(bob.address), 0);
       const events2 = await submitTransactionAsync(bob, tx);
       const result2 = getGenericResult(events2);
 
@@ -152,7 +152,7 @@
     await addCollectionAdminExpectSuccess(alice, collectionId, bob);
 
     await usingApi(async (api) => {
-      const tx = api.tx.nft.burnItem(collectionId, tokenId, 0);
+      const tx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(alice.address), 0);
       const events = await submitTransactionAsync(bob, tx);
       const result = getGenericResult(events);
       // Get the item
@@ -164,6 +164,49 @@
       expect(item).to.be.null;
     });
   });
+
+
+  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
+    await addCollectionAdminExpectSuccess(alice, collectionId, bob);
+    const tokenId = 0; // ignored
+
+    await usingApi(async (api) => {
+      // Destroy 1 of 10
+      const tx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(alice.address), 1);
+      const events = await submitTransactionAsync(bob, 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 }});
+    const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
+    await addCollectionAdminExpectSuccess(alice, collectionId, bob);
+
+    await usingApi(async (api) => {
+      const tx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(alice.address), 1);
+      const events = await submitTransactionAsync(bob, 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.null;
+    });
+  });
 });
 
 describe('Negative integration test: ext. burnItem():', () => {
@@ -182,7 +225,7 @@
     await destroyCollectionExpectSuccess(collectionId);
 
     await usingApi(async (api) => {
-      const tx = api.tx.nft.burnItem(collectionId, tokenId, 0);
+      const tx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(alice.address), 0);
       const badTransaction = async function () { 
         await submitTransactionExpectFailAsync(alice, tx);
       };
@@ -197,7 +240,7 @@
     const tokenId = 10;
 
     await usingApi(async (api) => {
-      const tx = api.tx.nft.burnItem(collectionId, tokenId, 0);
+      const tx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(alice.address), 0);
       const badTransaction = async function () { 
         await submitTransactionExpectFailAsync(alice, tx);
       };
@@ -212,7 +255,7 @@
     const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
 
     await usingApi(async (api) => {
-      const tx = api.tx.nft.burnItem(collectionId, tokenId, 0);
+      const tx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(alice.address), 0);
       const badTransaction = async function () { 
         await submitTransactionExpectFailAsync(bob, tx);
       };
@@ -228,7 +271,7 @@
 
     await usingApi(async (api) => {
 
-      const burntx = api.tx.nft.burnItem(collectionId, tokenId, 0);
+      const burntx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(alice.address), 0);
       const events1 = await submitTransactionAsync(alice, burntx);
       const result1 = getGenericResult(events1);
       expect(result1.success).to.be.true;
@@ -251,7 +294,7 @@
 
     await usingApi(async (api) => {
       // Destroy 11 of 10
-      const tx = api.tx.nft.burnItem(collectionId, tokenId, 11);
+      const tx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(alice.address), 11);
       const badTransaction = async function () { 
         await submitTransactionExpectFailAsync(alice, tx);
       };
modifiedtests/src/check-event/burnItemEvent.test.tsdiffbeforeafterboth
--- a/tests/src/check-event/burnItemEvent.test.ts
+++ b/tests/src/check-event/burnItemEvent.test.ts
@@ -10,7 +10,7 @@
 import chaiAsPromised from 'chai-as-promised';
 import privateKey from '../substrate/privateKey';
 import usingApi, {submitTransactionAsync} from '../substrate/substrate-api';
-import { createCollectionExpectSuccess, createItemExpectSuccess, nftEventMessage } from '../util/helpers';
+import { createCollectionExpectSuccess, createItemExpectSuccess, nftEventMessage, normalizeAccountId } from '../util/helpers';
 
 chai.use(chaiAsPromised);
 const expect = chai.expect;
@@ -29,7 +29,7 @@
     await usingApi(async (api: ApiPromise) => {
       const collectionID = await createCollectionExpectSuccess();
       const itemID = await createItemExpectSuccess(Alice, collectionID, 'NFT');
-      const burnItem = api.tx.nft.burnItem(collectionID, itemID, 1);
+      const burnItem = api.tx.nft.burnItem(collectionID, itemID, normalizeAccountId(Alice.address), 1);
       const events = await submitTransactionAsync(Alice, burnItem);
       const msg = JSON.stringify(nftEventMessage(events));
       expect(msg).to.be.contain(checkSection);
modifiedtests/src/collision-tests/admVsOwnerTake.test.tsdiffbeforeafterboth
--- a/tests/src/collision-tests/admVsOwnerTake.test.ts
+++ b/tests/src/collision-tests/admVsOwnerTake.test.ts
@@ -34,7 +34,7 @@
       const itemId = await createItemExpectSuccess(Bob, collectionId, 'NFT');
       //
       const sendItem = api.tx.nft.transfer(normalizeAccountId(Ferdie.address), collectionId, itemId, 1);
-      const burnItem = api.tx.nft.burnItem(collectionId, itemId, 1);
+      const burnItem = api.tx.nft.burnItem(collectionId, itemId, normalizeAccountId(Alice.address), 1);
       await Promise.all([
         sendItem.signAndSend(Bob),
         burnItem.signAndSend(Alice),
modifiedtests/src/setVariableMetaData.test.tsdiffbeforeafterboth
--- a/tests/src/setVariableMetaData.test.ts
+++ b/tests/src/setVariableMetaData.test.ts
@@ -116,7 +116,7 @@
   it('fails on removed token', async () => {
     const removedTokenCollectionId = await createCollectionExpectSuccess({ mode: { type: 'NFT' } });
     const removedTokenId = await createItemExpectSuccess(alice, removedTokenCollectionId, 'NFT');
-    await burnItemExpectSuccess(alice, removedTokenCollectionId, removedTokenId);
+    await burnItemExpectSuccess(alice, removedTokenCollectionId, removedTokenId, alice);
 
     await setVariableMetaDataExpectFailure(alice, removedTokenCollectionId, removedTokenId, data);
   });
modifiedtests/src/transfer.test.tsdiffbeforeafterboth
--- a/tests/src/transfer.test.ts
+++ b/tests/src/transfer.test.ts
@@ -188,18 +188,18 @@
     // nft
     const nftCollectionId = await createCollectionExpectSuccess();
     const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
-    await burnItemExpectSuccess(Alice, nftCollectionId, newNftTokenId, 1);
+    await burnItemExpectSuccess(Alice, nftCollectionId, newNftTokenId, Alice, 1);
     await transferExpectFailure(nftCollectionId, newNftTokenId, Alice, Bob, 1);
     // fungible
     const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
     const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');
-    await burnItemExpectSuccess(Alice, fungibleCollectionId, newFungibleTokenId, 10);
+    await burnItemExpectSuccess(Alice, fungibleCollectionId, newFungibleTokenId, Alice, 10);
     await transferExpectFailure(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1);
     // reFungible
     const reFungibleCollectionId = await
     createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
-    await burnItemExpectSuccess(Alice, reFungibleCollectionId, newReFungibleTokenId, 1);
+    await burnItemExpectSuccess(Alice, reFungibleCollectionId, newReFungibleTokenId, Alice, 1);
     await transferExpectFailure(
       reFungibleCollectionId,
       newReFungibleTokenId,
modifiedtests/src/transferFrom.test.tsdiffbeforeafterboth
--- a/tests/src/transferFrom.test.ts
+++ b/tests/src/transferFrom.test.ts
@@ -246,7 +246,7 @@
       // nft
       const nftCollectionId = await createCollectionExpectSuccess();
       const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
-      await burnItemExpectSuccess(Alice, nftCollectionId, newNftTokenId, 1);
+      await burnItemExpectSuccess(Alice, nftCollectionId, newNftTokenId, Alice, 1);
       await approveExpectFail(nftCollectionId, newNftTokenId, Alice, Bob);
       await transferFromExpectFail(nftCollectionId, newNftTokenId, Bob, Alice, Charlie, 1);      
     });
@@ -255,7 +255,7 @@
     await usingApi(async () => {
       const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
       const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');
-      await burnItemExpectSuccess(Alice, fungibleCollectionId, 1, 10);
+      await burnItemExpectSuccess(Alice, fungibleCollectionId, 1, Alice, 10);
       await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob);
       await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, Bob, Alice, Charlie, 1);
           
@@ -265,7 +265,7 @@
     await usingApi(async () => {
       const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
-      await burnItemExpectSuccess(Alice, reFungibleCollectionId, newReFungibleTokenId, 1);
+      await burnItemExpectSuccess(Alice, reFungibleCollectionId, newReFungibleTokenId, Alice, 1);
       await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob);
       await transferFromExpectFail(reFungibleCollectionId, newReFungibleTokenId, Bob, Alice, Charlie, 1);
           
@@ -278,7 +278,7 @@
       const nftCollectionId = await createCollectionExpectSuccess();
       const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
       await approveExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob);
-      await burnItemExpectSuccess(Alice, nftCollectionId, newNftTokenId, 1);
+      await burnItemExpectSuccess(Alice, nftCollectionId, newNftTokenId, Alice, 1);
       await transferFromExpectFail(nftCollectionId, newNftTokenId, Bob, Alice, Charlie, 1);      
     });
   });
@@ -287,7 +287,7 @@
       const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
       const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');
       await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob);
-      await burnItemExpectSuccess(Alice, fungibleCollectionId, 1, 10);
+      await burnItemExpectSuccess(Alice, fungibleCollectionId, 1, Alice, 10);
       await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, Bob, Alice, Charlie, 1);
           
     });
@@ -297,7 +297,7 @@
       const reFungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob);
-      await burnItemExpectSuccess(Alice, reFungibleCollectionId, newReFungibleTokenId, 1);
+      await burnItemExpectSuccess(Alice, reFungibleCollectionId, newReFungibleTokenId, Alice, 1);
       await transferFromExpectFail(reFungibleCollectionId, newReFungibleTokenId, Bob, Alice, Charlie, 1);
           
     });
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
before · tests/src/util/helpers.ts
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56import { ApiPromise, Keyring } from '@polkadot/api';7import type { AccountId, EventRecord } from '@polkadot/types/interfaces';8import { IKeyringPair } from '@polkadot/types/types';9import { evmToAddress } from '@polkadot/util-crypto';10import { BigNumber } from 'bignumber.js';11import BN from 'bn.js';12import chai from 'chai';13import chaiAsPromised from 'chai-as-promised';14import { alicesPublicKey } from '../accounts';15import privateKey from '../substrate/privateKey';16import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api';17import { ICollectionInterface } from '../types';18import { hexToStr, strToUTF16, utf16ToStr } from './util';1920chai.use(chaiAsPromised);21const expect = chai.expect;2223export type CrossAccountId = {24  substrate: string,25} | {26  ethereum: string,27};28export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {29  if (typeof input === 'string')30    return { substrate: input };31  if ('address' in input) {32    return { substrate: input.address };33  }34  if ('ethereum' in input) {35    input.ethereum = input.ethereum.toLowerCase();36    return input;37  }38  if ('substrate' in input) {39    return input;40  }4142  // AccountId43  return {substrate: input.toString()};44}45export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {46  input = normalizeAccountId(input);47  if ('substrate' in input) {48    return input.substrate;49  } else {50    return evmToAddress(input.ethereum);51  }52}5354export const U128_MAX = (1n << 128n) - 1n;5556const MICROUNIQUE = 1_000_000_000n;57const MILLIUNIQUE = 1_000n * MICROUNIQUE;58const CENTIUNIQUE = 10n * MILLIUNIQUE;59export const UNIQUE = 100n * CENTIUNIQUE;6061type GenericResult = {62  success: boolean,63};6465interface CreateCollectionResult {66  success: boolean;67  collectionId: number;68}6970interface CreateItemResult {71  success: boolean;72  collectionId: number;73  itemId: number;74  recipient?: CrossAccountId;75}7677interface TransferResult {78  success: boolean;79  collectionId: number;80  itemId: number;81  sender?: CrossAccountId;82  recipient?: CrossAccountId;83  value: bigint;84}8586interface IReFungibleOwner {87  Fraction: BN;88  Owner: number[];89}9091interface ITokenDataType {92  Owner: IKeyringPair;93  ConstData: number[];94  VariableData: number[];95}9697interface IGetMessage {98  checkMsgNftMethod: string;99  checkMsgTrsMethod: string;100  checkMsgSysMethod: string;101}102103export interface IFungibleTokenDataType {104  Value: number;105}106107export interface IChainLimits {108  CollectionNumbersLimit: number;109	AccountTokenOwnershipLimit: number;110	CollectionsAdminsLimit: number;111	CustomDataLimit: number;112	NftSponsorTransferTimeout: number;113	FungibleSponsorTransferTimeout: number;114	RefungibleSponsorTransferTimeout: number;115	OffchainSchemaLimit: number;116	VariableOnChainSchemaLimit: number;117	ConstOnChainSchemaLimit: number;118}119120export interface IReFungibleTokenDataType {121  Owner: IReFungibleOwner[];122  ConstData: number[];123  VariableData: number[];124}125126export function nftEventMessage(events: EventRecord[]): IGetMessage {127  let checkMsgNftMethod = '';128  let checkMsgTrsMethod = '';129  let checkMsgSysMethod = '';130  events.forEach(({ event: { method, section } }) => {131    if (section === 'nft') {132      checkMsgNftMethod = method;133    } else if (section === 'treasury') {134      checkMsgTrsMethod = method;135    } else if (section === 'system') {136      checkMsgSysMethod = method;137    } else { return null; }138  });139  const result: IGetMessage = {140    checkMsgNftMethod,141    checkMsgTrsMethod,142    checkMsgSysMethod,143  };144  return result;145}146147export function getGenericResult(events: EventRecord[]): GenericResult {148  const result: GenericResult = {149    success: false,150  };151  events.forEach(({ event: { method } }) => {152    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);153    if (method === 'ExtrinsicSuccess') {154      result.success = true;155    }156  });157  return result;158}159160161162export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {163  let success = false;164  let collectionId = 0;165  events.forEach(({ event: { data, method, section } }) => {166    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);167    if (method == 'ExtrinsicSuccess') {168      success = true;169    } else if ((section == 'nft') && (method == 'CollectionCreated')) {170      collectionId = parseInt(data[0].toString());171    }172  });173  const result: CreateCollectionResult = {174    success,175    collectionId,176  };177  return result;178}179180export function getCreateItemResult(events: EventRecord[]): CreateItemResult {181  let success = false;182  let collectionId = 0;183  let itemId = 0;184  let recipient;185  events.forEach(({ event: { data, method, section } }) => {186    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);187    if (method == 'ExtrinsicSuccess') {188      success = true;189    } else if ((section == 'nft') && (method == 'ItemCreated')) {190      collectionId = parseInt(data[0].toString());191      itemId = parseInt(data[1].toString());192      recipient = data[2].toJSON();193    }194  });195  const result: CreateItemResult = {196    success,197    collectionId,198    itemId,199    recipient,200  };201  return result;202}203204export function getTransferResult(events: EventRecord[]): TransferResult {205  const result: TransferResult = {206    success: false,207    collectionId: 0,208    itemId: 0,209    value: 0n,210  };211212  events.forEach(({ event: { data, method, section } }) => {213    if (method === 'ExtrinsicSuccess') {214      result.success = true;215    } else if (section === 'nft' && method === 'Transfer') {216      result.collectionId = +data[0].toString();217      result.itemId = +data[1].toString();218      result.sender = data[2].toJSON() as CrossAccountId;219      result.recipient = data[3].toJSON() as CrossAccountId;220      result.value = BigInt(data[4].toString());221    }222  });223224  return result;225}226227interface Nft {228  type: 'NFT';229}230231interface Fungible {232  type: 'Fungible';233  decimalPoints: number;234}235236interface ReFungible {237  type: 'ReFungible';238}239240type CollectionMode = Nft | Fungible | ReFungible;241242export type CreateCollectionParams = {243  mode: CollectionMode,244  name: string,245  description: string,246  tokenPrefix: string,247};248249const defaultCreateCollectionParams: CreateCollectionParams = {250  description: 'description',251  mode: { type: 'NFT' },252  name: 'name',253  tokenPrefix: 'prefix',254};255256export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {257  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };258259  let collectionId = 0;260  await usingApi(async (api) => {261    // Get number of collections before the transaction262    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);263264    // Run the CreateCollection transaction265    const alicePrivateKey = privateKey('//Alice');266267    let modeprm = {};268    if (mode.type === 'NFT') {269      modeprm = { nft: null };270    } else if (mode.type === 'Fungible') {271      modeprm = { fungible: mode.decimalPoints };272    } else if (mode.type === 'ReFungible') {273      modeprm = { refungible: null };274    }275276    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);277    const events = await submitTransactionAsync(alicePrivateKey, tx);278    const result = getCreateCollectionResult(events);279280    // Get number of collections after the transaction281    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);282283    // Get the collection284    const collection: any = (await api.query.nft.collectionById(result.collectionId) as any).toJSON();285286    // What to expect287    // tslint:disable-next-line:no-unused-expression288    expect(result.success).to.be.true;289    expect(result.collectionId).to.be.equal(BcollectionCount);290    // tslint:disable-next-line:no-unused-expression291    expect(collection).to.be.not.null;292    expect(BcollectionCount).to.be.equal(AcollectionCount + 1, 'Error: NFT collection NOT created.');293    expect(collection.Owner).to.be.equal(toSubstrateAddress(alicesPublicKey));294    expect(utf16ToStr(collection.Name)).to.be.equal(name);295    expect(utf16ToStr(collection.Description)).to.be.equal(description);296    expect(hexToStr(collection.TokenPrefix)).to.be.equal(tokenPrefix);297298    collectionId = result.collectionId;299  });300301  return collectionId;302}303304export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {305  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };306307  let modeprm = {};308  if (mode.type === 'NFT') {309    modeprm = { nft: null };310  } else if (mode.type === 'Fungible') {311    modeprm = { fungible: mode.decimalPoints };312  } else if (mode.type === 'ReFungible') {313    modeprm = { refungible: null };314  }315316  await usingApi(async (api) => {317    // Get number of collections before the transaction318    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());319320    // Run the CreateCollection transaction321    const alicePrivateKey = privateKey('//Alice');322    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);323    const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;324    const result = getCreateCollectionResult(events);325326    // Get number of collections after the transaction327    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());328329    // What to expect330    // tslint:disable-next-line:no-unused-expression331    expect(result.success).to.be.false;332    expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');333  });334}335336export async function findUnusedAddress(api: ApiPromise, seedAddition = ''): Promise<IKeyringPair> {337  let bal = new BigNumber(0);338  let unused;339  do {340    const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;341    const keyring = new Keyring({ type: 'sr25519' });342    unused = keyring.addFromUri(`//${randomSeed}`);343    bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());344  } while (bal.toFixed() != '0');345  return unused;346}347348export async function getAllowance(collectionId: number, tokenId: number, owner: string, approved: string) {349  return await usingApi(async (api) => {350    const bn = await api.query.nft.allowances(collectionId, [tokenId, owner, approved]) as unknown as BN;351    return BigInt(bn.toString());352  });353}354355export function findUnusedAddresses(api: ApiPromise, amount: number): Promise<IKeyringPair[]> {356  return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, '_' + Date.now())));357}358359export async function findNotExistingCollection(api: ApiPromise): Promise<number> {360  const totalNumber = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10) as unknown as number;361  const newCollection: number = totalNumber + 1;362  return newCollection;363}364365function getDestroyResult(events: EventRecord[]): boolean {366  let success = false;367  events.forEach(({ event: { method } }) => {368    if (method == 'ExtrinsicSuccess') {369      success = true;370    }371  });372  return success;373}374375export async function destroyCollectionExpectFailure(collectionId: number, senderSeed = '//Alice') {376  await usingApi(async (api) => {377    // Run the DestroyCollection transaction378    const alicePrivateKey = privateKey(senderSeed);379    const tx = api.tx.nft.destroyCollection(collectionId);380    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;381  });382}383384export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed = '//Alice') {385  await usingApi(async (api) => {386    // Run the DestroyCollection transaction387    const alicePrivateKey = privateKey(senderSeed);388    const tx = api.tx.nft.destroyCollection(collectionId);389    const events = await submitTransactionAsync(alicePrivateKey, tx);390    const result = getDestroyResult(events);391392    // Get the collection393    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();394395    // What to expect396    expect(result).to.be.true;397    expect(collection).to.be.null;398  });399}400401export async function queryCollectionLimits(collectionId: number) {402  return await usingApi(async (api) => {403    return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;404  });405}406407export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {408  await usingApi(async (api) => {409    const oldLimits = await queryCollectionLimits(collectionId);410    const newLimits = { ...oldLimits as any, ...limits };411    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);412    const events = await submitTransactionAsync(sender, tx);413    const result = getGenericResult(events);414415    expect(result.success).to.be.true;416  });417}418419export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) {420  await usingApi(async (api) => {421    const oldLimits = await queryCollectionLimits(collectionId);422    const newLimits = { ...oldLimits as any, ...limits };423    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);424    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;425    const result = getGenericResult(events);426427    expect(result.success).to.be.false;428  });429}430431export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string, sender = '//Alice') {432  await usingApi(async (api) => {433434    // Run the transaction435    const senderPrivateKey = privateKey(sender);436    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);437    const events = await submitTransactionAsync(senderPrivateKey, tx);438    const result = getGenericResult(events);439440    // Get the collection441    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();442443    // What to expect444    expect(result.success).to.be.true;445    expect(collection.Sponsorship).to.deep.equal({446      unconfirmed: sponsor,447    });448  });449}450451export async function removeCollectionSponsorExpectSuccess(collectionId: number, sender = '//Alice') {452  await usingApi(async (api) => {453454    // Run the transaction455    const alicePrivateKey = privateKey(sender);456    const tx = api.tx.nft.removeCollectionSponsor(collectionId);457    const events = await submitTransactionAsync(alicePrivateKey, tx);458    const result = getGenericResult(events);459460    // Get the collection461    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();462463    // What to expect464    expect(result.success).to.be.true;465    expect(collection.Sponsorship).to.be.deep.equal({ disabled: null });466  });467}468469export async function removeCollectionSponsorExpectFailure(collectionId: number, senderSeed = '//Alice') {470  await usingApi(async (api) => {471472    // Run the transaction473    const alicePrivateKey = privateKey(senderSeed);474    const tx = api.tx.nft.removeCollectionSponsor(collectionId);475    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;476  });477}478479export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed = '//Alice') {480  await usingApi(async (api) => {481482    // Run the transaction483    const alicePrivateKey = privateKey(senderSeed);484    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);485    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;486  });487}488489export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed = '//Alice') {490  await usingApi(async (api) => {491492    // Run the transaction493    const sender = privateKey(senderSeed);494    const tx = api.tx.nft.confirmSponsorship(collectionId);495    const events = await submitTransactionAsync(sender, tx);496    const result = getGenericResult(events);497498    // Get the collection499    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();500501    // What to expect502    expect(result.success).to.be.true;503    expect(collection.Sponsorship).to.be.deep.equal({504      confirmed: sender.address,505    });506  });507}508509510export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed = '//Alice') {511  await usingApi(async (api) => {512513    // Run the transaction514    const sender = privateKey(senderSeed);515    const tx = api.tx.nft.confirmSponsorship(collectionId);516    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;517  });518}519520export async function setMetadataUpdatePermissionFlagExpectSuccess(sender: IKeyringPair, collectionId: number, flag: string) {521522  await usingApi(async (api) => {523    const tx = api.tx.nft.setMetaUpdatePermissionFlag(collectionId, flag);524    const events = await submitTransactionAsync(sender, tx);525    const result = getGenericResult(events);526527    expect(result.success).to.be.true;528  });529}530531export async function setMetadataUpdatePermissionFlagExpectFailure(sender: IKeyringPair, collectionId: number, flag: string) {532533  await usingApi(async (api) => {534    const tx = api.tx.nft.setMetaUpdatePermissionFlag(collectionId, flag);535    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;536    const result = getGenericResult(events);537538    expect(result.success).to.be.false;539  });540}541542export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {543  await usingApi(async (api) => {544    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);545    const events = await submitTransactionAsync(sender, tx);546    const result = getGenericResult(events);547548    expect(result.success).to.be.true;549  });550}551552export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {553  await usingApi(async (api) => {554    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);555    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;556    const result = getGenericResult(events);557558    expect(result.success).to.be.false;559  });560}561562export async function setTransferFlagExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {563564  await usingApi(async (api) => {565566    const tx = api.tx.nft.setTransfersEnabledFlag (collectionId, enabled);567    const events = await submitTransactionAsync(sender, tx);568    const result = getGenericResult(events);569570    expect(result.success).to.be.true;571  });572}573574export async function setTransferFlagExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {575576  await usingApi(async (api) => {577578    const tx = api.tx.nft.setTransfersEnabledFlag (collectionId, enabled);579    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;580    const result = getGenericResult(events);581582    expect(result.success).to.be.false;583  });584}585586export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {587  await usingApi(async (api) => {588    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);589    const events = await submitTransactionAsync(sender, tx);590    const result = getGenericResult(events);591592    expect(result.success).to.be.true;593  });594}595596export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {597  await usingApi(async (api) => {598    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);599    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;600    const result = getGenericResult(events);601602    expect(result.success).to.be.false;603  });604}605606export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, value = true) {607  await usingApi(async (api) => {608    const tx = api.tx.nft.toggleContractWhiteList(contractAddress, value);609    const events = await submitTransactionAsync(sender, tx);610    const result = getGenericResult(events);611612    expect(result.success).to.be.true;613  });614}615616export async function isWhitelistedInContract(contractAddress: AccountId | string, user: string) {617  let whitelisted = false;618  await usingApi(async (api) => {619    whitelisted = (await api.query.nft.contractWhiteList(contractAddress, user)).toJSON() as boolean;620  });621  return whitelisted;622}623624export async function addToContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {625  await usingApi(async (api) => {626    const tx = api.tx.nft.addToContractWhiteList(contractAddress.toString(), user.toString());627    const events = await submitTransactionAsync(sender, tx);628    const result = getGenericResult(events);629630    expect(result.success).to.be.true;631  });632}633634export async function removeFromContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {635  await usingApi(async (api) => {636    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());637    const events = await submitTransactionAsync(sender, tx);638    const result = getGenericResult(events);639640    expect(result.success).to.be.true;641  });642}643644export async function removeFromContractWhiteListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {645  await usingApi(async (api) => {646    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());647    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;648    const result = getGenericResult(events);649650    expect(result.success).to.be.false;651  });652}653654export async function setVariableMetaDataExpectSuccess(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {655  await usingApi(async (api) => {656    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));657    const events = await submitTransactionAsync(sender, tx);658    const result = getGenericResult(events);659660    expect(result.success).to.be.true;661  });662}663664export async function setVariableMetaDataExpectFailure(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {665  await usingApi(async (api) => {666    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));667    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;668  });669}670671export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {672  await usingApi(async (api) => {673    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));674    const events = await submitTransactionAsync(sender, tx);675    const result = getGenericResult(events);676677    expect(result.success).to.be.true;678  });679}680681export async function setOffchainSchemaExpectFailure(sender: IKeyringPair, collectionId: number, data: number[]) {682  await usingApi(async (api) => {683    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));684    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;685  });686}687688export interface CreateFungibleData {689  readonly Value: bigint;690}691692export interface CreateReFungibleData { }693export interface CreateNftData { }694695export type CreateItemData = {696  NFT: CreateNftData;697} | {698  Fungible: CreateFungibleData;699} | {700  ReFungible: CreateReFungibleData;701};702703export async function burnItemExpectSuccess(owner: IKeyringPair, collectionId: number, tokenId: number, value = 0) {704  await usingApi(async (api) => {705    const tx = api.tx.nft.burnItem(collectionId, tokenId, value);706    const events = await submitTransactionAsync(owner, tx);707    const result = getGenericResult(events);708    // Get the item709    const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();710    // What to expect711    // tslint:disable-next-line:no-unused-expression712    expect(result.success).to.be.true;713    // tslint:disable-next-line:no-unused-expression714    expect(item).to.be.null;715  });716}717718export async function719approveExpectSuccess(720  collectionId: number,721  tokenId: number, owner: IKeyringPair, approved: IKeyringPair | CrossAccountId | string, amount: number | bigint = 1,722) {723  await usingApi(async (api: ApiPromise) => {724    approved = normalizeAccountId(approved);725    const allowanceBefore =726      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;727    const approveNftTx = api.tx.nft.approve(approved, collectionId, tokenId, amount);728    const events = await submitTransactionAsync(owner, approveNftTx);729    const result = getCreateItemResult(events);730    // tslint:disable-next-line:no-unused-expression731    expect(result.success).to.be.true;732    const allowanceAfter =733      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;734    expect(allowanceAfter.sub(allowanceBefore).toString()).to.be.equal(amount.toString());735  });736}737738export async function739transferFromExpectSuccess(740  collectionId: number,741  tokenId: number,742  accountApproved: IKeyringPair,743  accountFrom: IKeyringPair | CrossAccountId,744  accountTo: IKeyringPair | CrossAccountId,745  value: number | bigint = 1,746  type = 'NFT',747) {748  await usingApi(async (api: ApiPromise) => {749    const to = normalizeAccountId(accountTo);750    let balanceBefore = new BN(0);751    if (type === 'Fungible') {752      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;753    }754    const transferFromTx = api.tx.nft.transferFrom(normalizeAccountId(accountFrom), to, collectionId, tokenId, value);755    const events = await submitTransactionAsync(accountApproved, transferFromTx);756    const result = getCreateItemResult(events);757    // tslint:disable-next-line:no-unused-expression758    expect(result.success).to.be.true;759    if (type === 'NFT') {760      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON() as ITokenDataType;761      expect(nftItemData.Owner).to.be.deep.equal(to);762    }763    if (type === 'Fungible') {764      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;765      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());766    }767    if (type === 'ReFungible') {768      const nftItemData =769        (await api.query.nft.reFungibleItemList(collectionId, tokenId) as any).toJSON() as IReFungibleTokenDataType;770      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(normalizeAccountId(to));771      expect(nftItemData.Owner[0].Fraction).to.be.equal(value);772    }773  });774}775776export async function777transferFromExpectFail(778  collectionId: number,779  tokenId: number,780  accountApproved: IKeyringPair,781  accountFrom: IKeyringPair,782  accountTo: IKeyringPair,783  value: number | bigint = 1,784) {785  await usingApi(async (api: ApiPromise) => {786    const transferFromTx = api.tx.nft.transferFrom(normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);787    const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;788    const result = getCreateCollectionResult(events);789    // tslint:disable-next-line:no-unused-expression790    expect(result.success).to.be.false;791  });792}793794/* eslint no-async-promise-executor: "off" */795async function getBlockNumber(api: ApiPromise): Promise<number> {796  return new Promise<number>(async (resolve) => {797    const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {798      unsubscribe();799      resolve(head.number.toNumber());800    });801  });802}803804export async function addCollectionAdminExpectSuccess(sender: IKeyringPair, collectionId: number, address: IKeyringPair) {805  await usingApi(async (api) => {806    const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, normalizeAccountId(address.address));807    const events = await submitTransactionAsync(sender, changeAdminTx);808    const result = getCreateCollectionResult(events);809    expect(result.success).to.be.true;810  });811}812813export async function814getFreeBalance(account: IKeyringPair) : Promise<BigNumber>815{816  let balance = new BigNumber(0) ;817  await usingApi(async (api) => { 818    balance = new BigNumber((await api.query.system.account(account.address)).data.free.toString());  819  });820821  return balance;822}823824export async function825scheduleTransferExpectSuccess(826  collectionId: number,827  tokenId: number,828  sender: IKeyringPair,829  recipient: IKeyringPair,830  value: number | bigint = 1,831  blockTimeMs: number,832  blockSchedule: number,833) {834  await usingApi(async (api: ApiPromise) => {835    const blockNumber: number | undefined = await getBlockNumber(api);836    const expectedBlockNumber = blockNumber + blockSchedule;837838    expect(blockNumber).to.be.greaterThan(0);839    const transferTx = await api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);840    const scheduleTx = await api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx);841842    await submitTransactionAsync(sender, scheduleTx);843844    const recipientBalanceBefore = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());845846    const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as any as ITokenDataType;847    expect(toSubstrateAddress(nftItemDataBefore.Owner)).to.be.equal(sender.address);848849    // sleep for 4 blocks850    await new Promise(resolve => setTimeout(resolve, blockTimeMs * (blockSchedule + 1)));851852    const recipientBalanceAfter = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());853854    const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;855    expect(toSubstrateAddress(nftItemData.Owner)).to.be.equal(recipient.address);856    expect(recipientBalanceAfter.toNumber()).to.be.equal(recipientBalanceBefore.toNumber());857  });858}859860861export async function862transferExpectSuccess(863  collectionId: number,864  tokenId: number,865  sender: IKeyringPair,866  recipient: IKeyringPair | CrossAccountId,867  value: number | bigint = 1,868  type = 'NFT',869) {870  await usingApi(async (api: ApiPromise) => {871    const to = normalizeAccountId(recipient);872873    let balanceBefore = new BN(0);874    if (type === 'Fungible') {875      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;876    }877    const transferTx = api.tx.nft.transfer(to, collectionId, tokenId, value);878    const events = await submitTransactionAsync(sender, transferTx);879    const result = getTransferResult(events);880    // tslint:disable-next-line:no-unused-expression881    expect(result.success).to.be.true;882    expect(result.collectionId).to.be.equal(collectionId);883    expect(result.itemId).to.be.equal(tokenId);884    expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));885    expect(result.recipient).to.be.deep.equal(to);886    expect(result.value.toString()).to.be.equal(value.toString());887    if (type === 'NFT') {888      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;889      expect(nftItemData.Owner).to.be.deep.equal(to);890    }891    if (type === 'Fungible') {892      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;893      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());894    }895    if (type === 'ReFungible') {896      const nftItemData =897        (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;898      const expectedOwner = toSubstrateAddress(to);899      const ownerIndex = nftItemData.Owner.findIndex(v => toSubstrateAddress(v.Owner as any as string) == expectedOwner);900      expect(ownerIndex).to.not.equal(-1);901      expect(nftItemData.Owner[ownerIndex].Owner).to.be.deep.equal(normalizeAccountId(to));902      expect(nftItemData.Owner[ownerIndex].Fraction).to.be.greaterThanOrEqual(value as number);903    }904  });905}906907export async function908transferExpectFailure(909  collectionId: number,910  tokenId: number,911  sender: IKeyringPair,912  recipient: IKeyringPair,913  value: number | bigint = 1,914) {915  await usingApi(async (api: ApiPromise) => {916    const transferTx = api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);917    const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;918    if (events && Array.isArray(events)) {919      const result = getCreateCollectionResult(events);920      // tslint:disable-next-line:no-unused-expression921      expect(result.success).to.be.false;922    }923  });924}925926export async function927approveExpectFail(928  collectionId: number,929  tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1,930) {931  await usingApi(async (api: ApiPromise) => {932    const approveNftTx = api.tx.nft.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);933    const events = await expect(submitTransactionExpectFailAsync(owner, approveNftTx)).to.be.rejected;934    const result = getCreateCollectionResult(events);935    // tslint:disable-next-line:no-unused-expression936    expect(result.success).to.be.false;937  });938}939940export async function getFungibleBalance(941  collectionId: number,942  owner: string,943) {944  return await usingApi(async (api) => {945    const response = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON() as unknown as { Value: string };946    return BigInt(response.Value);947  });948}949950export async function createFungibleItemExpectSuccess(951  sender: IKeyringPair,952  collectionId: number,953  data: CreateFungibleData,954  owner: CrossAccountId | string = sender.address,955) {956  return await usingApi(async (api) => {957    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), { Fungible: data });958959    const events = await submitTransactionAsync(sender, tx);960    const result = getCreateItemResult(events);961962    expect(result.success).to.be.true;963    return result.itemId;964  });965}966967export async function createItemExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {968  let newItemId = 0;969  await usingApi(async (api) => {970    const to = normalizeAccountId(owner);971    const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);972    const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();973    const AItemBalance = new BigNumber(Aitem.Value);974975    let tx;976    if (createMode === 'Fungible') {977      const createData = { fungible: { value: 10 } };978      tx = api.tx.nft.createItem(collectionId, to, createData);979    } else if (createMode === 'ReFungible') {980      const createData = { refungible: { const_data: [], variable_data: [], pieces: 100 } };981      tx = api.tx.nft.createItem(collectionId, to, createData);982    } else {983      const createData = { nft: { const_data: [], variable_data: [] } };984      tx = api.tx.nft.createItem(collectionId, to, createData);985    }986987    const events = await submitTransactionAsync(sender, tx);988    const result = getCreateItemResult(events);989990    const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);991    const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();992    const BItemBalance = new BigNumber(Bitem.Value);993994    // What to expect995    // tslint:disable-next-line:no-unused-expression996    expect(result.success).to.be.true;997    if (createMode === 'Fungible') {998      expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10);999    } else {1000      expect(BItemCount).to.be.equal(AItemCount + 1);1001    }1002    expect(collectionId).to.be.equal(result.collectionId);1003    expect(BItemCount.toString()).to.be.equal(result.itemId.toString());1004    expect(to).to.be.deep.equal(result.recipient);1005    newItemId = result.itemId;1006  });1007  return newItemId;1008}10091010export async function createItemExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, owner: string = sender.address) {1011  await usingApi(async (api) => {1012    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), createMode);10131014    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1015    const result = getCreateItemResult(events);10161017    expect(result.success).to.be.false;1018  });1019}10201021export async function setPublicAccessModeExpectSuccess(1022  sender: IKeyringPair, collectionId: number,1023  accessMode: 'Normal' | 'WhiteList',1024) {1025  await usingApi(async (api) => {10261027    // Run the transaction1028    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);1029    const events = await submitTransactionAsync(sender, tx);1030    const result = getGenericResult(events);10311032    // Get the collection1033    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();10341035    // What to expect1036    // tslint:disable-next-line:no-unused-expression1037    expect(result.success).to.be.true;1038    expect(collection.Access).to.be.equal(accessMode);1039  });1040}10411042export async function setPublicAccessModeExpectFail(1043  sender: IKeyringPair, collectionId: number,1044  accessMode: 'Normal' | 'WhiteList',1045) {1046  await usingApi(async (api) => {10471048    // Run the transaction1049    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);1050    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1051    const result = getGenericResult(events);10521053    // What to expect1054    // tslint:disable-next-line:no-unused-expression1055    expect(result.success).to.be.false;1056  });1057}10581059export async function enableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {1060  await setPublicAccessModeExpectSuccess(sender, collectionId, 'WhiteList');1061}10621063export async function enableWhiteListExpectFail(sender: IKeyringPair, collectionId: number) {1064  await setPublicAccessModeExpectFail(sender, collectionId, 'WhiteList');1065}10661067export async function disableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {1068  await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');1069}10701071export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {1072  await usingApi(async (api) => {10731074    // Run the transaction1075    const tx = api.tx.nft.setMintPermission(collectionId, enabled);1076    const events = await submitTransactionAsync(sender, tx);1077    const result = getGenericResult(events);10781079    // Get the collection1080    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();10811082    // What to expect1083    // tslint:disable-next-line:no-unused-expression1084    expect(result.success).to.be.true;1085    expect(collection.MintMode).to.be.equal(enabled);1086  });1087}10881089export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {1090  await setMintPermissionExpectSuccess(sender, collectionId, true);1091}10921093export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {1094  await usingApi(async (api) => {1095    // Run the transaction1096    const tx = api.tx.nft.setMintPermission(collectionId, enabled);1097    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1098    const result = getCreateCollectionResult(events);1099    // tslint:disable-next-line:no-unused-expression1100    expect(result.success).to.be.false;1101  });1102}11031104export async function setChainLimitsExpectFailure(sender: IKeyringPair, limits: IChainLimits) {1105  await usingApi(async (api) => {1106    // Run the transaction1107    const tx = api.tx.nft.setChainLimits(limits);1108    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1109    const result = getCreateCollectionResult(events);1110    // tslint:disable-next-line:no-unused-expression1111    expect(result.success).to.be.false;1112  });1113}11141115export async function isWhitelisted(collectionId: number, address: string) {1116  let whitelisted = false;1117  await usingApi(async (api) => {1118    whitelisted = (await api.query.nft.whiteList(collectionId, address)).toJSON() as unknown as boolean;1119  });1120  return whitelisted;1121}11221123export async function addToWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1124  await usingApi(async (api) => {11251126    const whiteListedBefore = (await api.query.nft.whiteList(collectionId, address)).toJSON();11271128    // Run the transaction1129    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1130    const events = await submitTransactionAsync(sender, tx);1131    const result = getGenericResult(events);11321133    const whiteListedAfter = (await api.query.nft.whiteList(collectionId, address)).toJSON();11341135    // What to expect1136    // tslint:disable-next-line:no-unused-expression1137    expect(result.success).to.be.true;1138    // tslint:disable-next-line: no-unused-expression1139    expect(whiteListedBefore).to.be.false;1140    // tslint:disable-next-line: no-unused-expression1141    expect(whiteListedAfter).to.be.true;1142  });1143}11441145export async function addToWhiteListExpectFail(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1146  await usingApi(async (api) => {1147    // Run the transaction1148    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1149    const events = await expect(submitTransactionAsync(sender, tx)).to.be.rejected;1150    const result = getGenericResult(events);11511152    // What to expect1153    // tslint:disable-next-line:no-unused-expression1154    expect(result.success).to.be.false;1155  });1156}11571158export async function removeFromWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1159  await usingApi(async (api) => {1160    // Run the transaction1161    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1162    const events = await submitTransactionAsync(sender, tx);1163    const result = getGenericResult(events);11641165    // What to expect1166    // tslint:disable-next-line:no-unused-expression1167    expect(result.success).to.be.true;1168  });1169}11701171export async function removeFromWhiteListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1172  await usingApi(async (api) => {1173    // Run the transaction1174    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1175    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1176    const result = getGenericResult(events);11771178    // What to expect1179    // tslint:disable-next-line:no-unused-expression1180    expect(result.success).to.be.false;1181  });1182}11831184export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)1185  : Promise<ICollectionInterface | null> => {1186  return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1187};11881189export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {1190  // set global object - collectionsCount1191  return (await api.query.nft.createdCollectionCount() as unknown as BN).toNumber();1192};11931194export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {1195  return await usingApi(async (api) => {1196    return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1197  });1198}11991200export async function queryNftOwner(api: ApiPromise, collectionId: number, tokenId: number): Promise<CrossAccountId> {1201  return normalizeAccountId((await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON().Owner);1202}12031204export async function waitNewBlocks(blocksCount = 1): Promise<void> {1205  await usingApi(async (api) => {1206    const promise = new Promise<void>(async (resolve) => {1207      const unsubscribe = await api.rpc.chain.subscribeNewHeads(() => {1208        if (blocksCount > 0) {1209          blocksCount--;1210        } else {1211          unsubscribe();1212          resolve();1213        }1214      });1215    });1216    return promise;1217  });1218}
after · tests/src/util/helpers.ts
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56import { ApiPromise, Keyring } from '@polkadot/api';7import type { AccountId, EventRecord } from '@polkadot/types/interfaces';8import { IKeyringPair } from '@polkadot/types/types';9import { evmToAddress } from '@polkadot/util-crypto';10import { BigNumber } from 'bignumber.js';11import BN from 'bn.js';12import chai from 'chai';13import chaiAsPromised from 'chai-as-promised';14import { alicesPublicKey } from '../accounts';15import privateKey from '../substrate/privateKey';16import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api';17import { ICollectionInterface } from '../types';18import { hexToStr, strToUTF16, utf16ToStr } from './util';1920chai.use(chaiAsPromised);21const expect = chai.expect;2223export type CrossAccountId = {24  substrate: string,25} | {26  ethereum: string,27};28export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {29  if (typeof input === 'string')30    return { substrate: input };31  if ('address' in input) {32    return { substrate: input.address };33  }34  if ('ethereum' in input) {35    input.ethereum = input.ethereum.toLowerCase();36    return input;37  }38  if ('substrate' in input) {39    return input;40  }4142  // AccountId43  return {substrate: input.toString()};44}45export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {46  input = normalizeAccountId(input);47  if ('substrate' in input) {48    return input.substrate;49  } else {50    return evmToAddress(input.ethereum);51  }52}5354export const U128_MAX = (1n << 128n) - 1n;5556const MICROUNIQUE = 1_000_000_000n;57const MILLIUNIQUE = 1_000n * MICROUNIQUE;58const CENTIUNIQUE = 10n * MILLIUNIQUE;59export const UNIQUE = 100n * CENTIUNIQUE;6061type GenericResult = {62  success: boolean,63};6465interface CreateCollectionResult {66  success: boolean;67  collectionId: number;68}6970interface CreateItemResult {71  success: boolean;72  collectionId: number;73  itemId: number;74  recipient?: CrossAccountId;75}7677interface TransferResult {78  success: boolean;79  collectionId: number;80  itemId: number;81  sender?: CrossAccountId;82  recipient?: CrossAccountId;83  value: bigint;84}8586interface IReFungibleOwner {87  Fraction: BN;88  Owner: number[];89}9091interface ITokenDataType {92  Owner: IKeyringPair;93  ConstData: number[];94  VariableData: number[];95}9697interface IGetMessage {98  checkMsgNftMethod: string;99  checkMsgTrsMethod: string;100  checkMsgSysMethod: string;101}102103export interface IFungibleTokenDataType {104  Value: number;105}106107export interface IChainLimits {108  CollectionNumbersLimit: number;109	AccountTokenOwnershipLimit: number;110	CollectionsAdminsLimit: number;111	CustomDataLimit: number;112	NftSponsorTransferTimeout: number;113	FungibleSponsorTransferTimeout: number;114	RefungibleSponsorTransferTimeout: number;115	OffchainSchemaLimit: number;116	VariableOnChainSchemaLimit: number;117	ConstOnChainSchemaLimit: number;118}119120export interface IReFungibleTokenDataType {121  Owner: IReFungibleOwner[];122  ConstData: number[];123  VariableData: number[];124}125126export function nftEventMessage(events: EventRecord[]): IGetMessage {127  let checkMsgNftMethod = '';128  let checkMsgTrsMethod = '';129  let checkMsgSysMethod = '';130  events.forEach(({ event: { method, section } }) => {131    if (section === 'nft') {132      checkMsgNftMethod = method;133    } else if (section === 'treasury') {134      checkMsgTrsMethod = method;135    } else if (section === 'system') {136      checkMsgSysMethod = method;137    } else { return null; }138  });139  const result: IGetMessage = {140    checkMsgNftMethod,141    checkMsgTrsMethod,142    checkMsgSysMethod,143  };144  return result;145}146147export function getGenericResult(events: EventRecord[]): GenericResult {148  const result: GenericResult = {149    success: false,150  };151  events.forEach(({ event: { method } }) => {152    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);153    if (method === 'ExtrinsicSuccess') {154      result.success = true;155    }156  });157  return result;158}159160161162export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {163  let success = false;164  let collectionId = 0;165  events.forEach(({ event: { data, method, section } }) => {166    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);167    if (method == 'ExtrinsicSuccess') {168      success = true;169    } else if ((section == 'nft') && (method == 'CollectionCreated')) {170      collectionId = parseInt(data[0].toString());171    }172  });173  const result: CreateCollectionResult = {174    success,175    collectionId,176  };177  return result;178}179180export function getCreateItemResult(events: EventRecord[]): CreateItemResult {181  let success = false;182  let collectionId = 0;183  let itemId = 0;184  let recipient;185  events.forEach(({ event: { data, method, section } }) => {186    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);187    if (method == 'ExtrinsicSuccess') {188      success = true;189    } else if ((section == 'nft') && (method == 'ItemCreated')) {190      collectionId = parseInt(data[0].toString());191      itemId = parseInt(data[1].toString());192      recipient = data[2].toJSON();193    }194  });195  const result: CreateItemResult = {196    success,197    collectionId,198    itemId,199    recipient,200  };201  return result;202}203204export function getTransferResult(events: EventRecord[]): TransferResult {205  const result: TransferResult = {206    success: false,207    collectionId: 0,208    itemId: 0,209    value: 0n,210  };211212  events.forEach(({ event: { data, method, section } }) => {213    if (method === 'ExtrinsicSuccess') {214      result.success = true;215    } else if (section === 'nft' && method === 'Transfer') {216      result.collectionId = +data[0].toString();217      result.itemId = +data[1].toString();218      result.sender = data[2].toJSON() as CrossAccountId;219      result.recipient = data[3].toJSON() as CrossAccountId;220      result.value = BigInt(data[4].toString());221    }222  });223224  return result;225}226227interface Nft {228  type: 'NFT';229}230231interface Fungible {232  type: 'Fungible';233  decimalPoints: number;234}235236interface ReFungible {237  type: 'ReFungible';238}239240type CollectionMode = Nft | Fungible | ReFungible;241242export type CreateCollectionParams = {243  mode: CollectionMode,244  name: string,245  description: string,246  tokenPrefix: string,247};248249const defaultCreateCollectionParams: CreateCollectionParams = {250  description: 'description',251  mode: { type: 'NFT' },252  name: 'name',253  tokenPrefix: 'prefix',254};255256export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {257  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };258259  let collectionId = 0;260  await usingApi(async (api) => {261    // Get number of collections before the transaction262    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);263264    // Run the CreateCollection transaction265    const alicePrivateKey = privateKey('//Alice');266267    let modeprm = {};268    if (mode.type === 'NFT') {269      modeprm = { nft: null };270    } else if (mode.type === 'Fungible') {271      modeprm = { fungible: mode.decimalPoints };272    } else if (mode.type === 'ReFungible') {273      modeprm = { refungible: null };274    }275276    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);277    const events = await submitTransactionAsync(alicePrivateKey, tx);278    const result = getCreateCollectionResult(events);279280    // Get number of collections after the transaction281    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);282283    // Get the collection284    const collection: any = (await api.query.nft.collectionById(result.collectionId) as any).toJSON();285286    // What to expect287    // tslint:disable-next-line:no-unused-expression288    expect(result.success).to.be.true;289    expect(result.collectionId).to.be.equal(BcollectionCount);290    // tslint:disable-next-line:no-unused-expression291    expect(collection).to.be.not.null;292    expect(BcollectionCount).to.be.equal(AcollectionCount + 1, 'Error: NFT collection NOT created.');293    expect(collection.Owner).to.be.equal(toSubstrateAddress(alicesPublicKey));294    expect(utf16ToStr(collection.Name)).to.be.equal(name);295    expect(utf16ToStr(collection.Description)).to.be.equal(description);296    expect(hexToStr(collection.TokenPrefix)).to.be.equal(tokenPrefix);297298    collectionId = result.collectionId;299  });300301  return collectionId;302}303304export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {305  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };306307  let modeprm = {};308  if (mode.type === 'NFT') {309    modeprm = { nft: null };310  } else if (mode.type === 'Fungible') {311    modeprm = { fungible: mode.decimalPoints };312  } else if (mode.type === 'ReFungible') {313    modeprm = { refungible: null };314  }315316  await usingApi(async (api) => {317    // Get number of collections before the transaction318    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());319320    // Run the CreateCollection transaction321    const alicePrivateKey = privateKey('//Alice');322    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);323    const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;324    const result = getCreateCollectionResult(events);325326    // Get number of collections after the transaction327    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());328329    // What to expect330    // tslint:disable-next-line:no-unused-expression331    expect(result.success).to.be.false;332    expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');333  });334}335336export async function findUnusedAddress(api: ApiPromise, seedAddition = ''): Promise<IKeyringPair> {337  let bal = new BigNumber(0);338  let unused;339  do {340    const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;341    const keyring = new Keyring({ type: 'sr25519' });342    unused = keyring.addFromUri(`//${randomSeed}`);343    bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());344  } while (bal.toFixed() != '0');345  return unused;346}347348export async function getAllowance(collectionId: number, tokenId: number, owner: string, approved: string) {349  return await usingApi(async (api) => {350    const bn = await api.query.nft.allowances(collectionId, [tokenId, owner, approved]) as unknown as BN;351    return BigInt(bn.toString());352  });353}354355export function findUnusedAddresses(api: ApiPromise, amount: number): Promise<IKeyringPair[]> {356  return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, '_' + Date.now())));357}358359export async function findNotExistingCollection(api: ApiPromise): Promise<number> {360  const totalNumber = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10) as unknown as number;361  const newCollection: number = totalNumber + 1;362  return newCollection;363}364365function getDestroyResult(events: EventRecord[]): boolean {366  let success = false;367  events.forEach(({ event: { method } }) => {368    if (method == 'ExtrinsicSuccess') {369      success = true;370    }371  });372  return success;373}374375export async function destroyCollectionExpectFailure(collectionId: number, senderSeed = '//Alice') {376  await usingApi(async (api) => {377    // Run the DestroyCollection transaction378    const alicePrivateKey = privateKey(senderSeed);379    const tx = api.tx.nft.destroyCollection(collectionId);380    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;381  });382}383384export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed = '//Alice') {385  await usingApi(async (api) => {386    // Run the DestroyCollection transaction387    const alicePrivateKey = privateKey(senderSeed);388    const tx = api.tx.nft.destroyCollection(collectionId);389    const events = await submitTransactionAsync(alicePrivateKey, tx);390    const result = getDestroyResult(events);391392    // Get the collection393    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();394395    // What to expect396    expect(result).to.be.true;397    expect(collection).to.be.null;398  });399}400401export async function queryCollectionLimits(collectionId: number) {402  return await usingApi(async (api) => {403    return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;404  });405}406407export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {408  await usingApi(async (api) => {409    const oldLimits = await queryCollectionLimits(collectionId);410    const newLimits = { ...oldLimits as any, ...limits };411    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);412    const events = await submitTransactionAsync(sender, tx);413    const result = getGenericResult(events);414415    expect(result.success).to.be.true;416  });417}418419export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) {420  await usingApi(async (api) => {421    const oldLimits = await queryCollectionLimits(collectionId);422    const newLimits = { ...oldLimits as any, ...limits };423    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);424    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;425    const result = getGenericResult(events);426427    expect(result.success).to.be.false;428  });429}430431export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string, sender = '//Alice') {432  await usingApi(async (api) => {433434    // Run the transaction435    const senderPrivateKey = privateKey(sender);436    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);437    const events = await submitTransactionAsync(senderPrivateKey, tx);438    const result = getGenericResult(events);439440    // Get the collection441    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();442443    // What to expect444    expect(result.success).to.be.true;445    expect(collection.Sponsorship).to.deep.equal({446      unconfirmed: sponsor,447    });448  });449}450451export async function removeCollectionSponsorExpectSuccess(collectionId: number, sender = '//Alice') {452  await usingApi(async (api) => {453454    // Run the transaction455    const alicePrivateKey = privateKey(sender);456    const tx = api.tx.nft.removeCollectionSponsor(collectionId);457    const events = await submitTransactionAsync(alicePrivateKey, tx);458    const result = getGenericResult(events);459460    // Get the collection461    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();462463    // What to expect464    expect(result.success).to.be.true;465    expect(collection.Sponsorship).to.be.deep.equal({ disabled: null });466  });467}468469export async function removeCollectionSponsorExpectFailure(collectionId: number, senderSeed = '//Alice') {470  await usingApi(async (api) => {471472    // Run the transaction473    const alicePrivateKey = privateKey(senderSeed);474    const tx = api.tx.nft.removeCollectionSponsor(collectionId);475    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;476  });477}478479export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed = '//Alice') {480  await usingApi(async (api) => {481482    // Run the transaction483    const alicePrivateKey = privateKey(senderSeed);484    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);485    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;486  });487}488489export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed = '//Alice') {490  await usingApi(async (api) => {491492    // Run the transaction493    const sender = privateKey(senderSeed);494    const tx = api.tx.nft.confirmSponsorship(collectionId);495    const events = await submitTransactionAsync(sender, tx);496    const result = getGenericResult(events);497498    // Get the collection499    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();500501    // What to expect502    expect(result.success).to.be.true;503    expect(collection.Sponsorship).to.be.deep.equal({504      confirmed: sender.address,505    });506  });507}508509510export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed = '//Alice') {511  await usingApi(async (api) => {512513    // Run the transaction514    const sender = privateKey(senderSeed);515    const tx = api.tx.nft.confirmSponsorship(collectionId);516    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;517  });518}519520export async function setMetadataUpdatePermissionFlagExpectSuccess(sender: IKeyringPair, collectionId: number, flag: string) {521522  await usingApi(async (api) => {523    const tx = api.tx.nft.setMetaUpdatePermissionFlag(collectionId, flag);524    const events = await submitTransactionAsync(sender, tx);525    const result = getGenericResult(events);526527    expect(result.success).to.be.true;528  });529}530531export async function setMetadataUpdatePermissionFlagExpectFailure(sender: IKeyringPair, collectionId: number, flag: string) {532533  await usingApi(async (api) => {534    const tx = api.tx.nft.setMetaUpdatePermissionFlag(collectionId, flag);535    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;536    const result = getGenericResult(events);537538    expect(result.success).to.be.false;539  });540}541542export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {543  await usingApi(async (api) => {544    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);545    const events = await submitTransactionAsync(sender, tx);546    const result = getGenericResult(events);547548    expect(result.success).to.be.true;549  });550}551552export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {553  await usingApi(async (api) => {554    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);555    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;556    const result = getGenericResult(events);557558    expect(result.success).to.be.false;559  });560}561562export async function setTransferFlagExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {563564  await usingApi(async (api) => {565566    const tx = api.tx.nft.setTransfersEnabledFlag (collectionId, enabled);567    const events = await submitTransactionAsync(sender, tx);568    const result = getGenericResult(events);569570    expect(result.success).to.be.true;571  });572}573574export async function setTransferFlagExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {575576  await usingApi(async (api) => {577578    const tx = api.tx.nft.setTransfersEnabledFlag (collectionId, enabled);579    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;580    const result = getGenericResult(events);581582    expect(result.success).to.be.false;583  });584}585586export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {587  await usingApi(async (api) => {588    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);589    const events = await submitTransactionAsync(sender, tx);590    const result = getGenericResult(events);591592    expect(result.success).to.be.true;593  });594}595596export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {597  await usingApi(async (api) => {598    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);599    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;600    const result = getGenericResult(events);601602    expect(result.success).to.be.false;603  });604}605606export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, value = true) {607  await usingApi(async (api) => {608    const tx = api.tx.nft.toggleContractWhiteList(contractAddress, value);609    const events = await submitTransactionAsync(sender, tx);610    const result = getGenericResult(events);611612    expect(result.success).to.be.true;613  });614}615616export async function isWhitelistedInContract(contractAddress: AccountId | string, user: string) {617  let whitelisted = false;618  await usingApi(async (api) => {619    whitelisted = (await api.query.nft.contractWhiteList(contractAddress, user)).toJSON() as boolean;620  });621  return whitelisted;622}623624export async function addToContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {625  await usingApi(async (api) => {626    const tx = api.tx.nft.addToContractWhiteList(contractAddress.toString(), user.toString());627    const events = await submitTransactionAsync(sender, tx);628    const result = getGenericResult(events);629630    expect(result.success).to.be.true;631  });632}633634export async function removeFromContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {635  await usingApi(async (api) => {636    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());637    const events = await submitTransactionAsync(sender, tx);638    const result = getGenericResult(events);639640    expect(result.success).to.be.true;641  });642}643644export async function removeFromContractWhiteListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {645  await usingApi(async (api) => {646    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());647    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;648    const result = getGenericResult(events);649650    expect(result.success).to.be.false;651  });652}653654export async function setVariableMetaDataExpectSuccess(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {655  await usingApi(async (api) => {656    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));657    const events = await submitTransactionAsync(sender, tx);658    const result = getGenericResult(events);659660    expect(result.success).to.be.true;661  });662}663664export async function setVariableMetaDataExpectFailure(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {665  await usingApi(async (api) => {666    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));667    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;668  });669}670671export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {672  await usingApi(async (api) => {673    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));674    const events = await submitTransactionAsync(sender, tx);675    const result = getGenericResult(events);676677    expect(result.success).to.be.true;678  });679}680681export async function setOffchainSchemaExpectFailure(sender: IKeyringPair, collectionId: number, data: number[]) {682  await usingApi(async (api) => {683    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));684    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;685  });686}687688export interface CreateFungibleData {689  readonly Value: bigint;690}691692export interface CreateReFungibleData { }693export interface CreateNftData { }694695export type CreateItemData = {696  NFT: CreateNftData;697} | {698  Fungible: CreateFungibleData;699} | {700  ReFungible: CreateReFungibleData;701};702703export async function burnItemExpectSuccess(sender: IKeyringPair, collectionId: number, tokenId: number, owner: IKeyringPair, value = 0) {704  await usingApi(async (api) => {705    const tx = api.tx.nft.burnItem(collectionId, tokenId, normalizeAccountId(owner.address), value);706    const events = await submitTransactionAsync(sender, tx);707    const result = getGenericResult(events);708    // Get the item709    const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();710    // What to expect711    // tslint:disable-next-line:no-unused-expression712    expect(result.success).to.be.true;713    // tslint:disable-next-line:no-unused-expression714    expect(item).to.be.null;715  });716}717718export async function719approveExpectSuccess(720  collectionId: number,721  tokenId: number, owner: IKeyringPair, approved: IKeyringPair | CrossAccountId | string, amount: number | bigint = 1,722) {723  await usingApi(async (api: ApiPromise) => {724    approved = normalizeAccountId(approved);725    const allowanceBefore =726      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;727    const approveNftTx = api.tx.nft.approve(approved, collectionId, tokenId, amount);728    const events = await submitTransactionAsync(owner, approveNftTx);729    const result = getCreateItemResult(events);730    // tslint:disable-next-line:no-unused-expression731    expect(result.success).to.be.true;732    const allowanceAfter =733      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;734    expect(allowanceAfter.sub(allowanceBefore).toString()).to.be.equal(amount.toString());735  });736}737738export async function739transferFromExpectSuccess(740  collectionId: number,741  tokenId: number,742  accountApproved: IKeyringPair,743  accountFrom: IKeyringPair | CrossAccountId,744  accountTo: IKeyringPair | CrossAccountId,745  value: number | bigint = 1,746  type = 'NFT',747) {748  await usingApi(async (api: ApiPromise) => {749    const to = normalizeAccountId(accountTo);750    let balanceBefore = new BN(0);751    if (type === 'Fungible') {752      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;753    }754    const transferFromTx = api.tx.nft.transferFrom(normalizeAccountId(accountFrom), to, collectionId, tokenId, value);755    const events = await submitTransactionAsync(accountApproved, transferFromTx);756    const result = getCreateItemResult(events);757    // tslint:disable-next-line:no-unused-expression758    expect(result.success).to.be.true;759    if (type === 'NFT') {760      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON() as ITokenDataType;761      expect(nftItemData.Owner).to.be.deep.equal(to);762    }763    if (type === 'Fungible') {764      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;765      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());766    }767    if (type === 'ReFungible') {768      const nftItemData =769        (await api.query.nft.reFungibleItemList(collectionId, tokenId) as any).toJSON() as IReFungibleTokenDataType;770      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(normalizeAccountId(to));771      expect(nftItemData.Owner[0].Fraction).to.be.equal(value);772    }773  });774}775776export async function777transferFromExpectFail(778  collectionId: number,779  tokenId: number,780  accountApproved: IKeyringPair,781  accountFrom: IKeyringPair,782  accountTo: IKeyringPair,783  value: number | bigint = 1,784) {785  await usingApi(async (api: ApiPromise) => {786    const transferFromTx = api.tx.nft.transferFrom(normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);787    const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;788    const result = getCreateCollectionResult(events);789    // tslint:disable-next-line:no-unused-expression790    expect(result.success).to.be.false;791  });792}793794/* eslint no-async-promise-executor: "off" */795async function getBlockNumber(api: ApiPromise): Promise<number> {796  return new Promise<number>(async (resolve) => {797    const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {798      unsubscribe();799      resolve(head.number.toNumber());800    });801  });802}803804export async function addCollectionAdminExpectSuccess(sender: IKeyringPair, collectionId: number, address: IKeyringPair) {805  await usingApi(async (api) => {806    const changeAdminTx = api.tx.nft.addCollectionAdmin(collectionId, normalizeAccountId(address.address));807    const events = await submitTransactionAsync(sender, changeAdminTx);808    const result = getCreateCollectionResult(events);809    expect(result.success).to.be.true;810  });811}812813export async function814getFreeBalance(account: IKeyringPair) : Promise<BigNumber>815{816  let balance = new BigNumber(0) ;817  await usingApi(async (api) => { 818    balance = new BigNumber((await api.query.system.account(account.address)).data.free.toString());  819  });820821  return balance;822}823824export async function825scheduleTransferExpectSuccess(826  collectionId: number,827  tokenId: number,828  sender: IKeyringPair,829  recipient: IKeyringPair,830  value: number | bigint = 1,831  blockTimeMs: number,832  blockSchedule: number,833) {834  await usingApi(async (api: ApiPromise) => {835    const blockNumber: number | undefined = await getBlockNumber(api);836    const expectedBlockNumber = blockNumber + blockSchedule;837838    expect(blockNumber).to.be.greaterThan(0);839    const transferTx = await api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);840    const scheduleTx = await api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx);841842    await submitTransactionAsync(sender, scheduleTx);843844    const recipientBalanceBefore = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());845846    const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as any as ITokenDataType;847    expect(toSubstrateAddress(nftItemDataBefore.Owner)).to.be.equal(sender.address);848849    // sleep for 4 blocks850    await new Promise(resolve => setTimeout(resolve, blockTimeMs * (blockSchedule + 1)));851852    const recipientBalanceAfter = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());853854    const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;855    expect(toSubstrateAddress(nftItemData.Owner)).to.be.equal(recipient.address);856    expect(recipientBalanceAfter.toNumber()).to.be.equal(recipientBalanceBefore.toNumber());857  });858}859860861export async function862transferExpectSuccess(863  collectionId: number,864  tokenId: number,865  sender: IKeyringPair,866  recipient: IKeyringPair | CrossAccountId,867  value: number | bigint = 1,868  type = 'NFT',869) {870  await usingApi(async (api: ApiPromise) => {871    const to = normalizeAccountId(recipient);872873    let balanceBefore = new BN(0);874    if (type === 'Fungible') {875      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;876    }877    const transferTx = api.tx.nft.transfer(to, collectionId, tokenId, value);878    const events = await submitTransactionAsync(sender, transferTx);879    const result = getTransferResult(events);880    // tslint:disable-next-line:no-unused-expression881    expect(result.success).to.be.true;882    expect(result.collectionId).to.be.equal(collectionId);883    expect(result.itemId).to.be.equal(tokenId);884    expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));885    expect(result.recipient).to.be.deep.equal(to);886    expect(result.value.toString()).to.be.equal(value.toString());887    if (type === 'NFT') {888      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;889      expect(nftItemData.Owner).to.be.deep.equal(to);890    }891    if (type === 'Fungible') {892      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;893      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());894    }895    if (type === 'ReFungible') {896      const nftItemData =897        (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;898      const expectedOwner = toSubstrateAddress(to);899      const ownerIndex = nftItemData.Owner.findIndex(v => toSubstrateAddress(v.Owner as any as string) == expectedOwner);900      expect(ownerIndex).to.not.equal(-1);901      expect(nftItemData.Owner[ownerIndex].Owner).to.be.deep.equal(normalizeAccountId(to));902      expect(nftItemData.Owner[ownerIndex].Fraction).to.be.greaterThanOrEqual(value as number);903    }904  });905}906907export async function908transferExpectFailure(909  collectionId: number,910  tokenId: number,911  sender: IKeyringPair,912  recipient: IKeyringPair,913  value: number | bigint = 1,914) {915  await usingApi(async (api: ApiPromise) => {916    const transferTx = api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);917    const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;918    if (events && Array.isArray(events)) {919      const result = getCreateCollectionResult(events);920      // tslint:disable-next-line:no-unused-expression921      expect(result.success).to.be.false;922    }923  });924}925926export async function927approveExpectFail(928  collectionId: number,929  tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1,930) {931  await usingApi(async (api: ApiPromise) => {932    const approveNftTx = api.tx.nft.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);933    const events = await expect(submitTransactionExpectFailAsync(owner, approveNftTx)).to.be.rejected;934    const result = getCreateCollectionResult(events);935    // tslint:disable-next-line:no-unused-expression936    expect(result.success).to.be.false;937  });938}939940export async function getFungibleBalance(941  collectionId: number,942  owner: string,943) {944  return await usingApi(async (api) => {945    const response = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON() as unknown as { Value: string };946    return BigInt(response.Value);947  });948}949950export async function createFungibleItemExpectSuccess(951  sender: IKeyringPair,952  collectionId: number,953  data: CreateFungibleData,954  owner: CrossAccountId | string = sender.address,955) {956  return await usingApi(async (api) => {957    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), { Fungible: data });958959    const events = await submitTransactionAsync(sender, tx);960    const result = getCreateItemResult(events);961962    expect(result.success).to.be.true;963    return result.itemId;964  });965}966967export async function createItemExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {968  let newItemId = 0;969  await usingApi(async (api) => {970    const to = normalizeAccountId(owner);971    const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);972    const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();973    const AItemBalance = new BigNumber(Aitem.Value);974975    let tx;976    if (createMode === 'Fungible') {977      const createData = { fungible: { value: 10 } };978      tx = api.tx.nft.createItem(collectionId, to, createData);979    } else if (createMode === 'ReFungible') {980      const createData = { refungible: { const_data: [], variable_data: [], pieces: 100 } };981      tx = api.tx.nft.createItem(collectionId, to, createData);982    } else {983      const createData = { nft: { const_data: [], variable_data: [] } };984      tx = api.tx.nft.createItem(collectionId, to, createData);985    }986987    const events = await submitTransactionAsync(sender, tx);988    const result = getCreateItemResult(events);989990    const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);991    const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();992    const BItemBalance = new BigNumber(Bitem.Value);993994    // What to expect995    // tslint:disable-next-line:no-unused-expression996    expect(result.success).to.be.true;997    if (createMode === 'Fungible') {998      expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10);999    } else {1000      expect(BItemCount).to.be.equal(AItemCount + 1);1001    }1002    expect(collectionId).to.be.equal(result.collectionId);1003    expect(BItemCount.toString()).to.be.equal(result.itemId.toString());1004    expect(to).to.be.deep.equal(result.recipient);1005    newItemId = result.itemId;1006  });1007  return newItemId;1008}10091010export async function createItemExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, owner: string = sender.address) {1011  await usingApi(async (api) => {1012    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), createMode);10131014    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1015    const result = getCreateItemResult(events);10161017    expect(result.success).to.be.false;1018  });1019}10201021export async function setPublicAccessModeExpectSuccess(1022  sender: IKeyringPair, collectionId: number,1023  accessMode: 'Normal' | 'WhiteList',1024) {1025  await usingApi(async (api) => {10261027    // Run the transaction1028    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);1029    const events = await submitTransactionAsync(sender, tx);1030    const result = getGenericResult(events);10311032    // Get the collection1033    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();10341035    // What to expect1036    // tslint:disable-next-line:no-unused-expression1037    expect(result.success).to.be.true;1038    expect(collection.Access).to.be.equal(accessMode);1039  });1040}10411042export async function setPublicAccessModeExpectFail(1043  sender: IKeyringPair, collectionId: number,1044  accessMode: 'Normal' | 'WhiteList',1045) {1046  await usingApi(async (api) => {10471048    // Run the transaction1049    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);1050    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1051    const result = getGenericResult(events);10521053    // What to expect1054    // tslint:disable-next-line:no-unused-expression1055    expect(result.success).to.be.false;1056  });1057}10581059export async function enableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {1060  await setPublicAccessModeExpectSuccess(sender, collectionId, 'WhiteList');1061}10621063export async function enableWhiteListExpectFail(sender: IKeyringPair, collectionId: number) {1064  await setPublicAccessModeExpectFail(sender, collectionId, 'WhiteList');1065}10661067export async function disableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {1068  await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');1069}10701071export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {1072  await usingApi(async (api) => {10731074    // Run the transaction1075    const tx = api.tx.nft.setMintPermission(collectionId, enabled);1076    const events = await submitTransactionAsync(sender, tx);1077    const result = getGenericResult(events);10781079    // Get the collection1080    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();10811082    // What to expect1083    // tslint:disable-next-line:no-unused-expression1084    expect(result.success).to.be.true;1085    expect(collection.MintMode).to.be.equal(enabled);1086  });1087}10881089export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {1090  await setMintPermissionExpectSuccess(sender, collectionId, true);1091}10921093export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {1094  await usingApi(async (api) => {1095    // Run the transaction1096    const tx = api.tx.nft.setMintPermission(collectionId, enabled);1097    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1098    const result = getCreateCollectionResult(events);1099    // tslint:disable-next-line:no-unused-expression1100    expect(result.success).to.be.false;1101  });1102}11031104export async function setChainLimitsExpectFailure(sender: IKeyringPair, limits: IChainLimits) {1105  await usingApi(async (api) => {1106    // Run the transaction1107    const tx = api.tx.nft.setChainLimits(limits);1108    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1109    const result = getCreateCollectionResult(events);1110    // tslint:disable-next-line:no-unused-expression1111    expect(result.success).to.be.false;1112  });1113}11141115export async function isWhitelisted(collectionId: number, address: string) {1116  let whitelisted = false;1117  await usingApi(async (api) => {1118    whitelisted = (await api.query.nft.whiteList(collectionId, address)).toJSON() as unknown as boolean;1119  });1120  return whitelisted;1121}11221123export async function addToWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1124  await usingApi(async (api) => {11251126    const whiteListedBefore = (await api.query.nft.whiteList(collectionId, address)).toJSON();11271128    // Run the transaction1129    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1130    const events = await submitTransactionAsync(sender, tx);1131    const result = getGenericResult(events);11321133    const whiteListedAfter = (await api.query.nft.whiteList(collectionId, address)).toJSON();11341135    // What to expect1136    // tslint:disable-next-line:no-unused-expression1137    expect(result.success).to.be.true;1138    // tslint:disable-next-line: no-unused-expression1139    expect(whiteListedBefore).to.be.false;1140    // tslint:disable-next-line: no-unused-expression1141    expect(whiteListedAfter).to.be.true;1142  });1143}11441145export async function addToWhiteListExpectFail(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1146  await usingApi(async (api) => {1147    // Run the transaction1148    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1149    const events = await expect(submitTransactionAsync(sender, tx)).to.be.rejected;1150    const result = getGenericResult(events);11511152    // What to expect1153    // tslint:disable-next-line:no-unused-expression1154    expect(result.success).to.be.false;1155  });1156}11571158export async function removeFromWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1159  await usingApi(async (api) => {1160    // Run the transaction1161    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1162    const events = await submitTransactionAsync(sender, tx);1163    const result = getGenericResult(events);11641165    // What to expect1166    // tslint:disable-next-line:no-unused-expression1167    expect(result.success).to.be.true;1168  });1169}11701171export async function removeFromWhiteListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1172  await usingApi(async (api) => {1173    // Run the transaction1174    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1175    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1176    const result = getGenericResult(events);11771178    // What to expect1179    // tslint:disable-next-line:no-unused-expression1180    expect(result.success).to.be.false;1181  });1182}11831184export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)1185  : Promise<ICollectionInterface | null> => {1186  return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1187};11881189export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {1190  // set global object - collectionsCount1191  return (await api.query.nft.createdCollectionCount() as unknown as BN).toNumber();1192};11931194export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {1195  return await usingApi(async (api) => {1196    return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1197  });1198}11991200export async function queryNftOwner(api: ApiPromise, collectionId: number, tokenId: number): Promise<CrossAccountId> {1201  return normalizeAccountId((await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON().Owner);1202}12031204export async function waitNewBlocks(blocksCount = 1): Promise<void> {1205  await usingApi(async (api) => {1206    const promise = new Promise<void>(async (resolve) => {1207      const unsubscribe = await api.rpc.chain.subscribeNewHeads(() => {1208        if (blocksCount > 0) {1209          blocksCount--;1210        } else {1211          unsubscribe();1212          resolve();1213        }1214      });1215    });1216    return promise;1217  });1218}