git.delta.rocks / unique-network / refs/commits / fced7659a53c

difftreelog

Tests can build

Greg Zaitsev2021-06-25parent: #90fcef9.patch.diff
in: master

8 files changed

modifiedCargo.lockdiffbeforeafterboth
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5996,34 +5996,34 @@
 [[package]]
 name = "pallet-scheduler"
 version = "3.0.0"
+source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.3#c94e0cdfe5556680dca1996004751eeb114755d7"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
  "frame-system",
  "log",
  "parity-scale-codec 2.1.3",
- "serde",
- "sp-core",
  "sp-io",
  "sp-runtime",
  "sp-std",
- "substrate-test-utils",
- "up-sponsorship",
 ]
 
 [[package]]
 name = "pallet-scheduler"
 version = "3.0.0"
-source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.3#c94e0cdfe5556680dca1996004751eeb114755d7"
 dependencies = [
  "frame-benchmarking",
  "frame-support",
  "frame-system",
  "log",
  "parity-scale-codec 2.1.3",
+ "serde",
+ "sp-core",
  "sp-io",
  "sp-runtime",
  "sp-std",
+ "substrate-test-utils",
+ "up-sponsorship",
 ]
 
 [[package]]
modifiedlaunch-config.jsondiffbeforeafterboth
--- a/launch-config.json
+++ b/launch-config.json
@@ -45,8 +45,15 @@
                     "nodes": [
                             {
                                     "port": 31200,
+                                    "wsPort": "9944",
                                     "name": "alice",
                                     "flags": []
+                            },
+                            {
+                                    "port": 31201,
+                                    "wsPort": "9945",
+                                    "name": "bob",
+                                    "flags": []
                             }
                     ]
             }
modifiedruntime/src/lib.rsdiffbeforeafterboth
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -216,7 +216,7 @@
 /// by  Operational  extrinsics.
 const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
 /// We allow for 2 seconds of compute with a 6 second average block time.
-const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND;
+const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND / 2;
 
 parameter_types! {
 	pub const BlockHashCount: BlockNumber = 2400;
modifiedtests/src/config.tsdiffbeforeafterboth
--- a/tests/src/config.ts
+++ b/tests/src/config.ts
@@ -6,7 +6,7 @@
 import process from 'process';
 
 const config = {
-  substrateUrl: process.env.substrateUrl || 'ws://127.0.0.1:9844'
+  substrateUrl: process.env.substrateUrl || 'ws://127.0.0.1:9944'
 }
 
 export default config;
\ No newline at end of file
modifiedtests/src/contracts.test.tsdiffbeforeafterboth
--- a/tests/src/contracts.test.ts
+++ b/tests/src/contracts.test.ts
@@ -177,7 +177,7 @@
       const result = getGenericResult(events);
       expect(result.success).to.be.true;
 
-      await transferFromExpectSuccess(collectionId, tokenId, bob, contract.address.toString(), charlie, 1, 'NFT');
+      await transferFromExpectSuccess(collectionId, tokenId, bob, normalizeAccountId(contract.address.toString()), charlie, 1, 'NFT');
     });
   });
 
modifiedtests/src/removeFromWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/removeFromWhiteList.test.ts
+++ b/tests/src/removeFromWhiteList.test.ts
@@ -16,6 +16,7 @@
   findNotExistingCollection,
   removeFromWhiteListExpectFailure,
   disableWhiteListExpectSuccess,
+  normalizeAccountId
 } from './util/helpers';
 import { IKeyringPair } from '@polkadot/types/types';
 import privateKey from './substrate/privateKey';
@@ -40,7 +41,7 @@
       await enableWhiteListExpectSuccess(alice, collectionId);
       await addToWhiteListExpectSuccess(alice, collectionId, bob.address);
 
-      await removeFromWhiteListExpectSuccess(alice, collectionId, bob.address);
+      await removeFromWhiteListExpectSuccess(alice, collectionId, normalizeAccountId(bob.address));
       expect(await isWhitelisted(collectionId, bob.address)).to.be.false;
     });
   });
@@ -52,7 +53,7 @@
       await addToWhiteListExpectSuccess(alice, collectionWithoutWhitelistId, bob.address);
       await disableWhiteListExpectSuccess(alice, collectionWithoutWhitelistId);
 
-      await removeFromWhiteListExpectSuccess(alice, collectionWithoutWhitelistId, bob.address);
+      await removeFromWhiteListExpectSuccess(alice, collectionWithoutWhitelistId, normalizeAccountId(bob.address));
     });
   });
 });
@@ -72,7 +73,7 @@
     await usingApi(async (api) => {
       const collectionId = await findNotExistingCollection(api);
 
-      await removeFromWhiteListExpectFailure(alice, collectionId, bob.address);
+      await removeFromWhiteListExpectFailure(alice, collectionId, normalizeAccountId(bob.address));
     });
   });
 
@@ -83,7 +84,7 @@
       await addToWhiteListExpectSuccess(alice, collectionId, bob.address);
       await destroyCollectionExpectSuccess(collectionId);
 
-      await removeFromWhiteListExpectFailure(alice, collectionId, bob.address);
+      await removeFromWhiteListExpectFailure(alice, collectionId, normalizeAccountId(bob.address));
     });
   });
 });
modifiedtests/src/toggleContractWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/toggleContractWhiteList.test.ts
+++ b/tests/src/toggleContractWhiteList.test.ts
@@ -45,14 +45,14 @@
       const [contract, deployer] = await deployFlipper(api);
 
       let flipValueBefore = await getFlipValue(contract, deployer);
