git.delta.rocks / unique-network / refs/commits / 4e76702c569f

difftreelog

source

tests/src/util/helpers.ts38.2 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 type { AccountId, EventRecord } from '@polkadot/types/interfaces';8import { IKeyringPair } from '@polkadot/types/types';9import { evmToAddress } from '@polkadot/util-crypto';10import { BigNumber } from 'bignumber.js';11import BN from 'bn.js';12import chai from 'chai';13import chaiAsPromised from 'chai-as-promised';14import { alicesPublicKey } from '../accounts';15import privateKey from '../substrate/privateKey';16import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api';17import { ICollectionInterface } from '../types';18import { hexToStr, strToUTF16, utf16ToStr } from './util';1920chai.use(chaiAsPromised);21const expect = chai.expect;2223export type CrossAccountId = {24  substrate: string,25} | {26  ethereum: string,27};28export function normalizeAccountId(input: string | CrossAccountId | IKeyringPair): CrossAccountId {29  if (typeof input === 'string')30    return { substrate: input };31  if ('address' in input) {32    return { substrate: input.address };33  }34  if ('ethereum' in input) {35    input.ethereum = input.ethereum.toLowerCase();36  }37  return input;38}39export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {40  input = normalizeAccountId(input);41  if ('substrate' in input) {42    return input.substrate;43  } else {44    return evmToAddress(input.ethereum);45  }46}4748export const U128_MAX = (1n << 128n) - 1n;4950type GenericResult = {51  success: boolean,52};5354interface CreateCollectionResult {55  success: boolean;56  collectionId: number;57}5859interface CreateItemResult {60  success: boolean;61  collectionId: number;62  itemId: number;63  recipient?: CrossAccountId;64}6566interface TransferResult {67  success: boolean;68  collectionId: number;69  itemId: number;70  sender?: CrossAccountId;71  recipient?: CrossAccountId;72  value: bigint;73}7475interface IReFungibleOwner {76  Fraction: BN;77  Owner: number[];78}7980interface ITokenDataType {81  Owner: number[];82  ConstData: number[];83  VariableData: number[];84}8586interface IGetMessage {87  checkMsgNftMethod: string;88  checkMsgTrsMethod: string;89  checkMsgSysMethod: string;90}9192export interface IReFungibleTokenDataType {93  Owner: IReFungibleOwner[];94  ConstData: number[];95  VariableData: number[];96}9798export function nftEventMessage(events: EventRecord[]): IGetMessage {99  let checkMsgNftMethod = '';100  let checkMsgTrsMethod = '';101  let checkMsgSysMethod = '';102  events.forEach(({ event: { method, section } }) => {103    if (section === 'nft') {104      checkMsgNftMethod = method;105    } else if (section === 'treasury') {106      checkMsgTrsMethod = method;107    } else if (section === 'system') {108      checkMsgSysMethod = method;109    } else { return null; }110  });111  const result: IGetMessage = {112    checkMsgNftMethod,113    checkMsgTrsMethod,114    checkMsgSysMethod,115  };116  return result;117}118119export function getGenericResult(events: EventRecord[]): GenericResult {120  const result: GenericResult = {121    success: false,122  };123  events.forEach(({ event: { method } }) => {124    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);125    if (method === 'ExtrinsicSuccess') {126      result.success = true;127    }128  });129  return result;130}131132133134export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {135  let success = false;136  let collectionId = 0;137  events.forEach(({ event: { data, method, section } }) => {138    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);139    if (method == 'ExtrinsicSuccess') {140      success = true;141    } else if ((section == 'nft') && (method == 'CollectionCreated')) {142      collectionId = parseInt(data[0].toString());143    }144  });145  const result: CreateCollectionResult = {146    success,147    collectionId,148  };149  return result;150}151152export function getCreateItemResult(events: EventRecord[]): CreateItemResult {153  let success = false;154  let collectionId = 0;155  let itemId = 0;156  let recipient;157  events.forEach(({ event: { data, method, section } }) => {158    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);159    if (method == 'ExtrinsicSuccess') {160      success = true;161    } else if ((section == 'nft') && (method == 'ItemCreated')) {162      collectionId = parseInt(data[0].toString());163      itemId = parseInt(data[1].toString());164      recipient = data[2].toJSON();165    }166  });167  const result: CreateItemResult = {168    success,169    collectionId,170    itemId,171    recipient,172  };173  return result;174}175176export function getTransferResult(events: EventRecord[]): TransferResult {177  const result: TransferResult = {178    success: false,179    collectionId: 0,180    itemId: 0,181    value: 0n,182  };183184  events.forEach(({ event: { data, method, section } }) => {185    if (method === 'ExtrinsicSuccess') {186      result.success = true;187    } else if (section === 'nft' && method === 'Transfer') {188      result.collectionId = +data[0].toString();189      result.itemId = +data[1].toString();190      result.sender = data[2].toJSON() as CrossAccountId;191      result.recipient = data[3].toJSON() as CrossAccountId;192      result.value = BigInt(data[4].toString());193    }194  });195196  return result;197}198199interface Invalid {200  type: 'Invalid';201}202203interface Nft {204  type: 'NFT';205}206207interface Fungible {208  type: 'Fungible';209  decimalPoints: number;210}211212interface ReFungible {213  type: 'ReFungible';214}215216type CollectionMode = Nft | Fungible | ReFungible | Invalid;217218export type CreateCollectionParams = {219  mode: CollectionMode,220  name: string,221  description: string,222  tokenPrefix: string,223};224225const defaultCreateCollectionParams: CreateCollectionParams = {226  description: 'description',227  mode: { type: 'NFT' },228  name: 'name',229  tokenPrefix: 'prefix',230};231232export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {233  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };234235  let collectionId = 0;236  await usingApi(async (api) => {237    // Get number of collections before the transaction238    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);239240    // Run the CreateCollection transaction241    const alicePrivateKey = privateKey('//Alice');242243    let modeprm = {};244    if (mode.type === 'NFT') {245      modeprm = { nft: null };246    } else if (mode.type === 'Fungible') {247      modeprm = { fungible: mode.decimalPoints };248    } else if (mode.type === 'ReFungible') {249      modeprm = { refungible: null };250    } else if (mode.type === 'Invalid') {251      modeprm = { invalid: null };252    }253254    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);255    const events = await submitTransactionAsync(alicePrivateKey, tx);256    const result = getCreateCollectionResult(events);257258    // Get number of collections after the transaction259    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);260261    // Get the collection262    const collection: any = (await api.query.nft.collectionById(result.collectionId) as any).toJSON();263264    // What to expect265    // tslint:disable-next-line:no-unused-expression266    expect(result.success).to.be.true;267    expect(result.collectionId).to.be.equal(BcollectionCount);268    // tslint:disable-next-line:no-unused-expression269    expect(collection).to.be.not.null;270    expect(BcollectionCount).to.be.equal(AcollectionCount + 1, 'Error: NFT collection NOT created.');271    expect(collection.Owner).to.be.equal(toSubstrateAddress(alicesPublicKey));272    expect(utf16ToStr(collection.Name)).to.be.equal(name);273    expect(utf16ToStr(collection.Description)).to.be.equal(description);274    expect(hexToStr(collection.TokenPrefix)).to.be.equal(tokenPrefix);275276    collectionId = result.collectionId;277  });278279  return collectionId;280}281282export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {283  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };284285  let modeprm = {};286  if (mode.type === 'NFT') {287    modeprm = { nft: null };288  } else if (mode.type === 'Fungible') {289    modeprm = { fungible: mode.decimalPoints };290  } else if (mode.type === 'ReFungible') {291    modeprm = { refungible: null };292  } else if (mode.type === 'Invalid') {293    modeprm = { invalid: null };294  }295296  await usingApi(async (api) => {297    // Get number of collections before the transaction298    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());299300    // Run the CreateCollection transaction301    const alicePrivateKey = privateKey('//Alice');302    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);303    const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;304    const result = getCreateCollectionResult(events);305306    // Get number of collections after the transaction307    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());308309    // What to expect310    // tslint:disable-next-line:no-unused-expression311    expect(result.success).to.be.false;312    expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');313  });314}315316export async function findUnusedAddress(api: ApiPromise, seedAddition = ''): Promise<IKeyringPair> {317  let bal = new BigNumber(0);318  let unused;319  do {320    const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;321    const keyring = new Keyring({ type: 'sr25519' });322    unused = keyring.addFromUri(`//${randomSeed}`);323    bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());324  } while (bal.toFixed() != '0');325  return unused;326}327328export async function getAllowance(collectionId: number, tokenId: number, owner: string, approved: string) {329  return await usingApi(async (api) => {330    const bn = await api.query.nft.allowances(collectionId, [tokenId, owner, approved]) as unknown as BN;331    return BigInt(bn.toString());332  });333}334335export function findUnusedAddresses(api: ApiPromise, amount: number): Promise<IKeyringPair[]> {336  return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, '_' + Date.now())));337}338339export async function findNotExistingCollection(api: ApiPromise): Promise<number> {340  const totalNumber = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10) as unknown as number;341  const newCollection: number = totalNumber + 1;342  return newCollection;343}344345function getDestroyResult(events: EventRecord[]): boolean {346  let success = false;347  events.forEach(({ event: { method } }) => {348    if (method == 'ExtrinsicSuccess') {349      success = true;350    }351  });352  return success;353}354355export async function destroyCollectionExpectFailure(collectionId: number, senderSeed = '//Alice') {356  await usingApi(async (api) => {357    // Run the DestroyCollection transaction358    const alicePrivateKey = privateKey(senderSeed);359    const tx = api.tx.nft.destroyCollection(collectionId);360    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;361  });362}363364export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed = '//Alice') {365  await usingApi(async (api) => {366    // Run the DestroyCollection transaction367    const alicePrivateKey = privateKey(senderSeed);368    const tx = api.tx.nft.destroyCollection(collectionId);369    const events = await submitTransactionAsync(alicePrivateKey, tx);370    const result = getDestroyResult(events);371372    // Get the collection373    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();374375    // What to expect376    expect(result).to.be.true;377    expect(collection).to.be.null;378  });379}380381export async function queryCollectionLimits(collectionId: number) {382  return await usingApi(async (api) => {383    return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;384  });385}386387export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {388  await usingApi(async (api) => {389    const oldLimits = await queryCollectionLimits(collectionId);390    const newLimits = { ...oldLimits as any, ...limits };391    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);392    const events = await submitTransactionAsync(sender, tx);393    const result = getGenericResult(events);394395    expect(result.success).to.be.true;396  });397}398399export async function setCollectionLimitsExpectFailure(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 expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;405    const result = getGenericResult(events);406407    expect(result.success).to.be.false;408  });409}410411export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string) {412  await usingApi(async (api) => {413414    // Run the transaction415    const alicePrivateKey = privateKey('//Alice');416    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);417    const events = await submitTransactionAsync(alicePrivateKey, tx);418    const result = getGenericResult(events);419420    // Get the collection421    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();422423    // What to expect424    expect(result.success).to.be.true;425    expect(collection.Sponsorship).to.deep.equal({426      unconfirmed: sponsor,427    });428  });429}430431export async function removeCollectionSponsorExpectSuccess(collectionId: number) {432  await usingApi(async (api) => {433434    // Run the transaction435    const alicePrivateKey = privateKey('//Alice');436    const tx = api.tx.nft.removeCollectionSponsor(collectionId);437    const events = await submitTransactionAsync(alicePrivateKey, tx);438    const result = getGenericResult(events);439440    // Get the collection441    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();442443    // What to expect444    expect(result.success).to.be.true;445    expect(collection.Sponsorship).to.be.deep.equal({ disabled: null });446  });447}448449export async function removeCollectionSponsorExpectFailure(collectionId: number) {450  await usingApi(async (api) => {451452    // Run the transaction453    const alicePrivateKey = privateKey('//Alice');454    const tx = api.tx.nft.removeCollectionSponsor(collectionId);455    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;456  });457}458459export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed = '//Alice') {460  await usingApi(async (api) => {461462    // Run the transaction463    const alicePrivateKey = privateKey(senderSeed);464    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);465    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;466  });467}468469export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed = '//Alice') {470  await usingApi(async (api) => {471472    // Run the transaction473    const sender = privateKey(senderSeed);474    const tx = api.tx.nft.confirmSponsorship(collectionId);475    const events = await submitTransactionAsync(sender, tx);476    const result = getGenericResult(events);477478    // Get the collection479    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();480481    // What to expect482    expect(result.success).to.be.true;483    expect(collection.Sponsorship).to.be.deep.equal({484      confirmed: sender.address,485    });486  });487}488489490export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed = '//Alice') {491  await usingApi(async (api) => {492493    // Run the transaction494    const sender = privateKey(senderSeed);495    const tx = api.tx.nft.confirmSponsorship(collectionId);496    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;497  });498}499500export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {501  await usingApi(async (api) => {502    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);503    const events = await submitTransactionAsync(sender, tx);504    const result = getGenericResult(events);505506    expect(result.success).to.be.true;507  });508}509510export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {511  await usingApi(async (api) => {512    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);513    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;514    const result = getGenericResult(events);515516    expect(result.success).to.be.false;517  });518}519520export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {521  await usingApi(async (api) => {522    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);523    const events = await submitTransactionAsync(sender, tx);524    const result = getGenericResult(events);525526    expect(result.success).to.be.true;527  });528}529530export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {531  await usingApi(async (api) => {532    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);533    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;534    const result = getGenericResult(events);535536    expect(result.success).to.be.false;537  });538}539540export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string) {541  await usingApi(async (api) => {542    const tx = api.tx.nft.toggleContractWhiteList(contractAddress, true);543    const events = await submitTransactionAsync(sender, tx);544    const result = getGenericResult(events);545546    expect(result.success).to.be.true;547  });548}549550export async function isWhitelistedInContract(contractAddress: AccountId | string, user: string) {551  let whitelisted = false;552  await usingApi(async (api) => {553    whitelisted = (await api.query.nft.contractWhiteList(contractAddress, user)).toJSON() as boolean;554  });555  return whitelisted;556}557558export async function addToContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {559  await usingApi(async (api) => {560    const tx = api.tx.nft.addToContractWhiteList(contractAddress.toString(), user.toString());561    const events = await submitTransactionAsync(sender, tx);562    const result = getGenericResult(events);563564    expect(result.success).to.be.true;565  });566}567568export async function removeFromContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {569  await usingApi(async (api) => {570    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());571    const events = await submitTransactionAsync(sender, tx);572    const result = getGenericResult(events);573574    expect(result.success).to.be.true;575  });576}577578export async function removeFromContractWhiteListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {579  await usingApi(async (api) => {580    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());581    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;582    const result = getGenericResult(events);583584    expect(result.success).to.be.false;585  });586}587588export async function setVariableMetaDataExpectSuccess(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {589  await usingApi(async (api) => {590    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));591    const events = await submitTransactionAsync(sender, tx);592    const result = getGenericResult(events);593594    expect(result.success).to.be.true;595  });596}597598export async function setVariableMetaDataExpectFailure(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {599  await usingApi(async (api) => {600    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));601    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;602  });603}604605export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {606  await usingApi(async (api) => {607    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));608    const events = await submitTransactionAsync(sender, tx);609    const result = getGenericResult(events);610611    expect(result.success).to.be.true;612  });613}614615export async function setOffchainSchemaExpectFailure(sender: IKeyringPair, collectionId: number, data: number[]) {616  await usingApi(async (api) => {617    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));618    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;619  });620}621622export interface CreateFungibleData {623  readonly Value: bigint;624}625626export interface CreateReFungibleData { }627export interface CreateNftData { }628629export type CreateItemData = {630  NFT: CreateNftData;631} | {632  Fungible: CreateFungibleData;633} | {634  ReFungible: CreateReFungibleData;635};636637export async function burnItemExpectSuccess(owner: IKeyringPair, collectionId: number, tokenId: number, value = 0) {638  await usingApi(async (api) => {639    const tx = api.tx.nft.burnItem(collectionId, tokenId, value);640    const events = await submitTransactionAsync(owner, tx);641    const result = getGenericResult(events);642    // Get the item643    const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();644    // What to expect645    // tslint:disable-next-line:no-unused-expression646    expect(result.success).to.be.true;647    // tslint:disable-next-line:no-unused-expression648    expect(item).to.be.null;649  });650}651652export async function653approveExpectSuccess(654  collectionId: number,655  tokenId: number, owner: IKeyringPair, approved: IKeyringPair | CrossAccountId | string, amount: number | bigint = 1,656) {657  await usingApi(async (api: ApiPromise) => {658    approved = normalizeAccountId(approved);659    const allowanceBefore =660      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;661    const approveNftTx = api.tx.nft.approve(approved, collectionId, tokenId, amount);662    const events = await submitTransactionAsync(owner, approveNftTx);663    const result = getCreateItemResult(events);664    // tslint:disable-next-line:no-unused-expression665    expect(result.success).to.be.true;666    const allowanceAfter =667      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;668    expect(allowanceAfter.sub(allowanceBefore).toString()).to.be.equal(amount.toString());669  });670}671672export async function673transferFromExpectSuccess(674  collectionId: number,675  tokenId: number,676  accountApproved: IKeyringPair,677  accountFrom: IKeyringPair | CrossAccountId,678  accountTo: IKeyringPair | CrossAccountId,679  value: number | bigint = 1,680  type = 'NFT',681) {682  await usingApi(async (api: ApiPromise) => {683    const to = normalizeAccountId(accountTo);684    let balanceBefore = new BN(0);685    if (type === 'Fungible') {686      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;687    }688    const transferFromTx = api.tx.nft.transferFrom(normalizeAccountId(accountFrom), to, collectionId, tokenId, value);689    const events = await submitTransactionAsync(accountApproved, transferFromTx);690    const result = getCreateItemResult(events);691    // tslint:disable-next-line:no-unused-expression692    expect(result.success).to.be.true;693    if (type === 'NFT') {694      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON() as ITokenDataType;695      expect(nftItemData.Owner).to.be.deep.equal(to);696    }697    if (type === 'Fungible') {698      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;699      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());700    }701    if (type === 'ReFungible') {702      const nftItemData =703        (await api.query.nft.reFungibleItemList(collectionId, tokenId) as any).toJSON() as IReFungibleTokenDataType;704      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(normalizeAccountId(to));705      expect(nftItemData.Owner[0].Fraction).to.be.equal(value);706    }707  });708}709710export async function711transferFromExpectFail(712  collectionId: number,713  tokenId: number,714  accountApproved: IKeyringPair,715  accountFrom: IKeyringPair,716  accountTo: IKeyringPair,717  value: number | bigint = 1,718) {719  await usingApi(async (api: ApiPromise) => {720    const transferFromTx = api.tx.nft.transferFrom(normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);721    const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;722    const result = getCreateCollectionResult(events);723    // tslint:disable-next-line:no-unused-expression724    expect(result.success).to.be.false;725  });726}727728/* eslint no-async-promise-executor: "off" */729async function getBlockNumber(api: ApiPromise): Promise<number> {730  return new Promise<number>(async (resolve) => {731    const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {732      unsubscribe();733      resolve(head.number.toNumber());734    });735  });736}737738export async function739scheduleTransferExpectSuccess(740  collectionId: number,741  tokenId: number,742  sender: IKeyringPair,743  recipient: IKeyringPair,744  value: number | bigint = 1,745) {746  await usingApi(async (api: ApiPromise) => {747    const blockNumber: number | undefined = await getBlockNumber(api);748    const expectedBlockNumber = blockNumber + 2;749750    expect(blockNumber).to.be.greaterThan(0);751    const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value); 752    const scheduleTx = await api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx);753754    await submitTransactionAsync(sender, scheduleTx);755756    const recipientBalanceBefore = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());757758    const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;759    expect(nftItemDataBefore.Owner.toString()).to.be.equal(sender.address);760761    // sleep for 2 blocks762    await new Promise(resolve => setTimeout(resolve, 6000 * 2));763764    const recipientBalanceAfter = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());765766    const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;767    expect(nftItemData.Owner.toString()).to.be.equal(recipient.address);768    expect(recipientBalanceAfter.toNumber()).to.be.equal(recipientBalanceBefore.toNumber());769  });770}771772773export async function774transferExpectSuccess(775  collectionId: number,776  tokenId: number,777  sender: IKeyringPair,778  recipient: IKeyringPair | CrossAccountId,779  value: number | bigint = 1,780  type = 'NFT',781) {782  await usingApi(async (api: ApiPromise) => {783    const to = normalizeAccountId(recipient);784785    let balanceBefore = new BN(0);786    if (type === 'Fungible') {787      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;788    }789    const transferTx = api.tx.nft.transfer(to, collectionId, tokenId, value);790    const events = await submitTransactionAsync(sender, transferTx);791    const result = getTransferResult(events);792    // tslint:disable-next-line:no-unused-expression793    expect(result.success).to.be.true;794    expect(result.collectionId).to.be.equal(collectionId);795    expect(result.itemId).to.be.equal(tokenId);796    expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));797    expect(result.recipient).to.be.deep.equal(to);798    expect(result.value.toString()).to.be.equal(value.toString());799    if (type === 'NFT') {800      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;801      expect(nftItemData.Owner).to.be.deep.equal(to);802    }803    if (type === 'Fungible') {804      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;805      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());806    }807    if (type === 'ReFungible') {808      const nftItemData =809        (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;810      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(to);811      expect(nftItemData.Owner[0].Fraction.toString()).to.be.equal(value.toString());812    }813  });814}815816export async function817transferExpectFail(818  collectionId: number,819  tokenId: number,820  sender: IKeyringPair,821  recipient: IKeyringPair,822  value: number | bigint = 1,823) {824  await usingApi(async (api: ApiPromise) => {825    const transferTx = api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);826    const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;827    if (events && Array.isArray(events)) {828      const result = getCreateCollectionResult(events);829      // tslint:disable-next-line:no-unused-expression830      expect(result.success).to.be.false;831    }832  });833}834835export async function836approveExpectFail(837  collectionId: number,838  tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1,839) {840  await usingApi(async (api: ApiPromise) => {841    const approveNftTx = api.tx.nft.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);842    const events = await expect(submitTransactionExpectFailAsync(owner, approveNftTx)).to.be.rejected;843    const result = getCreateCollectionResult(events);844    // tslint:disable-next-line:no-unused-expression845    expect(result.success).to.be.false;846  });847}848849export async function getFungibleBalance(850  collectionId: number,851  owner: string,852) {853  return await usingApi(async (api) => {854    const response = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON() as unknown as { Value: string };855    return BigInt(response.Value);856  });857}858859export async function createFungibleItemExpectSuccess(860  sender: IKeyringPair,861  collectionId: number,862  data: CreateFungibleData,863  owner: CrossAccountId | string = sender.address,864) {865  return await usingApi(async (api) => {866    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), { Fungible: data });867868    const events = await submitTransactionAsync(sender, tx);869    const result = getCreateItemResult(events);870871    expect(result.success).to.be.true;872    return result.itemId;873  });874}875876export async function createItemExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {877  let newItemId = 0;878  await usingApi(async (api) => {879    const to = normalizeAccountId(owner);880    const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);881    const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();882    const AItemBalance = new BigNumber(Aitem.Value);883884    let tx;885    if (createMode === 'Fungible') {886      const createData = { fungible: { value: 10 } };887      tx = api.tx.nft.createItem(collectionId, to, createData);888    } else if (createMode === 'ReFungible') {889      const createData = { refungible: { const_data: [], variable_data: [], pieces: 100 } };890      tx = api.tx.nft.createItem(collectionId, to, createData);891    } else {892      tx = api.tx.nft.createItem(collectionId, to, createMode);893    }894895    const events = await submitTransactionAsync(sender, tx);896    const result = getCreateItemResult(events);897898    const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);899    const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();900    const BItemBalance = new BigNumber(Bitem.Value);901902    // What to expect903    // tslint:disable-next-line:no-unused-expression904    expect(result.success).to.be.true;905    if (createMode === 'Fungible') {906      expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10);907    } else {908      expect(BItemCount).to.be.equal(AItemCount + 1);909    }910    expect(collectionId).to.be.equal(result.collectionId);911    expect(BItemCount.toString()).to.be.equal(result.itemId.toString());912    expect(to).to.be.deep.equal(result.recipient);913    newItemId = result.itemId;914  });915  return newItemId;916}917918export async function createItemExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, owner: string = sender.address) {919  await usingApi(async (api) => {920    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), createMode);921    922    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;923    const result = getCreateItemResult(events);924925    expect(result.success).to.be.false;926  });927}928929export async function setPublicAccessModeExpectSuccess(930  sender: IKeyringPair, collectionId: number,931  accessMode: 'Normal' | 'WhiteList',932) {933  await usingApi(async (api) => {934935    // Run the transaction936    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);937    const events = await submitTransactionAsync(sender, tx);938    const result = getGenericResult(events);939940    // Get the collection941    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();942943    // What to expect944    // tslint:disable-next-line:no-unused-expression945    expect(result.success).to.be.true;946    expect(collection.Access).to.be.equal(accessMode);947  });948}949950export async function enableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {951  await setPublicAccessModeExpectSuccess(sender, collectionId, 'WhiteList');952}953954export async function disableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {955  await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');956}957958export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {959  await usingApi(async (api) => {960961    // Run the transaction962    const tx = api.tx.nft.setMintPermission(collectionId, enabled);963    const events = await submitTransactionAsync(sender, tx);964    const result = getGenericResult(events);965966    // Get the collection967    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();968969    // What to expect970    // tslint:disable-next-line:no-unused-expression971    expect(result.success).to.be.true;972    expect(collection.MintMode).to.be.equal(enabled);973  });974}975976export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {977  await setMintPermissionExpectSuccess(sender, collectionId, true);978}979980export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {981  await usingApi(async (api) => {982    // Run the transaction983    const tx = api.tx.nft.setMintPermission(collectionId, enabled);984    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;985    const result = getCreateCollectionResult(events);986    // tslint:disable-next-line:no-unused-expression987    expect(result.success).to.be.false;988  });989}990991export async function isWhitelisted(collectionId: number, address: string) {992  let whitelisted = false;993  await usingApi(async (api) => {994    whitelisted = (await api.query.nft.whiteList(collectionId, address)).toJSON() as unknown as boolean;995  });996  return whitelisted;997}998999export async function addToWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1000  await usingApi(async (api) => {10011002    const whiteListedBefore = (await api.query.nft.whiteList(collectionId, address)).toJSON();10031004    // Run the transaction1005    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1006    const events = await submitTransactionAsync(sender, tx);1007    const result = getGenericResult(events);10081009    const whiteListedAfter = (await api.query.nft.whiteList(collectionId, address)).toJSON();10101011    // What to expect1012    // tslint:disable-next-line:no-unused-expression1013    expect(result.success).to.be.true;1014    // tslint:disable-next-line: no-unused-expression1015    expect(whiteListedBefore).to.be.false;1016    // tslint:disable-next-line: no-unused-expression1017    expect(whiteListedAfter).to.be.true;1018  });1019}10201021export async function removeFromWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1022  await usingApi(async (api) => {1023    // Run the transaction1024    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1025    const events = await submitTransactionAsync(sender, tx);1026    const result = getGenericResult(events);10271028    // What to expect1029    // tslint:disable-next-line:no-unused-expression1030    expect(result.success).to.be.true;1031  });1032}10331034export async function removeFromWhiteListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1035  await usingApi(async (api) => {1036    // Run the transaction1037    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1038    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1039    const result = getGenericResult(events);10401041    // What to expect1042    // tslint:disable-next-line:no-unused-expression1043    expect(result.success).to.be.false;1044  });1045}10461047export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)1048  : Promise<ICollectionInterface | null> => {1049  return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1050};10511052export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {1053  // set global object - collectionsCount1054  return (await api.query.nft.createdCollectionCount() as unknown as BN).toNumber();1055};10561057export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {1058  return await usingApi(async (api) => {1059    return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1060  });1061}