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

difftreelog

source

tests/src/util/helpers.ts40.1 KiBsourcehistory
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}