-      const flip = contract.exec('flip', value, gasLimit);
+      const flip = contract.tx.flip(value, gasLimit);
       await submitTransactionAsync(bob, flip);
       const flipValueAfter = await getFlipValue(contract,deployer);
       expect(flipValueAfter).to.be.eq(!flipValueBefore, `Anyone can call new contract.`);
 
       const deployerCanFlip = async () => {
         let flipValueBefore = await getFlipValue(contract, deployer);
-        const deployerFlip = contract.exec('flip', value, gasLimit);
+        const deployerFlip = contract.tx.flip(value, gasLimit);
         await submitTransactionAsync(deployer, deployerFlip);
         const aliceFlip1Response = await getFlipValue(contract, deployer);
         expect(aliceFlip1Response).to.be.eq(!flipValueBefore, `Deployer always can flip.`);
@@ -62,7 +62,7 @@
       flipValueBefore = await getFlipValue(contract, deployer);
       const enableWhiteListTx = api.tx.nft.toggleContractWhiteList(contract.address, true);
       const enableResult = await submitTransactionAsync(deployer, enableWhiteListTx);
-      const flipWithEnabledWhiteList = contract.exec('flip', value, gasLimit);
+      const flipWithEnabledWhiteList = contract.tx.flip(value, gasLimit);
       await expect(submitTransactionExpectFailAsync(bob, flipWithEnabledWhiteList)).to.be.rejected;
       const flipValueAfterEnableWhiteList = await getFlipValue(contract, deployer);
       expect(flipValueAfterEnableWhiteList).to.be.eq(flipValueBefore, `Enabling whitelist doesn't make it possible to call contract for everyone.`);
@@ -72,7 +72,7 @@
       flipValueBefore = await getFlipValue(contract, deployer);
       const addBobToWhiteListTx = api.tx.nft.addToContractWhiteList(contract.address, bob.address);
       const addBobResult = await submitTransactionAsync(deployer, addBobToWhiteListTx);
-      const flipWithWhitelistedBob = contract.exec('flip', value, gasLimit);
+      const flipWithWhitelistedBob = contract.tx.flip(value, gasLimit);
       await submitTransactionAsync(bob, flipWithWhitelistedBob);
       const flipAfterWhiteListed = await getFlipValue(contract,deployer);
       expect(flipAfterWhiteListed).to.be.eq(!flipValueBefore, `Bob was whitelisted, now he can flip.`);
@@ -82,7 +82,7 @@
       flipValueBefore = await getFlipValue(contract, deployer);
       const removeBobFromWhiteListTx = api.tx.nft.removeFromContractWhiteList(contract.address, bob.address);
       const removeBobResult = await submitTransactionAsync(deployer, removeBobFromWhiteListTx);
-      const bobRemoved = contract.exec('flip', value, gasLimit);
+      const bobRemoved = contract.tx.flip(value, gasLimit);
       await expect(submitTransactionExpectFailAsync(bob, bobRemoved)).to.be.rejected;
       const afterBobRemoved = await getFlipValue(contract, deployer);
       expect(afterBobRemoved).to.be.eq(flipValueBefore, `Bob can't call contract, now when he is removeed from white list.`);
@@ -92,7 +92,7 @@
       flipValueBefore = await getFlipValue(contract, deployer);
       const disableWhiteListTx = api.tx.nft.toggleContractWhiteList(contract.address, false);
       const disableWhiteListResult = await submitTransactionAsync(deployer, disableWhiteListTx);
-      const whiteListDisabledFlip = contract.exec('flip', value, gasLimit);
+      const whiteListDisabledFlip = contract.tx.flip(value, gasLimit);
       await submitTransactionAsync(bob, whiteListDisabledFlip);
       const afterWhiteListDisabled = await getFlipValue(contract,deployer);
       expect(afterWhiteListDisabled).to.be.eq(!flipValueBefore, `Anyone can call contract with disabled whitelist.`);
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 { Enum, Struct } from '@polkadot/types/codec';8import type { AccountId, BlockNumber, Call, EventRecord } from '@polkadot/types/interfaces';9import { u128 } from '@polkadot/types/primitive';10import { IKeyringPair } from '@polkadot/types/types';11import { evmToAddress } from '@polkadot/util-crypto';12import { BigNumber } from 'bignumber.js';13import BN from 'bn.js';14import chai from 'chai';15import chaiAsPromised from 'chai-as-promised';16import { alicesPublicKey, nullPublicKey } from '../accounts';17import privateKey from '../substrate/privateKey';18import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api';19import { ICollectionInterface } from '../types';20import { hexToStr, strToUTF16, utf16ToStr } from './util';21import { Compact, Option, Raw, Vec } from '@polkadot/types/codec';22// import { AccountId, AccountIdOf, AccountIndex, Address, AssetId, Balance, BalanceOf, Block, BlockNumber, Call, ChangesTrieConfiguration, Consensus, ConsensusEngineId, Digest, DigestItem, DispatchClass, DispatchInfo, DispatchInfoTo190, EcdsaSignature, Ed25519Signature, Extrinsic, ExtrinsicEra, ExtrinsicPayload, ExtrinsicPayloadUnknown, ExtrinsicPayloadV1, ExtrinsicPayloadV2, ExtrinsicPayloadV3, ExtrinsicPayloadV4, ExtrinsicSignatureV1, ExtrinsicSignatureV2, ExtrinsicSignatureV3, ExtrinsicSignatureV4, ExtrinsicUnknown, ExtrinsicV1, ExtrinsicV2, ExtrinsicV3, ExtrinsicV4, Hash, Header, ImmortalEra, Index, Justification, KeyTypeId, KeyValue, LockIdentifier, LookupSource, LookupTarget, Moment, MortalEra, MultiSignature, Origin, Perbill, Percent, Permill, Perquintill, Phantom, PhantomData, PreRuntime, Seal, SealV0, Signature, SignedBlock, SignerPayload, Sr25519Signature, ValidatorId, Weight, WeightMultiplier } from '@polkadot/types/interfaces/runtime';2324chai.use(chaiAsPromised);25const expect = chai.expect;2627export type CrossAccountId = {28  substrate: string,29} | {30  ethereum: string,31};32export function normalizeAccountId(input: string | CrossAccountId | IKeyringPair): CrossAccountId {33  if (typeof input === 'string')34    return { substrate: input };35  if ('address' in input) {36    return { substrate: input.address };37  }38  if ('ethereum' in input) {39    input.ethereum = input.ethereum.toLowerCase();40  }41  return input;42}43export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {44  input = normalizeAccountId(input);45  if ('substrate' in input) {46    return input.substrate;47  } else {48    return evmToAddress(input.ethereum);49  }50}5152export const U128_MAX = (1n << 128n) - 1n;5354type GenericResult = {55  success: boolean,56};5758interface CreateCollectionResult {59  success: boolean;60  collectionId: number;61}6263interface CreateItemResult {64  success: boolean;65  collectionId: number;66  itemId: number;67  recipient?: CrossAccountId;68}6970interface TransferResult {71  success: boolean;72  collectionId: number;73  itemId: number;74  sender?: CrossAccountId;75  recipient?: CrossAccountId;76  value: bigint;77}7879interface IReFungibleOwner {80  Fraction: BN;81  Owner: number[];82}8384interface ITokenDataType {85  Owner: number[];86  ConstData: number[];87  VariableData: number[];88}8990interface IFungibleTokenDataType {91  Value: BN;92}9394interface IGetMessage {95  checkMsgNftMethod: string;96  checkMsgTrsMethod: string;97  checkMsgSysMethod: string;98}99100export interface IReFungibleTokenDataType {101  Owner: IReFungibleOwner[];102  ConstData: number[];103  VariableData: number[];104}105106export function nftEventMessage(events: EventRecord[]): IGetMessage {107  let checkMsgNftMethod: string = '';108  let checkMsgTrsMethod: string = '';109  let checkMsgSysMethod: string = '';110  events.forEach(({ event: { method, section } }) => {111    if (section === 'nft') {112      checkMsgNftMethod = method;113    } else if (section === 'treasury') {114      checkMsgTrsMethod = method;115    } else if (section === 'system') {116      checkMsgSysMethod = method;117    } else { return null; }118  });119  const result: IGetMessage = {120    checkMsgNftMethod,121    checkMsgTrsMethod,122    checkMsgSysMethod,123  };124  return result;125}126127export function getGenericResult(events: EventRecord[]): GenericResult {128  const result: GenericResult = {129    success: false,130  };131  events.forEach(({ phase, event: { data, method, section } }) => {132    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);133    if (method === 'ExtrinsicSuccess') {134      result.success = true;135    }136  });137  return result;138}139140141142export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {143  let success = false;144  let collectionId: number = 0;145  events.forEach(({ phase, event: { data, method, section } }) => {146    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);147    if (method == 'ExtrinsicSuccess') {148      success = true;149    } else if ((section == 'nft') && (method == 'CollectionCreated')) {150      collectionId = parseInt(data[0].toString());151    }152  });153  const result: CreateCollectionResult = {154    success,155    collectionId,156  };157  return result;158}159160export function getCreateItemResult(events: EventRecord[]): CreateItemResult {161  let success = false;162  let collectionId: number = 0;163  let itemId: number = 0;164  let recipient;165  events.forEach(({ phase, event: { data, method, section } }) => {166    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);167    if (method == 'ExtrinsicSuccess') {168      success = true;169    } else if ((section == 'nft') && (method == 'ItemCreated')) {170      collectionId = parseInt(data[0].toString());171      itemId = parseInt(data[1].toString());172      recipient = data[2].toJSON();173    }174  });175  const result: CreateItemResult = {176    success,177    collectionId,178    itemId,179    recipient,180  };181  return result;182}183184export function getTransferResult(events: EventRecord[]): TransferResult {185  const result: TransferResult = {186    success: false,187    collectionId: 0,188    itemId: 0,189    value: 0n,190  };191192  events.forEach(({ event: { data, method, section } }) => {193    if (method === 'ExtrinsicSuccess') {194      result.success = true;195    } else if (section === 'nft' && method === 'Transfer') {196      result.collectionId = +data[0].toString();197      result.itemId = +data[1].toString();198      result.sender = data[2].toJSON() as CrossAccountId;199      result.recipient = data[3].toJSON() as CrossAccountId;200      result.value = BigInt(data[4].toString());201    }202  });203204  return result;205}206207interface Invalid {208  type: 'Invalid';209}210211interface Nft {212  type: 'NFT';213}214215interface Fungible {216  type: 'Fungible';217  decimalPoints: number;218}219220interface ReFungible {221  type: 'ReFungible';222}223224type CollectionMode = Nft | Fungible | ReFungible | Invalid;225226export type CreateCollectionParams = {227  mode: CollectionMode,228  name: string,229  description: string,230  tokenPrefix: string,231};232233const defaultCreateCollectionParams: CreateCollectionParams = {234  description: 'description',235  mode: { type: 'NFT' },236  name: 'name',237  tokenPrefix: 'prefix',238}239240export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {241  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };242243  let collectionId: number = 0;244  await usingApi(async (api) => {245    // Get number of collections before the transaction246    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);247248    // Run the CreateCollection transaction249    const alicePrivateKey = privateKey('//Alice');250251    let modeprm = {};252    if (mode.type === 'NFT') {253      modeprm = { nft: null };254    } else if (mode.type === 'Fungible') {255      modeprm = { fungible: mode.decimalPoints };256    } else if (mode.type === 'ReFungible') {257      modeprm = { refungible: null };258    } else if (mode.type === 'Invalid') {259      modeprm = { invalid: null };260    }261262    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);263    const events = await submitTransactionAsync(alicePrivateKey, tx);264    const result = getCreateCollectionResult(events);265266    // Get number of collections after the transaction267    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);268269    // Get the collection270    const collection: any = (await api.query.nft.collectionById(result.collectionId) as any).toJSON();271272    // What to expect273    // tslint:disable-next-line:no-unused-expression274    expect(result.success).to.be.true;275    expect(result.collectionId).to.be.equal(BcollectionCount);276    // tslint:disable-next-line:no-unused-expression277    expect(collection).to.be.not.null;278    expect(BcollectionCount).to.be.equal(AcollectionCount + 1, 'Error: NFT collection NOT created.');279    expect(collection.Owner).to.be.equal(toSubstrateAddress(alicesPublicKey));280    expect(utf16ToStr(collection.Name)).to.be.equal(name);281    expect(utf16ToStr(collection.Description)).to.be.equal(description);282    expect(hexToStr(collection.TokenPrefix)).to.be.equal(tokenPrefix);283284    collectionId = result.collectionId;285  });286287  return collectionId;288}289290export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {291  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };292293  let modeprm = {};294  if (mode.type === 'NFT') {295    modeprm = { nft: null };296  } else if (mode.type === 'Fungible') {297    modeprm = { fungible: mode.decimalPoints };298  } else if (mode.type === 'ReFungible') {299    modeprm = { refungible: null };300  } else if (mode.type === 'Invalid') {301    modeprm = { invalid: null };302  }303304  await usingApi(async (api) => {305    // Get number of collections before the transaction306    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());307308    // Run the CreateCollection transaction309    const alicePrivateKey = privateKey('//Alice');310    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);311    const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;312    const result = getCreateCollectionResult(events);313314    // Get number of collections after the transaction315    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());316317    // What to expect318    // tslint:disable-next-line:no-unused-expression319    expect(result.success).to.be.false;320    expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');321  });322}323324export async function findUnusedAddress(api: ApiPromise, seedAddition = ''): Promise<IKeyringPair> {325  let bal = new BigNumber(0);326  let unused;327  do {328    const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;329    const keyring = new Keyring({ type: 'sr25519' });330    unused = keyring.addFromUri(`//${randomSeed}`);331    bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());332  } while (bal.toFixed() != '0');333  return unused;334}335336export async function getAllowance(collectionId: number, tokenId: number, owner: string, approved: string) {337  return await usingApi(async (api) => {338    const bn = await api.query.nft.allowances(collectionId, [tokenId, owner, approved]) as unknown as BN;339    return BigInt(bn.toString());340  });341}342343export function findUnusedAddresses(api: ApiPromise, amount: number): Promise<IKeyringPair[]> {344  return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, '_' + Date.now())));345}346347export async function findNotExistingCollection(api: ApiPromise): Promise<number> {348  const totalNumber = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10) as unknown as number;349  const newCollection: number = totalNumber + 1;350  return newCollection;351}352353function getDestroyResult(events: EventRecord[]): boolean {354  let success: boolean = false;355  events.forEach(({ phase, event: { data, method, section } }) => {356    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);357    if (method == 'ExtrinsicSuccess') {358      success = true;359    }360  });361  return success;362}363364export async function destroyCollectionExpectFailure(collectionId: number, senderSeed: string = '//Alice') {365  await usingApi(async (api) => {366    // Run the DestroyCollection transaction367    const alicePrivateKey = privateKey(senderSeed);368    const tx = api.tx.nft.destroyCollection(collectionId);369    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;370  });371}372373export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed: string = '//Alice') {374  await usingApi(async (api) => {375    // Run the DestroyCollection transaction376    const alicePrivateKey = privateKey(senderSeed);377    const tx = api.tx.nft.destroyCollection(collectionId);378    const events = await submitTransactionAsync(alicePrivateKey, tx);379    const result = getDestroyResult(events);380381    // Get the collection382    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();383384    // What to expect385    expect(result).to.be.true;386    expect(collection).to.be.null;387  });388}389390export async function queryCollectionLimits(collectionId: number) {391  return await usingApi(async (api) => {392    return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;393  });394}395396export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {397  await usingApi(async (api) => {398    const oldLimits = await queryCollectionLimits(collectionId);399    const newLimits = { ...oldLimits as any, ...limits };400    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);401    const events = await submitTransactionAsync(sender, tx);402    const result = getGenericResult(events);403404    expect(result.success).to.be.true;405  });406}407408export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) {409  await usingApi(async (api) => {410    const oldLimits = await queryCollectionLimits(collectionId);411    const newLimits = { ...oldLimits as any, ...limits };412    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);413    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;414    const result = getGenericResult(events);415416    expect(result.success).to.be.false;417  });418}419420export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string) {421  await usingApi(async (api) => {422423    // Run the transaction424    const alicePrivateKey = privateKey('//Alice');425    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);426    const events = await submitTransactionAsync(alicePrivateKey, tx);427    const result = getGenericResult(events);428429    // Get the collection430    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();431432    // What to expect433    expect(result.success).to.be.true;434    expect(collection.Sponsorship).to.deep.equal({435      unconfirmed: sponsor,436    });437  });438}439440export async function removeCollectionSponsorExpectSuccess(collectionId: number) {441  await usingApi(async (api) => {442443    // Run the transaction444    const alicePrivateKey = privateKey('//Alice');445    const tx = api.tx.nft.removeCollectionSponsor(collectionId);446    const events = await submitTransactionAsync(alicePrivateKey, tx);447    const result = getGenericResult(events);448449    // Get the collection450    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();451452    // What to expect453    expect(result.success).to.be.true;454    expect(collection.Sponsorship).to.be.deep.equal({ disabled: null });455  });456}457458export async function removeCollectionSponsorExpectFailure(collectionId: number) {459  await usingApi(async (api) => {460461    // Run the transaction462    const alicePrivateKey = privateKey('//Alice');463    const tx = api.tx.nft.removeCollectionSponsor(collectionId);464    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;465  });466}467468export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed: string = '//Alice') {469  await usingApi(async (api) => {470471    // Run the transaction472    const alicePrivateKey = privateKey(senderSeed);473    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);474    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;475  });476}477478export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed: string = '//Alice') {479  await usingApi(async (api) => {480481    // Run the transaction482    const sender = privateKey(senderSeed);483    const tx = api.tx.nft.confirmSponsorship(collectionId);484    const events = await submitTransactionAsync(sender, tx);485    const result = getGenericResult(events);486487    // Get the collection488    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();489490    // What to expect491    expect(result.success).to.be.true;492    expect(collection.Sponsorship).to.be.deep.equal({493      confirmed: sender.address,494    });495  });496}497498499export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed: string = '//Alice') {500  await usingApi(async (api) => {501502    // Run the transaction503    const sender = privateKey(senderSeed);504    const tx = api.tx.nft.confirmSponsorship(collectionId);505    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;506  });507}508509export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {510  await usingApi(async (api) => {511    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);512    const events = await submitTransactionAsync(sender, tx);513    const result = getGenericResult(events);514515    expect(result.success).to.be.true;516  });517}518519export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {520  await usingApi(async (api) => {521    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);522    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;523    const result = getGenericResult(events);524525    expect(result.success).to.be.false;526  });527}528529export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {530  await usingApi(async (api) => {531    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);532    const events = await submitTransactionAsync(sender, tx);533    const result = getGenericResult(events);534535    expect(result.success).to.be.true;536  });537}538539export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {540  await usingApi(async (api) => {541    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);542    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;543    const result = getGenericResult(events);544545    expect(result.success).to.be.false;546  });547}548549export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enabled: boolean) {550  await usingApi(async (api) => {551    const tx = api.tx.nft.toggleContractWhiteList(contractAddress, true);552    const events = await submitTransactionAsync(sender, tx);553    const result = getGenericResult(events);554555    expect(result.success).to.be.true;556  });557}558559export async function isWhitelistedInContract(contractAddress: AccountId | string, user: string) {560  let whitelisted: boolean = false;561  await usingApi(async (api) => {562    whitelisted = (await api.query.nft.contractWhiteList(contractAddress, user)).toJSON() as boolean;563  });564  return whitelisted;565}566567export async function addToContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {568  await usingApi(async (api) => {569    const tx = api.tx.nft.addToContractWhiteList(contractAddress.toString(), user.toString());570    const events = await submitTransactionAsync(sender, tx);571    const result = getGenericResult(events);572573    expect(result.success).to.be.true;574  });575}576577export async function removeFromContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {578  await usingApi(async (api) => {579    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());580    const events = await submitTransactionAsync(sender, tx);581    const result = getGenericResult(events);582583    expect(result.success).to.be.true;584  });585}586587export async function removeFromContractWhiteListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {588  await usingApi(async (api) => {589    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());590    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;591    const result = getGenericResult(events);592593    expect(result.success).to.be.false;594  });595}596597export async function setVariableMetaDataExpectSuccess(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {598  await usingApi(async (api) => {599    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));600    const events = await submitTransactionAsync(sender, tx);601    const result = getGenericResult(events);602603    expect(result.success).to.be.true;604  });605}606607export async function setVariableMetaDataExpectFailure(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {608  await usingApi(async (api) => {609    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));610    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;611  });612}613614export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {615  await usingApi(async (api) => {616    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));617    const events = await submitTransactionAsync(sender, tx);618    const result = getGenericResult(events);619620    expect(result.success).to.be.true;621  });622}623624export async function setOffchainSchemaExpectFailure(sender: IKeyringPair, collectionId: number, data: number[]) {625  await usingApi(async (api) => {626    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));627    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;628  });629}630631export interface CreateFungibleData {632  readonly Value: bigint;633}634635export interface CreateReFungibleData { }636export interface CreateNftData { }637638export type CreateItemData = {639  NFT: CreateNftData;640} | {641  Fungible: CreateFungibleData;642} | {643  ReFungible: CreateReFungibleData;644};645646export async function burnItemExpectSuccess(owner: IKeyringPair, collectionId: number, tokenId: number, value = 0) {647  await usingApi(async (api) => {648    const tx = api.tx.nft.burnItem(collectionId, tokenId, value);649    const events = await submitTransactionAsync(owner, tx);650    const result = getGenericResult(events);651    // Get the item652    const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();653    // What to expect654    // tslint:disable-next-line:no-unused-expression655    expect(result.success).to.be.true;656    // tslint:disable-next-line:no-unused-expression657    expect(item).to.be.null;658  });659}660661export async function662  approveExpectSuccess(collectionId: number,663    tokenId: number, owner: IKeyringPair, approved: IKeyringPair | CrossAccountId | string, amount: number | bigint = 1) {664  await usingApi(async (api: ApiPromise) => {665    approved = normalizeAccountId(approved);666    const allowanceBefore =667      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;668    const approveNftTx = api.tx.nft.approve(approved, collectionId, tokenId, amount);669    const events = await submitTransactionAsync(owner, approveNftTx);670    const result = getCreateItemResult(events);671    // tslint:disable-next-line:no-unused-expression672    expect(result.success).to.be.true;673    const allowanceAfter =674      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;675    expect(allowanceAfter.sub(allowanceBefore).toString()).to.be.equal(amount.toString());676  });677}678679export async function680  transferFromExpectSuccess(collectionId: number,681    tokenId: number,682    accountApproved: IKeyringPair,683    accountFrom: IKeyringPair | CrossAccountId,684    accountTo: IKeyringPair | CrossAccountId,685    value: number | bigint = 1,686    type: string = 'NFT') {687  await usingApi(async (api: ApiPromise) => {688    const to = normalizeAccountId(accountTo);689    let balanceBefore = new BN(0);690    if (type === 'Fungible') {691      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;692    }693    const transferFromTx = api.tx.nft.transferFrom(694      normalizeAccountId(accountFrom), to, collectionId, tokenId, value);695    const events = await submitTransactionAsync(accountApproved, transferFromTx);696    const result = getCreateItemResult(events);697    // tslint:disable-next-line:no-unused-expression698    expect(result.success).to.be.true;699    if (type === 'NFT') {700      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON() as ITokenDataType;701      expect(nftItemData.Owner).to.be.deep.equal(to);702    }703    if (type === 'Fungible') {704      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;705      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());706    }707    if (type === 'ReFungible') {708      const nftItemData =709        (await api.query.nft.reFungibleItemList(collectionId, tokenId) as any).toJSON() as IReFungibleTokenDataType;710      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(normalizeAccountId(to));711      expect(nftItemData.Owner[0].Fraction).to.be.equal(value);712    }713  });714}715716export async function717  transferFromExpectFail(collectionId: number,718    tokenId: number,719    accountApproved: IKeyringPair,720    accountFrom: IKeyringPair,721    accountTo: IKeyringPair,722    value: number | bigint = 1) {723  await usingApi(async (api: ApiPromise) => {724    const transferFromTx = api.tx.nft.transferFrom(725      normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);726    const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;727    const result = getCreateCollectionResult(events);728    // tslint:disable-next-line:no-unused-expression729    expect(result.success).to.be.false;730  });731}732733async function getBlockNumber(api: ApiPromise): Promise<number> {734  return new Promise<number>(async (resolve, reject) => {735    const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {736        unsubscribe();737        resolve(head.number.toNumber());738    });739  });740}741742export async function743scheduleTransferExpectSuccess(collectionId: number,744                      tokenId: number,745                      sender: IKeyringPair,746                      recipient: IKeyringPair,747                      value: number | bigint = 1,748                      type: string = 'NFT') {749  await usingApi(async (api: ApiPromise) => {750    let balanceBefore = new BN(0);751752753    let blockNumber: number | undefined = await getBlockNumber(api);754    let expectedBlockNumber = blockNumber + 2;755756    expect(blockNumber).to.be.greaterThan(0);757    const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value); 758    const scheduleTx = await api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx);759760    const events = await submitTransactionAsync(sender, scheduleTx);761762    const sponsorBalanceBefore = new BigNumber((await api.query.system.account(sender.address)).data.free.toString());763    const recipientBalanceBefore = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());764765    const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;766    expect(nftItemDataBefore.Owner.toString()).to.be.equal(sender.address);767768    // sleep for 2 blocks769    await new Promise(resolve => setTimeout(resolve, 6000 * 2));770771    const sponsorBalanceAfter = new BigNumber((await api.query.system.account(sender.address)).data.free.toString());772    const recipientBalanceAfter = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());773774    const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;775    expect(nftItemData.Owner.toString()).to.be.equal(recipient.address);776    expect(recipientBalanceAfter.toNumber()).to.be.equal(recipientBalanceBefore.toNumber());777  });778}779780781export async function782  transferExpectSuccess(collectionId: number,783    tokenId: number,784    sender: IKeyringPair,785    recipient: IKeyringPair | CrossAccountId,786    value: number | bigint = 1,787    type: string = 'NFT') {788  await usingApi(async (api: ApiPromise) => {789    const to = normalizeAccountId(recipient);790791    let balanceBefore = new BN(0);792    if (type === 'Fungible') {793      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;794    }795    const transferTx = api.tx.nft.transfer(to, collectionId, tokenId, value);796    const events = await submitTransactionAsync(sender, transferTx);797    const result = getTransferResult(events);798    // tslint:disable-next-line:no-unused-expression799    expect(result.success).to.be.true;800    expect(result.collectionId).to.be.equal(collectionId);801    expect(result.itemId).to.be.equal(tokenId);802    expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));803    expect(result.recipient).to.be.deep.equal(to);804    expect(result.value.toString()).to.be.equal(value.toString());805    if (type === 'NFT') {806      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;807      expect(nftItemData.Owner).to.be.deep.equal(to);808    }809    if (type === 'Fungible') {810      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;811      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());812    }813    if (type === 'ReFungible') {814      const nftItemData =815        (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;816      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(to);817      expect(nftItemData.Owner[0].Fraction.toString()).to.be.equal(value.toString());818    }819  });820}821822export async function823  transferExpectFail(collectionId: number,824    tokenId: number,825    sender: IKeyringPair,826    recipient: IKeyringPair,827    value: number | bigint = 1,828    type: string = 'NFT') {829  await usingApi(async (api: ApiPromise) => {830    const transferTx = api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);831    const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;832    if (events && Array.isArray(events)) {833      const result = getCreateCollectionResult(events);834      // tslint:disable-next-line:no-unused-expression835      expect(result.success).to.be.false;836    }837  });838}839840export async function841  approveExpectFail(collectionId: number,842    tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1) {843  await usingApi(async (api: ApiPromise) => {844    const approveNftTx = api.tx.nft.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);845    const events = await expect(submitTransactionExpectFailAsync(owner, approveNftTx)).to.be.rejected;846    const result = getCreateCollectionResult(events);847    // tslint:disable-next-line:no-unused-expression848    expect(result.success).to.be.false;849  });850}851852export async function getFungibleBalance(853  collectionId: number,854  owner: string,855) {856  return await usingApi(async (api) => {857    const response = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON() as unknown as { Value: string };858    return BigInt(response.Value);859  });860}861862export async function createFungibleItemExpectSuccess(863  sender: IKeyringPair,864  collectionId: number,865  data: CreateFungibleData,866  owner: CrossAccountId | string = sender.address,867) {868  return await usingApi(async (api) => {869    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), { Fungible: data });870871    const events = await submitTransactionAsync(sender, tx);872    const result = getCreateItemResult(events);873874    expect(result.success).to.be.true;875    return result.itemId;876  });877}878879export async function createItemExpectSuccess(880  sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {881  let newItemId: number = 0;882  await usingApi(async (api) => {883    const to = normalizeAccountId(owner);884    const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);885    const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();886    const AItemBalance = new BigNumber(Aitem.Value);887888    let tx;889    if (createMode === 'Fungible') {890      const createData = { fungible: { value: 10 } };891      tx = api.tx.nft.createItem(collectionId, to, createData);892    } else if (createMode === 'ReFungible') {893      const createData = { refungible: { const_data: [], variable_data: [], pieces: 100 } };894      tx = api.tx.nft.createItem(collectionId, to, createData);895    } else {896      tx = api.tx.nft.createItem(collectionId, to, createMode);897    }898899    const events = await submitTransactionAsync(sender, tx);900    const result = getCreateItemResult(events);901902    const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);903    const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();904    const BItemBalance = new BigNumber(Bitem.Value);905906    // What to expect907    // tslint:disable-next-line:no-unused-expression908    expect(result.success).to.be.true;909    if (createMode === 'Fungible') {910      expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10);911    } else {912      expect(BItemCount).to.be.equal(AItemCount + 1);913    }914    expect(collectionId).to.be.equal(result.collectionId);915    expect(BItemCount.toString()).to.be.equal(result.itemId.toString());916    expect(to).to.be.deep.equal(result.recipient);917    newItemId = result.itemId;918  });919  return newItemId;920}921922export async function createItemExpectFailure(923  sender: IKeyringPair, collectionId: number, createMode: string, owner: string = sender.address) {924  await usingApi(async (api) => {925    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), createMode);926    927    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;928    const result = getCreateItemResult(events);929930    expect(result.success).to.be.false;931  });932}933934export async function setPublicAccessModeExpectSuccess(935  sender: IKeyringPair, collectionId: number,936  accessMode: 'Normal' | 'WhiteList',937) {938  await usingApi(async (api) => {939940    // Run the transaction941    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);942    const events = await submitTransactionAsync(sender, tx);943    const result = getGenericResult(events);944945    // Get the collection946    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();947948    // What to expect949    // tslint:disable-next-line:no-unused-expression950    expect(result.success).to.be.true;951    expect(collection.Access).to.be.equal(accessMode);952  });953}954955export async function enableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {956  await setPublicAccessModeExpectSuccess(sender, collectionId, 'WhiteList');957}958959export async function disableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {960  await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');961}962963export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {964  await usingApi(async (api) => {965966    // Run the transaction967    const tx = api.tx.nft.setMintPermission(collectionId, enabled);968    const events = await submitTransactionAsync(sender, tx);969    const result = getGenericResult(events);970971    // Get the collection972    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();973974    // What to expect975    // tslint:disable-next-line:no-unused-expression976    expect(result.success).to.be.true;977    expect(collection.MintMode).to.be.equal(enabled);978  });979}980981export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {982  await setMintPermissionExpectSuccess(sender, collectionId, true);983}984985export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {986  await usingApi(async (api) => {987    // Run the transaction988    const tx = api.tx.nft.setMintPermission(collectionId, enabled);989    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;990    const result = getCreateCollectionResult(events);991    // tslint:disable-next-line:no-unused-expression992    expect(result.success).to.be.false;993  });994}995996export async function isWhitelisted(collectionId: number, address: string) {997  let whitelisted: boolean = false;998  await usingApi(async (api) => {999    whitelisted = (await api.query.nft.whiteList(collectionId, address)).toJSON() as unknown as boolean;1000  });1001  return whitelisted;1002}10031004export async function addToWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1005  await usingApi(async (api) => {10061007    const whiteListedBefore = (await api.query.nft.whiteList(collectionId, address)).toJSON();10081009    // Run the transaction1010    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1011    const events = await submitTransactionAsync(sender, tx);1012    const result = getGenericResult(events);10131014    const whiteListedAfter = (await api.query.nft.whiteList(collectionId, address)).toJSON();10151016    // What to expect1017    // tslint:disable-next-line:no-unused-expression1018    expect(result.success).to.be.true;1019    // tslint:disable-next-line: no-unused-expression1020    expect(whiteListedBefore).to.be.false;1021    // tslint:disable-next-line: no-unused-expression1022    expect(whiteListedAfter).to.be.true;1023  });1024}10251026export async function removeFromWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1027  await usingApi(async (api) => {1028    // Run the transaction1029    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1030    const events = await submitTransactionAsync(sender, tx);1031    const result = getGenericResult(events);10321033    // What to expect1034    // tslint:disable-next-line:no-unused-expression1035    expect(result.success).to.be.true;1036  });1037}10381039export async function removeFromWhiteListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1040  await usingApi(async (api) => {1041    // Run the transaction1042    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1043    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1044    const result = getGenericResult(events);10451046    // What to expect1047    // tslint:disable-next-line:no-unused-expression1048    expect(result.success).to.be.false;1049  });1050}10511052export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)1053  : Promise<ICollectionInterface | null> => {1054  return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1055};10561057export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {1058  // set global object - collectionsCount1059  return (await api.query.nft.createdCollectionCount() as unknown as BN).toNumber();1060};10611062export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {1063  return await usingApi(async (api) => {1064    return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1065  });1066}
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 { Enum, Struct } from '@polkadot/types/codec';8import type { AccountId, BlockNumber, Call, EventRecord } from '@polkadot/types/interfaces';9import { u128 } from '@polkadot/types/primitive';10import { IKeyringPair } from '@polkadot/types/types';11import { evmToAddress } from '@polkadot/util-crypto';12import { BigNumber } from 'bignumber.js';13import BN from 'bn.js';14import chai from 'chai';15import chaiAsPromised from 'chai-as-promised';16import { alicesPublicKey, nullPublicKey } from '../accounts';17import privateKey from '../substrate/privateKey';18import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api';19import { ICollectionInterface } from '../types';20import { hexToStr, strToUTF16, utf16ToStr } from './util';21import { Compact, Option, Raw, Vec } from '@polkadot/types/codec';22// import { AccountId, AccountIdOf, AccountIndex, Address, AssetId, Balance, BalanceOf, Block, BlockNumber, Call, ChangesTrieConfiguration, Consensus, ConsensusEngineId, Digest, DigestItem, DispatchClass, DispatchInfo, DispatchInfoTo190, EcdsaSignature, Ed25519Signature, Extrinsic, ExtrinsicEra, ExtrinsicPayload, ExtrinsicPayloadUnknown, ExtrinsicPayloadV1, ExtrinsicPayloadV2, ExtrinsicPayloadV3, ExtrinsicPayloadV4, ExtrinsicSignatureV1, ExtrinsicSignatureV2, ExtrinsicSignatureV3, ExtrinsicSignatureV4, ExtrinsicUnknown, ExtrinsicV1, ExtrinsicV2, ExtrinsicV3, ExtrinsicV4, Hash, Header, ImmortalEra, Index, Justification, KeyTypeId, KeyValue, LockIdentifier, LookupSource, LookupTarget, Moment, MortalEra, MultiSignature, Origin, Perbill, Percent, Permill, Perquintill, Phantom, PhantomData, PreRuntime, Seal, SealV0, Signature, SignedBlock, SignerPayload, Sr25519Signature, ValidatorId, Weight, WeightMultiplier } from '@polkadot/types/interfaces/runtime';2324chai.use(chaiAsPromised);25const expect = chai.expect;2627export type CrossAccountId = {28  substrate: string,29} | {30  ethereum: string,31};32export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {33  if (typeof input === 'string')34    return { substrate: input };35  if ('address' in input) {36    return { substrate: input.address };37  }38  if ('ethereum' in input) {39    input.ethereum = input.ethereum.toLowerCase();40    return input;41  }4243  // AccountId44  return {substrate: input.toString()}45}46export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {47  input = normalizeAccountId(input);48  if ('substrate' in input) {49    return input.substrate;50  } else {51    return evmToAddress(input.ethereum);52  }53}5455export const U128_MAX = (1n << 128n) - 1n;5657type GenericResult = {58  success: boolean,59};6061interface CreateCollectionResult {62  success: boolean;63  collectionId: number;64}6566interface CreateItemResult {67  success: boolean;68  collectionId: number;69  itemId: number;70  recipient?: CrossAccountId;71}7273interface TransferResult {74  success: boolean;75  collectionId: number;76  itemId: number;77  sender?: CrossAccountId;78  recipient?: CrossAccountId;79  value: bigint;80}8182interface IReFungibleOwner {83  Fraction: BN;84  Owner: number[];85}8687interface ITokenDataType {88  Owner: number[];89  ConstData: number[];90  VariableData: number[];91}9293interface IFungibleTokenDataType {94  Value: BN;95}9697interface IGetMessage {98  checkMsgNftMethod: string;99  checkMsgTrsMethod: string;100  checkMsgSysMethod: string;101}102103export interface IReFungibleTokenDataType {104  Owner: IReFungibleOwner[];105  ConstData: number[];106  VariableData: number[];107}108109export function nftEventMessage(events: EventRecord[]): IGetMessage {110  let checkMsgNftMethod: string = '';111  let checkMsgTrsMethod: string = '';112  let checkMsgSysMethod: string = '';113  events.forEach(({ event: { method, section } }) => {114    if (section === 'nft') {115      checkMsgNftMethod = method;116    } else if (section === 'treasury') {117      checkMsgTrsMethod = method;118    } else if (section === 'system') {119      checkMsgSysMethod = method;120    } else { return null; }121  });122  const result: IGetMessage = {123    checkMsgNftMethod,124    checkMsgTrsMethod,125    checkMsgSysMethod,126  };127  return result;128}129130export function getGenericResult(events: EventRecord[]): GenericResult {131  const result: GenericResult = {132    success: false,133  };134  events.forEach(({ phase, event: { data, method, section } }) => {135    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);136    if (method === 'ExtrinsicSuccess') {137      result.success = true;138    }139  });140  return result;141}142143144145export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {146  let success = false;147  let collectionId: number = 0;148  events.forEach(({ phase, event: { data, method, section } }) => {149    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);150    if (method == 'ExtrinsicSuccess') {151      success = true;152    } else if ((section == 'nft') && (method == 'CollectionCreated')) {153      collectionId = parseInt(data[0].toString());154    }155  });156  const result: CreateCollectionResult = {157    success,158    collectionId,159  };160  return result;161}162163export function getCreateItemResult(events: EventRecord[]): CreateItemResult {164  let success = false;165  let collectionId: number = 0;166  let itemId: number = 0;167  let recipient;168  events.forEach(({ phase, event: { data, method, section } }) => {169    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);170    if (method == 'ExtrinsicSuccess') {171      success = true;172    } else if ((section == 'nft') && (method == 'ItemCreated')) {173      collectionId = parseInt(data[0].toString());174      itemId = parseInt(data[1].toString());175      recipient = data[2].toJSON();176    }177  });178  const result: CreateItemResult = {179    success,180    collectionId,181    itemId,182    recipient,183  };184  return result;185}186187export function getTransferResult(events: EventRecord[]): TransferResult {188  const result: TransferResult = {189    success: false,190    collectionId: 0,191    itemId: 0,192    value: 0n,193  };194195  events.forEach(({ event: { data, method, section } }) => {196    if (method === 'ExtrinsicSuccess') {197      result.success = true;198    } else if (section === 'nft' && method === 'Transfer') {199      result.collectionId = +data[0].toString();200      result.itemId = +data[1].toString();201      result.sender = data[2].toJSON() as CrossAccountId;202      result.recipient = data[3].toJSON() as CrossAccountId;203      result.value = BigInt(data[4].toString());204    }205  });206207  return result;208}209210interface Invalid {211  type: 'Invalid';212}213214interface Nft {215  type: 'NFT';216}217218interface Fungible {219  type: 'Fungible';220  decimalPoints: number;221}222223interface ReFungible {224  type: 'ReFungible';225}226227type CollectionMode = Nft | Fungible | ReFungible | Invalid;228229export type CreateCollectionParams = {230  mode: CollectionMode,231  name: string,232  description: string,233  tokenPrefix: string,234};235236const defaultCreateCollectionParams: CreateCollectionParams = {237  description: 'description',238  mode: { type: 'NFT' },239  name: 'name',240  tokenPrefix: 'prefix',241}242243export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {244  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };245246  let collectionId: number = 0;247  await usingApi(async (api) => {248    // Get number of collections before the transaction249    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);250251    // Run the CreateCollection transaction252    const alicePrivateKey = privateKey('//Alice');253254    let modeprm = {};255    if (mode.type === 'NFT') {256      modeprm = { nft: null };257    } else if (mode.type === 'Fungible') {258      modeprm = { fungible: mode.decimalPoints };259    } else if (mode.type === 'ReFungible') {260      modeprm = { refungible: null };261    } else if (mode.type === 'Invalid') {262      modeprm = { invalid: null };263    }264265    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);266    const events = await submitTransactionAsync(alicePrivateKey, tx);267    const result = getCreateCollectionResult(events);268269    // Get number of collections after the transaction270    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);271272    // Get the collection273    const collection: any = (await api.query.nft.collectionById(result.collectionId) as any).toJSON();274275    // What to expect276    // tslint:disable-next-line:no-unused-expression277    expect(result.success).to.be.true;278    expect(result.collectionId).to.be.equal(BcollectionCount);279    // tslint:disable-next-line:no-unused-expression280    expect(collection).to.be.not.null;281    expect(BcollectionCount).to.be.equal(AcollectionCount + 1, 'Error: NFT collection NOT created.');282    expect(collection.Owner).to.be.equal(toSubstrateAddress(alicesPublicKey));283    expect(utf16ToStr(collection.Name)).to.be.equal(name);284    expect(utf16ToStr(collection.Description)).to.be.equal(description);285    expect(hexToStr(collection.TokenPrefix)).to.be.equal(tokenPrefix);286287    collectionId = result.collectionId;288  });289290  return collectionId;291}292293export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {294  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };295296  let modeprm = {};297  if (mode.type === 'NFT') {298    modeprm = { nft: null };299  } else if (mode.type === 'Fungible') {300    modeprm = { fungible: mode.decimalPoints };301  } else if (mode.type === 'ReFungible') {302    modeprm = { refungible: null };303  } else if (mode.type === 'Invalid') {304    modeprm = { invalid: null };305  }306307  await usingApi(async (api) => {308    // Get number of collections before the transaction309    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());310311    // Run the CreateCollection transaction312    const alicePrivateKey = privateKey('//Alice');313    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);314    const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;315    const result = getCreateCollectionResult(events);316317    // Get number of collections after the transaction318    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());319320    // What to expect321    // tslint:disable-next-line:no-unused-expression322    expect(result.success).to.be.false;323    expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');324  });325}326327export async function findUnusedAddress(api: ApiPromise, seedAddition = ''): Promise<IKeyringPair> {328  let bal = new BigNumber(0);329  let unused;330  do {331    const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;332    const keyring = new Keyring({ type: 'sr25519' });333    unused = keyring.addFromUri(`//${randomSeed}`);334    bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());335  } while (bal.toFixed() != '0');336  return unused;337}338339export async function getAllowance(collectionId: number, tokenId: number, owner: string, approved: string) {340  return await usingApi(async (api) => {341    const bn = await api.query.nft.allowances(collectionId, [tokenId, owner, approved]) as unknown as BN;342    return BigInt(bn.toString());343  });344}345346export function findUnusedAddresses(api: ApiPromise, amount: number): Promise<IKeyringPair[]> {347  return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, '_' + Date.now())));348}349350export async function findNotExistingCollection(api: ApiPromise): Promise<number> {351  const totalNumber = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10) as unknown as number;352  const newCollection: number = totalNumber + 1;353  return newCollection;354}355356function getDestroyResult(events: EventRecord[]): boolean {357  let success: boolean = false;358  events.forEach(({ phase, event: { data, method, section } }) => {359    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);360    if (method == 'ExtrinsicSuccess') {361      success = true;362    }363  });364  return success;365}366367export async function destroyCollectionExpectFailure(collectionId: number, senderSeed: string = '//Alice') {368  await usingApi(async (api) => {369    // Run the DestroyCollection transaction370    const alicePrivateKey = privateKey(senderSeed);371    const tx = api.tx.nft.destroyCollection(collectionId);372    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;373  });374}375376export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed: string = '//Alice') {377  await usingApi(async (api) => {378    // Run the DestroyCollection transaction379    const alicePrivateKey = privateKey(senderSeed);380    const tx = api.tx.nft.destroyCollection(collectionId);381    const events = await submitTransactionAsync(alicePrivateKey, tx);382    const result = getDestroyResult(events);383384    // Get the collection385    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();386387    // What to expect388    expect(result).to.be.true;389    expect(collection).to.be.null;390  });391}392393export async function queryCollectionLimits(collectionId: number) {394  return await usingApi(async (api) => {395    return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;396  });397}398399export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {400  await usingApi(async (api) => {401    const oldLimits = await queryCollectionLimits(collectionId);402    const newLimits = { ...oldLimits as any, ...limits };403    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);404    const events = await submitTransactionAsync(sender, tx);405    const result = getGenericResult(events);406407    expect(result.success).to.be.true;408  });409}410411export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) {412  await usingApi(async (api) => {413    const oldLimits = await queryCollectionLimits(collectionId);414    const newLimits = { ...oldLimits as any, ...limits };415    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);416    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;417    const result = getGenericResult(events);418419    expect(result.success).to.be.false;420  });421}422423export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string) {424  await usingApi(async (api) => {425426    // Run the transaction427    const alicePrivateKey = privateKey('//Alice');428    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);429    const events = await submitTransactionAsync(alicePrivateKey, tx);430    const result = getGenericResult(events);431432    // Get the collection433    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();434435    // What to expect436    expect(result.success).to.be.true;437    expect(collection.Sponsorship).to.deep.equal({438      unconfirmed: sponsor,439    });440  });441}442443export async function removeCollectionSponsorExpectSuccess(collectionId: number) {444  await usingApi(async (api) => {445446    // Run the transaction447    const alicePrivateKey = privateKey('//Alice');448    const tx = api.tx.nft.removeCollectionSponsor(collectionId);449    const events = await submitTransactionAsync(alicePrivateKey, tx);450    const result = getGenericResult(events);451452    // Get the collection453    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();454455    // What to expect456    expect(result.success).to.be.true;457    expect(collection.Sponsorship).to.be.deep.equal({ disabled: null });458  });459}460461export async function removeCollectionSponsorExpectFailure(collectionId: number) {462  await usingApi(async (api) => {463464    // Run the transaction465    const alicePrivateKey = privateKey('//Alice');466    const tx = api.tx.nft.removeCollectionSponsor(collectionId);467    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;468  });469}470471export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed: string = '//Alice') {472  await usingApi(async (api) => {473474    // Run the transaction475    const alicePrivateKey = privateKey(senderSeed);476    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);477    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;478  });479}480481export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed: string = '//Alice') {482  await usingApi(async (api) => {483484    // Run the transaction485    const sender = privateKey(senderSeed);486    const tx = api.tx.nft.confirmSponsorship(collectionId);487    const events = await submitTransactionAsync(sender, tx);488    const result = getGenericResult(events);489490    // Get the collection491    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();492493    // What to expect494    expect(result.success).to.be.true;495    expect(collection.Sponsorship).to.be.deep.equal({496      confirmed: sender.address,497    });498  });499}500501502export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed: string = '//Alice') {503  await usingApi(async (api) => {504505    // Run the transaction506    const sender = privateKey(senderSeed);507    const tx = api.tx.nft.confirmSponsorship(collectionId);508    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;509  });510}511512export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {513  await usingApi(async (api) => {514    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);515    const events = await submitTransactionAsync(sender, tx);516    const result = getGenericResult(events);517518    expect(result.success).to.be.true;519  });520}521522export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {523  await usingApi(async (api) => {524    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);525    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;526    const result = getGenericResult(events);527528    expect(result.success).to.be.false;529  });530}531532export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {533  await usingApi(async (api) => {534    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);535    const events = await submitTransactionAsync(sender, tx);536    const result = getGenericResult(events);537538    expect(result.success).to.be.true;539  });540}541542export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {543  await usingApi(async (api) => {544    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);545    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;546    const result = getGenericResult(events);547548    expect(result.success).to.be.false;549  });550}551552export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enabled: boolean) {553  await usingApi(async (api) => {554    const tx = api.tx.nft.toggleContractWhiteList(contractAddress, true);555    const events = await submitTransactionAsync(sender, tx);556    const result = getGenericResult(events);557558    expect(result.success).to.be.true;559  });560}561562export async function isWhitelistedInContract(contractAddress: AccountId | string, user: string) {563  let whitelisted: boolean = false;564  await usingApi(async (api) => {565    whitelisted = (await api.query.nft.contractWhiteList(contractAddress, user)).toJSON() as boolean;566  });567  return whitelisted;568}569570export async function addToContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {571  await usingApi(async (api) => {572    const tx = api.tx.nft.addToContractWhiteList(contractAddress.toString(), user.toString());573    const events = await submitTransactionAsync(sender, tx);574    const result = getGenericResult(events);575576    expect(result.success).to.be.true;577  });578}579580export async function removeFromContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {581  await usingApi(async (api) => {582    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());583    const events = await submitTransactionAsync(sender, tx);584    const result = getGenericResult(events);585586    expect(result.success).to.be.true;587  });588}589590export async function removeFromContractWhiteListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {591  await usingApi(async (api) => {592    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());593    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;594    const result = getGenericResult(events);595596    expect(result.success).to.be.false;597  });598}599600export async function setVariableMetaDataExpectSuccess(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {601  await usingApi(async (api) => {602    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));603    const events = await submitTransactionAsync(sender, tx);604    const result = getGenericResult(events);605606    expect(result.success).to.be.true;607  });608}609610export async function setVariableMetaDataExpectFailure(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {611  await usingApi(async (api) => {612    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));613    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;614  });615}616617export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {618  await usingApi(async (api) => {619    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));620    const events = await submitTransactionAsync(sender, tx);621    const result = getGenericResult(events);622623    expect(result.success).to.be.true;624  });625}626627export async function setOffchainSchemaExpectFailure(sender: IKeyringPair, collectionId: number, data: number[]) {628  await usingApi(async (api) => {629    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));630    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;631  });632}633634export interface CreateFungibleData {635  readonly Value: bigint;636}637638export interface CreateReFungibleData { }639export interface CreateNftData { }640641export type CreateItemData = {642  NFT: CreateNftData;643} | {644  Fungible: CreateFungibleData;645} | {646  ReFungible: CreateReFungibleData;647};648649export async function burnItemExpectSuccess(owner: IKeyringPair, collectionId: number, tokenId: number, value = 0) {650  await usingApi(async (api) => {651    const tx = api.tx.nft.burnItem(collectionId, tokenId, value);652    const events = await submitTransactionAsync(owner, tx);653    const result = getGenericResult(events);654    // Get the item655    const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();656    // What to expect657    // tslint:disable-next-line:no-unused-expression658    expect(result.success).to.be.true;659    // tslint:disable-next-line:no-unused-expression660    expect(item).to.be.null;661  });662}663664export async function665  approveExpectSuccess(collectionId: number,666    tokenId: number, owner: IKeyringPair, approved: IKeyringPair | CrossAccountId | string, amount: number | bigint = 1) {667  await usingApi(async (api: ApiPromise) => {668    approved = normalizeAccountId(approved);669    const allowanceBefore =670      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;671    const approveNftTx = api.tx.nft.approve(approved, collectionId, tokenId, amount);672    const events = await submitTransactionAsync(owner, approveNftTx);673    const result = getCreateItemResult(events);674    // tslint:disable-next-line:no-unused-expression675    expect(result.success).to.be.true;676    const allowanceAfter =677      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;678    expect(allowanceAfter.sub(allowanceBefore).toString()).to.be.equal(amount.toString());679  });680}681682export async function683  transferFromExpectSuccess(collectionId: number,684    tokenId: number,685    accountApproved: IKeyringPair,686    accountFrom: IKeyringPair | CrossAccountId,687    accountTo: IKeyringPair | CrossAccountId,688    value: number | bigint = 1,689    type: string = 'NFT') {690  await usingApi(async (api: ApiPromise) => {691    const to = normalizeAccountId(accountTo);692    let balanceBefore = new BN(0);693    if (type === 'Fungible') {694      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;695    }696    const transferFromTx = api.tx.nft.transferFrom(697      normalizeAccountId(accountFrom), to, collectionId, tokenId, value);698    const events = await submitTransactionAsync(accountApproved, transferFromTx);699    const result = getCreateItemResult(events);700    // tslint:disable-next-line:no-unused-expression701    expect(result.success).to.be.true;702    if (type === 'NFT') {703      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON() as ITokenDataType;704      expect(nftItemData.Owner).to.be.deep.equal(to);705    }706    if (type === 'Fungible') {707      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;708      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());709    }710    if (type === 'ReFungible') {711      const nftItemData =712        (await api.query.nft.reFungibleItemList(collectionId, tokenId) as any).toJSON() as IReFungibleTokenDataType;713      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(normalizeAccountId(to));714      expect(nftItemData.Owner[0].Fraction).to.be.equal(value);715    }716  });717}718719export async function720  transferFromExpectFail(collectionId: number,721    tokenId: number,722    accountApproved: IKeyringPair,723    accountFrom: IKeyringPair,724    accountTo: IKeyringPair,725    value: number | bigint = 1) {726  await usingApi(async (api: ApiPromise) => {727    const transferFromTx = api.tx.nft.transferFrom(728      normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);729    const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;730    const result = getCreateCollectionResult(events);731    // tslint:disable-next-line:no-unused-expression732    expect(result.success).to.be.false;733  });734}735736async function getBlockNumber(api: ApiPromise): Promise<number> {737  return new Promise<number>(async (resolve, reject) => {738    const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {739        unsubscribe();740        resolve(head.number.toNumber());741    });742  });743}744745export async function746scheduleTransferExpectSuccess(collectionId: number,747                      tokenId: number,748                      sender: IKeyringPair,749                      recipient: IKeyringPair,750                      value: number | bigint = 1,751                      type: string = 'NFT') {752  await usingApi(async (api: ApiPromise) => {753    let balanceBefore = new BN(0);754755756    let blockNumber: number | undefined = await getBlockNumber(api);757    let expectedBlockNumber = blockNumber + 2;758759    expect(blockNumber).to.be.greaterThan(0);760    const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value); 761    const scheduleTx = await api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx);762763    const events = await submitTransactionAsync(sender, scheduleTx);764765    const sponsorBalanceBefore = new BigNumber((await api.query.system.account(sender.address)).data.free.toString());766    const recipientBalanceBefore = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());767768    const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;769    expect(nftItemDataBefore.Owner.toString()).to.be.equal(sender.address);770771    // sleep for 2 blocks772    await new Promise(resolve => setTimeout(resolve, 6000 * 2));773774    const sponsorBalanceAfter = new BigNumber((await api.query.system.account(sender.address)).data.free.toString());775    const recipientBalanceAfter = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());776777    const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;778    expect(nftItemData.Owner.toString()).to.be.equal(recipient.address);779    expect(recipientBalanceAfter.toNumber()).to.be.equal(recipientBalanceBefore.toNumber());780  });781}782783784export async function785  transferExpectSuccess(collectionId: number,786    tokenId: number,787    sender: IKeyringPair,788    recipient: IKeyringPair | CrossAccountId,789    value: number | bigint = 1,790    type: string = 'NFT') {791  await usingApi(async (api: ApiPromise) => {792    const to = normalizeAccountId(recipient);793794    let balanceBefore = new BN(0);795    if (type === 'Fungible') {796      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;797    }798    const transferTx = api.tx.nft.transfer(to, collectionId, tokenId, value);799    const events = await submitTransactionAsync(sender, transferTx);800    const result = getTransferResult(events);801    // tslint:disable-next-line:no-unused-expression802    expect(result.success).to.be.true;803    expect(result.collectionId).to.be.equal(collectionId);804    expect(result.itemId).to.be.equal(tokenId);805    expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));806    expect(result.recipient).to.be.deep.equal(to);807    expect(result.value.toString()).to.be.equal(value.toString());808    if (type === 'NFT') {809      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;810      expect(nftItemData.Owner).to.be.deep.equal(to);811    }812    if (type === 'Fungible') {813      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;814      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());815    }816    if (type === 'ReFungible') {817      const nftItemData =818        (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;819      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(to);820      expect(nftItemData.Owner[0].Fraction.toString()).to.be.equal(value.toString());821    }822  });823}824825export async function826  transferExpectFail(collectionId: number,827    tokenId: number,828    sender: IKeyringPair,829    recipient: IKeyringPair,830    value: number | bigint = 1,831    type: string = 'NFT') {832  await usingApi(async (api: ApiPromise) => {833    const transferTx = api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);834    const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;835    if (events && Array.isArray(events)) {836      const result = getCreateCollectionResult(events);837      // tslint:disable-next-line:no-unused-expression838      expect(result.success).to.be.false;839    }840  });841}842843export async function844  approveExpectFail(collectionId: number,845    tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1) {846  await usingApi(async (api: ApiPromise) => {847    const approveNftTx = api.tx.nft.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);848    const events = await expect(submitTransactionExpectFailAsync(owner, approveNftTx)).to.be.rejected;849    const result = getCreateCollectionResult(events);850    // tslint:disable-next-line:no-unused-expression851    expect(result.success).to.be.false;852  });853}854855export async function getFungibleBalance(856  collectionId: number,857  owner: string,858) {859  return await usingApi(async (api) => {860    const response = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON() as unknown as { Value: string };861    return BigInt(response.Value);862  });863}864865export async function createFungibleItemExpectSuccess(866  sender: IKeyringPair,867  collectionId: number,868  data: CreateFungibleData,869  owner: CrossAccountId | string = sender.address,870) {871  return await usingApi(async (api) => {872    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), { Fungible: data });873874    const events = await submitTransactionAsync(sender, tx);875    const result = getCreateItemResult(events);876877    expect(result.success).to.be.true;878    return result.itemId;879  });880}881882export async function createItemExpectSuccess(883  sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {884  let newItemId: number = 0;885  await usingApi(async (api) => {886    const to = normalizeAccountId(owner);887    const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);888    const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();889    const AItemBalance = new BigNumber(Aitem.Value);890891    let tx;892    if (createMode === 'Fungible') {893      const createData = { fungible: { value: 10 } };894      tx = api.tx.nft.createItem(collectionId, to, createData);895    } else if (createMode === 'ReFungible') {896      const createData = { refungible: { const_data: [], variable_data: [], pieces: 100 } };897      tx = api.tx.nft.createItem(collectionId, to, createData);898    } else {899      tx = api.tx.nft.createItem(collectionId, to, createMode);900    }901902    const events = await submitTransactionAsync(sender, tx);903    const result = getCreateItemResult(events);904905    const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);906    const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();907    const BItemBalance = new BigNumber(Bitem.Value);908909    // What to expect910    // tslint:disable-next-line:no-unused-expression911    expect(result.success).to.be.true;912    if (createMode === 'Fungible') {913      expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10);914    } else {915      expect(BItemCount).to.be.equal(AItemCount + 1);916    }917    expect(collectionId).to.be.equal(result.collectionId);918    expect(BItemCount.toString()).to.be.equal(result.itemId.toString());919    expect(to).to.be.deep.equal(result.recipient);920    newItemId = result.itemId;921  });922  return newItemId;923}924925export async function createItemExpectFailure(926  sender: IKeyringPair, collectionId: number, createMode: string, owner: string = sender.address) {927  await usingApi(async (api) => {928    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), createMode);929    930    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;931    const result = getCreateItemResult(events);932933    expect(result.success).to.be.false;934  });935}936937export async function setPublicAccessModeExpectSuccess(938  sender: IKeyringPair, collectionId: number,939  accessMode: 'Normal' | 'WhiteList',940) {941  await usingApi(async (api) => {942943    // Run the transaction944    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);945    const events = await submitTransactionAsync(sender, tx);946    const result = getGenericResult(events);947948    // Get the collection949    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();950951    // What to expect952    // tslint:disable-next-line:no-unused-expression953    expect(result.success).to.be.true;954    expect(collection.Access).to.be.equal(accessMode);955  });956}957958export async function enableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {959  await setPublicAccessModeExpectSuccess(sender, collectionId, 'WhiteList');960}961962export async function disableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {963  await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');964}965966export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {967  await usingApi(async (api) => {968969    // Run the transaction970    const tx = api.tx.nft.setMintPermission(collectionId, enabled);971    const events = await submitTransactionAsync(sender, tx);972    const result = getGenericResult(events);973974    // Get the collection975    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();976977    // What to expect978    // tslint:disable-next-line:no-unused-expression979    expect(result.success).to.be.true;980    expect(collection.MintMode).to.be.equal(enabled);981  });982}983984export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {985  await setMintPermissionExpectSuccess(sender, collectionId, true);986}987988export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {989  await usingApi(async (api) => {990    // Run the transaction991    const tx = api.tx.nft.setMintPermission(collectionId, enabled);992    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;993    const result = getCreateCollectionResult(events);994    // tslint:disable-next-line:no-unused-expression995    expect(result.success).to.be.false;996  });997}998999export async function isWhitelisted(collectionId: number, address: string) {1000  let whitelisted: boolean = false;1001  await usingApi(async (api) => {1002    whitelisted = (await api.query.nft.whiteList(collectionId, address)).toJSON() as unknown as boolean;1003  });1004  return whitelisted;1005}10061007export async function addToWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1008  await usingApi(async (api) => {10091010    const whiteListedBefore = (await api.query.nft.whiteList(collectionId, address)).toJSON();10111012    // Run the transaction1013    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1014    const events = await submitTransactionAsync(sender, tx);1015    const result = getGenericResult(events);10161017    const whiteListedAfter = (await api.query.nft.whiteList(collectionId, address)).toJSON();10181019    // What to expect1020    // tslint:disable-next-line:no-unused-expression1021    expect(result.success).to.be.true;1022    // tslint:disable-next-line: no-unused-expression1023    expect(whiteListedBefore).to.be.false;1024    // tslint:disable-next-line: no-unused-expression1025    expect(whiteListedAfter).to.be.true;1026  });1027}10281029export async function removeFromWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1030  await usingApi(async (api) => {1031    // Run the transaction1032    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1033    const events = await submitTransactionAsync(sender, tx);1034    const result = getGenericResult(events);10351036    // What to expect1037    // tslint:disable-next-line:no-unused-expression1038    expect(result.success).to.be.true;1039  });1040}10411042export async function removeFromWhiteListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1043  await usingApi(async (api) => {1044    // Run the transaction1045    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1046    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1047    const result = getGenericResult(events);10481049    // What to expect1050    // tslint:disable-next-line:no-unused-expression1051    expect(result.success).to.be.false;1052  });1053}10541055export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)1056  : Promise<ICollectionInterface | null> => {1057  return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1058};10591060export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {1061  // set global object - collectionsCount1062  return (await api.query.nft.createdCollectionCount() as unknown as BN).toNumber();1063};10641065export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {1066  return await usingApi(async (api) => {1067    return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1068  });1069}