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

difftreelog

source

tests/src/util/helpers.ts40.3 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 | 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  }42  if ('substrate' in input) {43    return input;44  }4546  // AccountId47  return {substrate: input.toString()}48}49export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {50  input = normalizeAccountId(input);51  if ('substrate' in input) {52    return input.substrate;53  } else {54    return evmToAddress(input.ethereum);55  }56}5758export const U128_MAX = (1n << 128n) - 1n;5960type GenericResult = {61  success: boolean,62};6364interface CreateCollectionResult {65  success: boolean;66  collectionId: number;67}6869interface CreateItemResult {70  success: boolean;71  collectionId: number;72  itemId: number;73  recipient?: CrossAccountId;74}7576interface TransferResult {77  success: boolean;78  collectionId: number;79  itemId: number;80  sender?: CrossAccountId;81  recipient?: CrossAccountId;82  value: bigint;83}8485interface IReFungibleOwner {86  Fraction: BN;87  Owner: number[];88}8990interface ITokenDataType {91  Owner: number[];92  ConstData: number[];93  VariableData: number[];94}9596interface IFungibleTokenDataType {97  Value: BN;98}99100interface IGetMessage {101  checkMsgNftMethod: string;102  checkMsgTrsMethod: string;103  checkMsgSysMethod: string;104}105106export interface IReFungibleTokenDataType {107  Owner: IReFungibleOwner[];108  ConstData: number[];109  VariableData: number[];110}111112export function nftEventMessage(events: EventRecord[]): IGetMessage {113  let checkMsgNftMethod: string = '';114  let checkMsgTrsMethod: string = '';115  let checkMsgSysMethod: string = '';116  events.forEach(({ event: { method, section } }) => {117    if (section === 'nft') {118      checkMsgNftMethod = method;119    } else if (section === 'treasury') {120      checkMsgTrsMethod = method;121    } else if (section === 'system') {122      checkMsgSysMethod = method;123    } else { return null; }124  });125  const result: IGetMessage = {126    checkMsgNftMethod,127    checkMsgTrsMethod,128    checkMsgSysMethod,129  };130  return result;131}132133export function getGenericResult(events: EventRecord[]): GenericResult {134  const result: GenericResult = {135    success: false,136  };137  events.forEach(({ phase, event: { data, method, section } }) => {138    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);139    if (method === 'ExtrinsicSuccess') {140      result.success = true;141    }142  });143  return result;144}145146147148export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {149  let success = false;150  let collectionId: number = 0;151  events.forEach(({ phase, event: { data, method, section } }) => {152    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);153    if (method == 'ExtrinsicSuccess') {154      success = true;155    } else if ((section == 'nft') && (method == 'CollectionCreated')) {156      collectionId = parseInt(data[0].toString());157    }158  });159  const result: CreateCollectionResult = {160    success,161    collectionId,162  };163  return result;164}165166export function getCreateItemResult(events: EventRecord[]): CreateItemResult {167  let success = false;168  let collectionId: number = 0;169  let itemId: number = 0;170  let recipient;171  events.forEach(({ phase, event: { data, method, section } }) => {172    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);173    if (method == 'ExtrinsicSuccess') {174      success = true;175    } else if ((section == 'nft') && (method == 'ItemCreated')) {176      collectionId = parseInt(data[0].toString());177      itemId = parseInt(data[1].toString());178      recipient = data[2].toJSON();179    }180  });181  const result: CreateItemResult = {182    success,183    collectionId,184    itemId,185    recipient,186  };187  return result;188}189190export function getTransferResult(events: EventRecord[]): TransferResult {191  const result: TransferResult = {192    success: false,193    collectionId: 0,194    itemId: 0,195    value: 0n,196  };197198  events.forEach(({ event: { data, method, section } }) => {199    if (method === 'ExtrinsicSuccess') {200      result.success = true;201    } else if (section === 'nft' && method === 'Transfer') {202      result.collectionId = +data[0].toString();203      result.itemId = +data[1].toString();204      result.sender = data[2].toJSON() as CrossAccountId;205      result.recipient = data[3].toJSON() as CrossAccountId;206      result.value = BigInt(data[4].toString());207    }208  });209210  return result;211}212213interface Invalid {214  type: 'Invalid';215}216217interface Nft {218  type: 'NFT';219}220221interface Fungible {222  type: 'Fungible';223  decimalPoints: number;224}225226interface ReFungible {227  type: 'ReFungible';228}229230type CollectionMode = Nft | Fungible | ReFungible | Invalid;231232export type CreateCollectionParams = {233  mode: CollectionMode,234  name: string,235  description: string,236  tokenPrefix: string,237};238239const defaultCreateCollectionParams: CreateCollectionParams = {240  description: 'description',241  mode: { type: 'NFT' },242  name: 'name',243  tokenPrefix: 'prefix',244}245246export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {247  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };248249  let collectionId: number = 0;250  await usingApi(async (api) => {251    // Get number of collections before the transaction252    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);253254    // Run the CreateCollection transaction255    const alicePrivateKey = privateKey('//Alice');256257    let modeprm = {};258    if (mode.type === 'NFT') {259      modeprm = { nft: null };260    } else if (mode.type === 'Fungible') {261      modeprm = { fungible: mode.decimalPoints };262    } else if (mode.type === 'ReFungible') {263      modeprm = { refungible: null };264    } else if (mode.type === 'Invalid') {265      modeprm = { invalid: null };266    }267268    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);269    const events = await submitTransactionAsync(alicePrivateKey, tx);270    const result = getCreateCollectionResult(events);271272    // Get number of collections after the transaction273    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);274275    // Get the collection276    const collection: any = (await api.query.nft.collectionById(result.collectionId) as any).toJSON();277278    // What to expect279    // tslint:disable-next-line:no-unused-expression280    expect(result.success).to.be.true;281    expect(result.collectionId).to.be.equal(BcollectionCount);282    // tslint:disable-next-line:no-unused-expression283    expect(collection).to.be.not.null;284    expect(BcollectionCount).to.be.equal(AcollectionCount + 1, 'Error: NFT collection NOT created.');285    expect(collection.Owner).to.be.equal(toSubstrateAddress(alicesPublicKey));286    expect(utf16ToStr(collection.Name)).to.be.equal(name);287    expect(utf16ToStr(collection.Description)).to.be.equal(description);288    expect(hexToStr(collection.TokenPrefix)).to.be.equal(tokenPrefix);289290    collectionId = result.collectionId;291  });292293  return collectionId;294}295296export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {297  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };298299  let modeprm = {};300  if (mode.type === 'NFT') {301    modeprm = { nft: null };302  } else if (mode.type === 'Fungible') {303    modeprm = { fungible: mode.decimalPoints };304  } else if (mode.type === 'ReFungible') {305    modeprm = { refungible: null };306  } else if (mode.type === 'Invalid') {307    modeprm = { invalid: null };308  }309310  await usingApi(async (api) => {311    // Get number of collections before the transaction312    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());313314    // Run the CreateCollection transaction315    const alicePrivateKey = privateKey('//Alice');316    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);317    const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;318    const result = getCreateCollectionResult(events);319320    // Get number of collections after the transaction321    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());322323    // What to expect324    // tslint:disable-next-line:no-unused-expression325    expect(result.success).to.be.false;326    expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');327  });328}329330export async function findUnusedAddress(api: ApiPromise, seedAddition = ''): Promise<IKeyringPair> {331  let bal = new BigNumber(0);332  let unused;333  do {334    const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;335    const keyring = new Keyring({ type: 'sr25519' });336    unused = keyring.addFromUri(`//${randomSeed}`);337    bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());338  } while (bal.toFixed() != '0');339  return unused;340}341342export async function getAllowance(collectionId: number, tokenId: number, owner: string, approved: string) {343  return await usingApi(async (api) => {344    const bn = await api.query.nft.allowances(collectionId, [tokenId, owner, approved]) as unknown as BN;345    return BigInt(bn.toString());346  });347}348349export function findUnusedAddresses(api: ApiPromise, amount: number): Promise<IKeyringPair[]> {350  return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, '_' + Date.now())));351}352353export async function findNotExistingCollection(api: ApiPromise): Promise<number> {354  const totalNumber = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10) as unknown as number;355  const newCollection: number = totalNumber + 1;356  return newCollection;357}358359function getDestroyResult(events: EventRecord[]): boolean {360  let success: boolean = false;361  events.forEach(({ phase, event: { data, method, section } }) => {362    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);363    if (method == 'ExtrinsicSuccess') {364      success = true;365    }366  });367  return success;368}369370export async function destroyCollectionExpectFailure(collectionId: number, senderSeed: string = '//Alice') {371  await usingApi(async (api) => {372    // Run the DestroyCollection transaction373    const alicePrivateKey = privateKey(senderSeed);374    const tx = api.tx.nft.destroyCollection(collectionId);375    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;376  });377}378379export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed: string = '//Alice') {380  await usingApi(async (api) => {381    // Run the DestroyCollection transaction382    const alicePrivateKey = privateKey(senderSeed);383    const tx = api.tx.nft.destroyCollection(collectionId);384    const events = await submitTransactionAsync(alicePrivateKey, tx);385    const result = getDestroyResult(events);386387    // Get the collection388    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();389390    // What to expect391    expect(result).to.be.true;392    expect(collection).to.be.null;393  });394}395396export async function queryCollectionLimits(collectionId: number) {397  return await usingApi(async (api) => {398    return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;399  });400}401402export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {403  await usingApi(async (api) => {404    const oldLimits = await queryCollectionLimits(collectionId);405    const newLimits = { ...oldLimits as any, ...limits };406    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);407    const events = await submitTransactionAsync(sender, tx);408    const result = getGenericResult(events);409410    expect(result.success).to.be.true;411  });412}413414export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) {415  await usingApi(async (api) => {416    const oldLimits = await queryCollectionLimits(collectionId);417    const newLimits = { ...oldLimits as any, ...limits };418    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);419    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;420    const result = getGenericResult(events);421422    expect(result.success).to.be.false;423  });424}425426export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string) {427  await usingApi(async (api) => {428429    // Run the transaction430    const alicePrivateKey = privateKey('//Alice');431    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);432    const events = await submitTransactionAsync(alicePrivateKey, tx);433    const result = getGenericResult(events);434435    // Get the collection436    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();437438    // What to expect439    expect(result.success).to.be.true;440    expect(collection.Sponsorship).to.deep.equal({441      unconfirmed: sponsor,442    });443  });444}445446export async function removeCollectionSponsorExpectSuccess(collectionId: number) {447  await usingApi(async (api) => {448449    // Run the transaction450    const alicePrivateKey = privateKey('//Alice');451    const tx = api.tx.nft.removeCollectionSponsor(collectionId);452    const events = await submitTransactionAsync(alicePrivateKey, tx);453    const result = getGenericResult(events);454455    // Get the collection456    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();457458    // What to expect459    expect(result.success).to.be.true;460    expect(collection.Sponsorship).to.be.deep.equal({ disabled: null });461  });462}463464export async function removeCollectionSponsorExpectFailure(collectionId: number) {465  await usingApi(async (api) => {466467    // Run the transaction468    const alicePrivateKey = privateKey('//Alice');469    const tx = api.tx.nft.removeCollectionSponsor(collectionId);470    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;471  });472}473474export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed: string = '//Alice') {475  await usingApi(async (api) => {476477    // Run the transaction478    const alicePrivateKey = privateKey(senderSeed);479    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);480    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;481  });482}483484export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed: string = '//Alice') {485  await usingApi(async (api) => {486487    // Run the transaction488    const sender = privateKey(senderSeed);489    const tx = api.tx.nft.confirmSponsorship(collectionId);490    const events = await submitTransactionAsync(sender, tx);491    const result = getGenericResult(events);492493    // Get the collection494    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();495496    // What to expect497    expect(result.success).to.be.true;498    expect(collection.Sponsorship).to.be.deep.equal({499      confirmed: sender.address,500    });501  });502}503504505export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed: string = '//Alice') {506  await usingApi(async (api) => {507508    // Run the transaction509    const sender = privateKey(senderSeed);510    const tx = api.tx.nft.confirmSponsorship(collectionId);511    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;512  });513}514515export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {516  await usingApi(async (api) => {517    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);518    const events = await submitTransactionAsync(sender, tx);519    const result = getGenericResult(events);520521    expect(result.success).to.be.true;522  });523}524525export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {526  await usingApi(async (api) => {527    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);528    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;529    const result = getGenericResult(events);530531    expect(result.success).to.be.false;532  });533}534535export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {536  await usingApi(async (api) => {537    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);538    const events = await submitTransactionAsync(sender, tx);539    const result = getGenericResult(events);540541    expect(result.success).to.be.true;542  });543}544545export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {546  await usingApi(async (api) => {547    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);548    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;549    const result = getGenericResult(events);550551    expect(result.success).to.be.false;552  });553}554555export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enabled: boolean) {556  await usingApi(async (api) => {557    const tx = api.tx.nft.toggleContractWhiteList(contractAddress, true);558    const events = await submitTransactionAsync(sender, tx);559    const result = getGenericResult(events);560561    expect(result.success).to.be.true;562  });563}564565export async function isWhitelistedInContract(contractAddress: AccountId | string, user: string) {566  let whitelisted: boolean = false;567  await usingApi(async (api) => {568    whitelisted = (await api.query.nft.contractWhiteList(contractAddress, user)).toJSON() as boolean;569  });570  return whitelisted;571}572573export async function addToContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {574  await usingApi(async (api) => {575    const tx = api.tx.nft.addToContractWhiteList(contractAddress.toString(), user.toString());576    const events = await submitTransactionAsync(sender, tx);577    const result = getGenericResult(events);578579    expect(result.success).to.be.true;580  });581}582583export async function removeFromContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {584  await usingApi(async (api) => {585    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());586    const events = await submitTransactionAsync(sender, tx);587    const result = getGenericResult(events);588589    expect(result.success).to.be.true;590  });591}592593export async function removeFromContractWhiteListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {594  await usingApi(async (api) => {595    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());596    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;597    const result = getGenericResult(events);598599    expect(result.success).to.be.false;600  });601}602603export async function setVariableMetaDataExpectSuccess(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {604  await usingApi(async (api) => {605    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));606    const events = await submitTransactionAsync(sender, tx);607    const result = getGenericResult(events);608609    expect(result.success).to.be.true;610  });611}612613export async function setVariableMetaDataExpectFailure(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {614  await usingApi(async (api) => {615    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));616    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;617  });618}619620export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {621  await usingApi(async (api) => {622    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));623    const events = await submitTransactionAsync(sender, tx);624    const result = getGenericResult(events);625626    expect(result.success).to.be.true;627  });628}629630export async function setOffchainSchemaExpectFailure(sender: IKeyringPair, collectionId: number, data: number[]) {631  await usingApi(async (api) => {632    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));633    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;634  });635}636637export interface CreateFungibleData {638  readonly Value: bigint;639}640641export interface CreateReFungibleData { }642export interface CreateNftData { }643644export type CreateItemData = {645  NFT: CreateNftData;646} | {647  Fungible: CreateFungibleData;648} | {649  ReFungible: CreateReFungibleData;650};651652export async function burnItemExpectSuccess(owner: IKeyringPair, collectionId: number, tokenId: number, value = 0) {653  await usingApi(async (api) => {654    const tx = api.tx.nft.burnItem(collectionId, tokenId, value);655    const events = await submitTransactionAsync(owner, tx);656    const result = getGenericResult(events);657    // Get the item658    const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();659    // What to expect660    // tslint:disable-next-line:no-unused-expression661    expect(result.success).to.be.true;662    // tslint:disable-next-line:no-unused-expression663    expect(item).to.be.null;664  });665}666667export async function668  approveExpectSuccess(collectionId: number,669    tokenId: number, owner: IKeyringPair, approved: IKeyringPair | CrossAccountId | string, amount: number | bigint = 1) {670  await usingApi(async (api: ApiPromise) => {671    approved = normalizeAccountId(approved);672    const allowanceBefore =673      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;674    const approveNftTx = api.tx.nft.approve(approved, collectionId, tokenId, amount);675    const events = await submitTransactionAsync(owner, approveNftTx);676    const result = getCreateItemResult(events);677    // tslint:disable-next-line:no-unused-expression678    expect(result.success).to.be.true;679    const allowanceAfter =680      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;681    expect(allowanceAfter.sub(allowanceBefore).toString()).to.be.equal(amount.toString());682  });683}684685export async function686  transferFromExpectSuccess(collectionId: number,687    tokenId: number,688    accountApproved: IKeyringPair,689    accountFrom: IKeyringPair | CrossAccountId,690    accountTo: IKeyringPair | CrossAccountId,691    value: number | bigint = 1,692    type: string = 'NFT') {693  await usingApi(async (api: ApiPromise) => {694    const to = normalizeAccountId(accountTo);695    let balanceBefore = new BN(0);696    if (type === 'Fungible') {697      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;698    }699    const transferFromTx = api.tx.nft.transferFrom(700      normalizeAccountId(accountFrom), to, collectionId, tokenId, value);701    const events = await submitTransactionAsync(accountApproved, transferFromTx);702    const result = getCreateItemResult(events);703    // tslint:disable-next-line:no-unused-expression704    expect(result.success).to.be.true;705    if (type === 'NFT') {706      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON() as ITokenDataType;707      expect(nftItemData.Owner).to.be.deep.equal(to);708    }709    if (type === 'Fungible') {710      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;711      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());712    }713    if (type === 'ReFungible') {714      const nftItemData =715        (await api.query.nft.reFungibleItemList(collectionId, tokenId) as any).toJSON() as IReFungibleTokenDataType;716      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(normalizeAccountId(to));717      expect(nftItemData.Owner[0].Fraction).to.be.equal(value);718    }719  });720}721722export async function723  transferFromExpectFail(collectionId: number,724    tokenId: number,725    accountApproved: IKeyringPair,726    accountFrom: IKeyringPair,727    accountTo: IKeyringPair,728    value: number | bigint = 1) {729  await usingApi(async (api: ApiPromise) => {730    const transferFromTx = api.tx.nft.transferFrom(731      normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);732    const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;733    const result = getCreateCollectionResult(events);734    // tslint:disable-next-line:no-unused-expression735    expect(result.success).to.be.false;736  });737}738739async function getBlockNumber(api: ApiPromise): Promise<number> {740  return new Promise<number>(async (resolve, reject) => {741    const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {742        unsubscribe();743        resolve(head.number.toNumber());744    });745  });746}747748export async function749scheduleTransferExpectSuccess(collectionId: number,750                      tokenId: number,751                      sender: IKeyringPair,752                      recipient: IKeyringPair,753                      value: number | bigint = 1,754                      type: string = 'NFT') {755  await usingApi(async (api: ApiPromise) => {756    let balanceBefore = new BN(0);757758759    let blockNumber: number | undefined = await getBlockNumber(api);760    let expectedBlockNumber = blockNumber + 2;761762    expect(blockNumber).to.be.greaterThan(0);763    const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value); 764    const scheduleTx = await api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx);765766    const events = await submitTransactionAsync(sender, scheduleTx);767768    const sponsorBalanceBefore = new BigNumber((await api.query.system.account(sender.address)).data.free.toString());769    const recipientBalanceBefore = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());770771    const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;772    expect(nftItemDataBefore.Owner.toString()).to.be.equal(sender.address);773774    // sleep for 2 blocks775    await new Promise(resolve => setTimeout(resolve, 6000 * 2));776777    const sponsorBalanceAfter = new BigNumber((await api.query.system.account(sender.address)).data.free.toString());778    const recipientBalanceAfter = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());779780    const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;781    expect(nftItemData.Owner.toString()).to.be.equal(recipient.address);782    expect(recipientBalanceAfter.toNumber()).to.be.equal(recipientBalanceBefore.toNumber());783  });784}785786787export async function788  transferExpectSuccess(collectionId: number,789    tokenId: number,790    sender: IKeyringPair,791    recipient: IKeyringPair | CrossAccountId,792    value: number | bigint = 1,793    type: string = 'NFT') {794  await usingApi(async (api: ApiPromise) => {795    const to = normalizeAccountId(recipient);796797    let balanceBefore = new BN(0);798    if (type === 'Fungible') {799      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;800    }801    const transferTx = api.tx.nft.transfer(to, collectionId, tokenId, value);802    const events = await submitTransactionAsync(sender, transferTx);803    const result = getTransferResult(events);804    // tslint:disable-next-line:no-unused-expression805    expect(result.success).to.be.true;806    expect(result.collectionId).to.be.equal(collectionId);807    expect(result.itemId).to.be.equal(tokenId);808    expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));809    expect(result.recipient).to.be.deep.equal(to);810    expect(result.value.toString()).to.be.equal(value.toString());811    if (type === 'NFT') {812      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;813      expect(nftItemData.Owner).to.be.deep.equal(to);814    }815    if (type === 'Fungible') {816      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;817      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());818    }819    if (type === 'ReFungible') {820      const nftItemData =821        (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;822      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(to);823      expect(nftItemData.Owner[0].Fraction.toString()).to.be.equal(value.toString());824    }825  });826}827828export async function829  transferExpectFail(collectionId: number,830    tokenId: number,831    sender: IKeyringPair,832    recipient: IKeyringPair,833    value: number | bigint = 1,834    type: string = 'NFT') {835  await usingApi(async (api: ApiPromise) => {836    const transferTx = api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);837    const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;838    if (events && Array.isArray(events)) {839      const result = getCreateCollectionResult(events);840      // tslint:disable-next-line:no-unused-expression841      expect(result.success).to.be.false;842    }843  });844}845846export async function847  approveExpectFail(collectionId: number,848    tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1) {849  await usingApi(async (api: ApiPromise) => {850    const approveNftTx = api.tx.nft.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);851    const events = await expect(submitTransactionExpectFailAsync(owner, approveNftTx)).to.be.rejected;852    const result = getCreateCollectionResult(events);853    // tslint:disable-next-line:no-unused-expression854    expect(result.success).to.be.false;855  });856}857858export async function getFungibleBalance(859  collectionId: number,860  owner: string,861) {862  return await usingApi(async (api) => {863    const response = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON() as unknown as { Value: string };864    return BigInt(response.Value);865  });866}867868export async function createFungibleItemExpectSuccess(869  sender: IKeyringPair,870  collectionId: number,871  data: CreateFungibleData,872  owner: CrossAccountId | string = sender.address,873) {874  return await usingApi(async (api) => {875    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), { Fungible: data });876877    const events = await submitTransactionAsync(sender, tx);878    const result = getCreateItemResult(events);879880    expect(result.success).to.be.true;881    return result.itemId;882  });883}884885export async function createItemExpectSuccess(886  sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {887  let newItemId: number = 0;888  await usingApi(async (api) => {889    const to = normalizeAccountId(owner);890    const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);891    const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();892    const AItemBalance = new BigNumber(Aitem.Value);893894    let tx;895    if (createMode === 'Fungible') {896      const createData = { fungible: { value: 10 } };897      tx = api.tx.nft.createItem(collectionId, to, createData);898    } else if (createMode === 'ReFungible') {899      const createData = { refungible: { const_data: [], variable_data: [], pieces: 100 } };900      tx = api.tx.nft.createItem(collectionId, to, createData);901    } else {902      tx = api.tx.nft.createItem(collectionId, to, createMode);903    }904905    const events = await submitTransactionAsync(sender, tx);906    const result = getCreateItemResult(events);907908    const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);909    const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();910    const BItemBalance = new BigNumber(Bitem.Value);911912    // What to expect913    // tslint:disable-next-line:no-unused-expression914    expect(result.success).to.be.true;915    if (createMode === 'Fungible') {916      expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10);917    } else {918      expect(BItemCount).to.be.equal(AItemCount + 1);919    }920    expect(collectionId).to.be.equal(result.collectionId);921    expect(BItemCount.toString()).to.be.equal(result.itemId.toString());922    expect(to).to.be.deep.equal(result.recipient);923    newItemId = result.itemId;924  });925  return newItemId;926}927928export async function createItemExpectFailure(929  sender: IKeyringPair, collectionId: number, createMode: string, owner: string = sender.address) {930  await usingApi(async (api) => {931    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), createMode);932    933    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;934    const result = getCreateItemResult(events);935936    expect(result.success).to.be.false;937  });938}939940export async function setPublicAccessModeExpectSuccess(941  sender: IKeyringPair, collectionId: number,942  accessMode: 'Normal' | 'WhiteList',943) {944  await usingApi(async (api) => {945946    // Run the transaction947    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);948    const events = await submitTransactionAsync(sender, tx);949    const result = getGenericResult(events);950951    // Get the collection952    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();953954    // What to expect955    // tslint:disable-next-line:no-unused-expression956    expect(result.success).to.be.true;957    expect(collection.Access).to.be.equal(accessMode);958  });959}960961export async function enableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {962  await setPublicAccessModeExpectSuccess(sender, collectionId, 'WhiteList');963}964965export async function disableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {966  await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');967}968969export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {970  await usingApi(async (api) => {971972    // Run the transaction973    const tx = api.tx.nft.setMintPermission(collectionId, enabled);974    const events = await submitTransactionAsync(sender, tx);975    const result = getGenericResult(events);976977    // Get the collection978    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();979980    // What to expect981    // tslint:disable-next-line:no-unused-expression982    expect(result.success).to.be.true;983    expect(collection.MintMode).to.be.equal(enabled);984  });985}986987export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {988  await setMintPermissionExpectSuccess(sender, collectionId, true);989}990991export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {992  await usingApi(async (api) => {993    // Run the transaction994    const tx = api.tx.nft.setMintPermission(collectionId, enabled);995    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;996    const result = getCreateCollectionResult(events);997    // tslint:disable-next-line:no-unused-expression998    expect(result.success).to.be.false;999  });1000}10011002export async function isWhitelisted(collectionId: number, address: string) {1003  let whitelisted: boolean = false;1004  await usingApi(async (api) => {1005    whitelisted = (await api.query.nft.whiteList(collectionId, address)).toJSON() as unknown as boolean;1006  });1007  return whitelisted;1008}10091010export async function addToWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1011  await usingApi(async (api) => {10121013    const whiteListedBefore = (await api.query.nft.whiteList(collectionId, address)).toJSON();10141015    // Run the transaction1016    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1017    const events = await submitTransactionAsync(sender, tx);1018    const result = getGenericResult(events);10191020    const whiteListedAfter = (await api.query.nft.whiteList(collectionId, address)).toJSON();10211022    // What to expect1023    // tslint:disable-next-line:no-unused-expression1024    expect(result.success).to.be.true;1025    // tslint:disable-next-line: no-unused-expression1026    expect(whiteListedBefore).to.be.false;1027    // tslint:disable-next-line: no-unused-expression1028    expect(whiteListedAfter).to.be.true;1029  });1030}10311032export async function removeFromWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1033  await usingApi(async (api) => {1034    // Run the transaction1035    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1036    const events = await submitTransactionAsync(sender, tx);1037    const result = getGenericResult(events);10381039    // What to expect1040    // tslint:disable-next-line:no-unused-expression1041    expect(result.success).to.be.true;1042  });1043}10441045export async function removeFromWhiteListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1046  await usingApi(async (api) => {1047    // Run the transaction1048    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1049    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1050    const result = getGenericResult(events);10511052    // What to expect1053    // tslint:disable-next-line:no-unused-expression1054    expect(result.success).to.be.false;1055  });1056}10571058export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)1059  : Promise<ICollectionInterface | null> => {1060  return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1061};10621063export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {1064  // set global object - collectionsCount1065  return (await api.query.nft.createdCollectionCount() as unknown as BN).toNumber();1066};10671068export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {1069  return await usingApi(async (api) => {1070    return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1071  });1072}