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

difftreelog

source

tests/src/util/helpers.ts40.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 { Enum, Struct } from '@polkadot/types/codec';8import type { AccountId, BlockNumber, Call, EventRecord } from '@polkadot/types/interfaces';9import { u128 } from '@polkadot/types/primitive';10import { IKeyringPair } from '@polkadot/types/types';11import { evmToAddress } from '@polkadot/util-crypto';12import { BigNumber } from 'bignumber.js';13import BN from 'bn.js';14import chai from 'chai';15import chaiAsPromised from 'chai-as-promised';16import { alicesPublicKey, nullPublicKey } from '../accounts';17import privateKey from '../substrate/privateKey';18import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api';19import { ICollectionInterface } from '../types';20import { hexToStr, strToUTF16, utf16ToStr } from './util';21import { Compact, Option, Raw, Vec } from '@polkadot/types/codec';22// import { AccountId, AccountIdOf, AccountIndex, Address, AssetId, Balance, BalanceOf, Block, BlockNumber, Call, ChangesTrieConfiguration, Consensus, ConsensusEngineId, Digest, DigestItem, DispatchClass, DispatchInfo, DispatchInfoTo190, EcdsaSignature, Ed25519Signature, Extrinsic, ExtrinsicEra, ExtrinsicPayload, ExtrinsicPayloadUnknown, ExtrinsicPayloadV1, ExtrinsicPayloadV2, ExtrinsicPayloadV3, ExtrinsicPayloadV4, ExtrinsicSignatureV1, ExtrinsicSignatureV2, ExtrinsicSignatureV3, ExtrinsicSignatureV4, ExtrinsicUnknown, ExtrinsicV1, ExtrinsicV2, ExtrinsicV3, ExtrinsicV4, Hash, Header, ImmortalEra, Index, Justification, KeyTypeId, KeyValue, LockIdentifier, LookupSource, LookupTarget, Moment, MortalEra, MultiSignature, Origin, Perbill, Percent, Permill, Perquintill, Phantom, PhantomData, PreRuntime, Seal, SealV0, Signature, SignedBlock, SignerPayload, Sr25519Signature, ValidatorId, Weight, WeightMultiplier } from '@polkadot/types/interfaces/runtime';2324chai.use(chaiAsPromised);25const expect = chai.expect;2627export type CrossAccountId = {28  substrate: string,29} | {30  ethereum: string,31};32export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {33  if (typeof input === 'string')34    return { substrate: input };35  if ('address' in input) {36    return { substrate: input.address };37  }38  if ('ethereum' in input) {39    input.ethereum = input.ethereum.toLowerCase();40    return input;41  }4243  // AccountId44  return {substrate: input.toString()}45}46export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {47  input = normalizeAccountId(input);48  if ('substrate' in input) {49    return input.substrate;50  } else {51    return evmToAddress(input.ethereum);52  }53}5455export const U128_MAX = (1n << 128n) - 1n;5657type GenericResult = {58  success: boolean,59};6061interface CreateCollectionResult {62  success: boolean;63  collectionId: number;64}6566interface CreateItemResult {67  success: boolean;68  collectionId: number;69  itemId: number;70  recipient?: CrossAccountId;71}7273interface TransferResult {74  success: boolean;75  collectionId: number;76  itemId: number;77  sender?: CrossAccountId;78  recipient?: CrossAccountId;79  value: bigint;80}8182interface IReFungibleOwner {83  Fraction: BN;84  Owner: number[];85}8687interface ITokenDataType {88  Owner: number[];89  ConstData: number[];90  VariableData: number[];91}9293interface IFungibleTokenDataType {94  Value: BN;95}9697interface IGetMessage {98  checkMsgNftMethod: string;99  checkMsgTrsMethod: string;100  checkMsgSysMethod: string;101}102103export interface IReFungibleTokenDataType {104  Owner: IReFungibleOwner[];105  ConstData: number[];106  VariableData: number[];107}108109export function nftEventMessage(events: EventRecord[]): IGetMessage {110  let checkMsgNftMethod: string = '';111  let checkMsgTrsMethod: string = '';112  let checkMsgSysMethod: string = '';113  events.forEach(({ event: { method, section } }) => {114    if (section === 'nft') {115      checkMsgNftMethod = method;116    } else if (section === 'treasury') {117      checkMsgTrsMethod = method;118    } else if (section === 'system') {119      checkMsgSysMethod = method;120    } else { return null; }121  });122  const result: IGetMessage = {123    checkMsgNftMethod,124    checkMsgTrsMethod,125    checkMsgSysMethod,126  };127  return result;128}129130export function getGenericResult(events: EventRecord[]): GenericResult {131  const result: GenericResult = {132    success: false,133  };134  events.forEach(({ phase, event: { data, method, section } }) => {135    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);136    if (method === 'ExtrinsicSuccess') {137      result.success = true;138    }139  });140  return result;141}142143144145export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {146  let success = false;147  let collectionId: number = 0;148  events.forEach(({ phase, event: { data, method, section } }) => {149    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);150    if (method == 'ExtrinsicSuccess') {151      success = true;152    } else if ((section == 'nft') && (method == 'CollectionCreated')) {153      collectionId = parseInt(data[0].toString());154    }155  });156  const result: CreateCollectionResult = {157    success,158    collectionId,159  };160  return result;161}162163export function getCreateItemResult(events: EventRecord[]): CreateItemResult {164  let success = false;165  let collectionId: number = 0;166  let itemId: number = 0;167  let recipient;168  events.forEach(({ phase, event: { data, method, section } }) => {169    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);170    if (method == 'ExtrinsicSuccess') {171      success = true;172    } else if ((section == 'nft') && (method == 'ItemCreated')) {173      collectionId = parseInt(data[0].toString());174      itemId = parseInt(data[1].toString());175      recipient = data[2].toJSON();176    }177  });178  const result: CreateItemResult = {179    success,180    collectionId,181    itemId,182    recipient,183  };184  return result;185}186187export function getTransferResult(events: EventRecord[]): TransferResult {188  const result: TransferResult = {189    success: false,190    collectionId: 0,191    itemId: 0,192    value: 0n,193  };194195  events.forEach(({ event: { data, method, section } }) => {196    if (method === 'ExtrinsicSuccess') {197      result.success = true;198    } else if (section === 'nft' && method === 'Transfer') {199      result.collectionId = +data[0].toString();200      result.itemId = +data[1].toString();201      result.sender = data[2].toJSON() as CrossAccountId;202      result.recipient = data[3].toJSON() as CrossAccountId;203      result.value = BigInt(data[4].toString());204    }205  });206207  return result;208}209210interface Invalid {211  type: 'Invalid';212}213214interface Nft {215  type: 'NFT';216}217218interface Fungible {219  type: 'Fungible';220  decimalPoints: number;221}222223interface ReFungible {224  type: 'ReFungible';225}226227type CollectionMode = Nft | Fungible | ReFungible | Invalid;228229export type CreateCollectionParams = {230  mode: CollectionMode,231  name: string,232  description: string,233  tokenPrefix: string,234};235236const defaultCreateCollectionParams: CreateCollectionParams = {237  description: 'description',238  mode: { type: 'NFT' },239  name: 'name',240  tokenPrefix: 'prefix',241}242243export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {244  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };245246  let collectionId: number = 0;247  await usingApi(async (api) => {248    // Get number of collections before the transaction249    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);250251    // Run the CreateCollection transaction252    const alicePrivateKey = privateKey('//Alice');253254    let modeprm = {};255    if (mode.type === 'NFT') {256      modeprm = { nft: null };257    } else if (mode.type === 'Fungible') {258      modeprm = { fungible: mode.decimalPoints };259    } else if (mode.type === 'ReFungible') {260      modeprm = { refungible: null };261    } else if (mode.type === 'Invalid') {262      modeprm = { invalid: null };263    }264265    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);266    const events = await submitTransactionAsync(alicePrivateKey, tx);267    const result = getCreateCollectionResult(events);268269    // Get number of collections after the transaction270    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);271272    // Get the collection273    const collection: any = (await api.query.nft.collectionById(result.collectionId) as any).toJSON();274275    // What to expect276    // tslint:disable-next-line:no-unused-expression277    expect(result.success).to.be.true;278    expect(result.collectionId).to.be.equal(BcollectionCount);279    // tslint:disable-next-line:no-unused-expression280    expect(collection).to.be.not.null;281    expect(BcollectionCount).to.be.equal(AcollectionCount + 1, 'Error: NFT collection NOT created.');282    expect(collection.Owner).to.be.equal(toSubstrateAddress(alicesPublicKey));283    expect(utf16ToStr(collection.Name)).to.be.equal(name);284    expect(utf16ToStr(collection.Description)).to.be.equal(description);285    expect(hexToStr(collection.TokenPrefix)).to.be.equal(tokenPrefix);286287    collectionId = result.collectionId;288  });289290  return collectionId;291}292293export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {294  const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };295296  let modeprm = {};297  if (mode.type === 'NFT') {298    modeprm = { nft: null };299  } else if (mode.type === 'Fungible') {300    modeprm = { fungible: mode.decimalPoints };301  } else if (mode.type === 'ReFungible') {302    modeprm = { refungible: null };303  } else if (mode.type === 'Invalid') {304    modeprm = { invalid: null };305  }306307  await usingApi(async (api) => {308    // Get number of collections before the transaction309    const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());310311    // Run the CreateCollection transaction312    const alicePrivateKey = privateKey('//Alice');313    const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);314    const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;315    const result = getCreateCollectionResult(events);316317    // Get number of collections after the transaction318    const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());319320    // What to expect321    // tslint:disable-next-line:no-unused-expression322    expect(result.success).to.be.false;323    expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');324  });325}326327export async function findUnusedAddress(api: ApiPromise, seedAddition = ''): Promise<IKeyringPair> {328  let bal = new BigNumber(0);329  let unused;330  do {331    const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;332    const keyring = new Keyring({ type: 'sr25519' });333    unused = keyring.addFromUri(`//${randomSeed}`);334    bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());335  } while (bal.toFixed() != '0');336  return unused;337}338339export async function getAllowance(collectionId: number, tokenId: number, owner: string, approved: string) {340  return await usingApi(async (api) => {341    const bn = await api.query.nft.allowances(collectionId, [tokenId, owner, approved]) as unknown as BN;342    return BigInt(bn.toString());343  });344}345346export function findUnusedAddresses(api: ApiPromise, amount: number): Promise<IKeyringPair[]> {347  return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, '_' + Date.now())));348}349350export async function findNotExistingCollection(api: ApiPromise): Promise<number> {351  const totalNumber = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10) as unknown as number;352  const newCollection: number = totalNumber + 1;353  return newCollection;354}355356function getDestroyResult(events: EventRecord[]): boolean {357  let success: boolean = false;358  events.forEach(({ phase, event: { data, method, section } }) => {359    // console.log(`    ${phase}: ${section}.${method}:: ${data}`);360    if (method == 'ExtrinsicSuccess') {361      success = true;362    }363  });364  return success;365}366367export async function destroyCollectionExpectFailure(collectionId: number, senderSeed: string = '//Alice') {368  await usingApi(async (api) => {369    // Run the DestroyCollection transaction370    const alicePrivateKey = privateKey(senderSeed);371    const tx = api.tx.nft.destroyCollection(collectionId);372    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;373  });374}375376export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed: string = '//Alice') {377  await usingApi(async (api) => {378    // Run the DestroyCollection transaction379    const alicePrivateKey = privateKey(senderSeed);380    const tx = api.tx.nft.destroyCollection(collectionId);381    const events = await submitTransactionAsync(alicePrivateKey, tx);382    const result = getDestroyResult(events);383384    // Get the collection385    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();386387    // What to expect388    expect(result).to.be.true;389    expect(collection).to.be.null;390  });391}392393export async function queryCollectionLimits(collectionId: number) {394  return await usingApi(async (api) => {395    return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;396  });397}398399export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {400  await usingApi(async (api) => {401    const oldLimits = await queryCollectionLimits(collectionId);402    const newLimits = { ...oldLimits as any, ...limits };403    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);404    const events = await submitTransactionAsync(sender, tx);405    const result = getGenericResult(events);406407    expect(result.success).to.be.true;408  });409}410411export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) {412  await usingApi(async (api) => {413    const oldLimits = await queryCollectionLimits(collectionId);414    const newLimits = { ...oldLimits as any, ...limits };415    const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);416    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;417    const result = getGenericResult(events);418419    expect(result.success).to.be.false;420  });421}422423export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string) {424  await usingApi(async (api) => {425426    // Run the transaction427    const alicePrivateKey = privateKey('//Alice');428    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);429    const events = await submitTransactionAsync(alicePrivateKey, tx);430    const result = getGenericResult(events);431432    // Get the collection433    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();434435    // What to expect436    expect(result.success).to.be.true;437    expect(collection.Sponsorship).to.deep.equal({438      unconfirmed: sponsor,439    });440  });441}442443export async function removeCollectionSponsorExpectSuccess(collectionId: number) {444  await usingApi(async (api) => {445446    // Run the transaction447    const alicePrivateKey = privateKey('//Alice');448    const tx = api.tx.nft.removeCollectionSponsor(collectionId);449    const events = await submitTransactionAsync(alicePrivateKey, tx);450    const result = getGenericResult(events);451452    // Get the collection453    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();454455    // What to expect456    expect(result.success).to.be.true;457    expect(collection.Sponsorship).to.be.deep.equal({ disabled: null });458  });459}460461export async function removeCollectionSponsorExpectFailure(collectionId: number) {462  await usingApi(async (api) => {463464    // Run the transaction465    const alicePrivateKey = privateKey('//Alice');466    const tx = api.tx.nft.removeCollectionSponsor(collectionId);467    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;468  });469}470471export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed: string = '//Alice') {472  await usingApi(async (api) => {473474    // Run the transaction475    const alicePrivateKey = privateKey(senderSeed);476    const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);477    await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;478  });479}480481export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed: string = '//Alice') {482  await usingApi(async (api) => {483484    // Run the transaction485    const sender = privateKey(senderSeed);486    const tx = api.tx.nft.confirmSponsorship(collectionId);487    const events = await submitTransactionAsync(sender, tx);488    const result = getGenericResult(events);489490    // Get the collection491    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();492493    // What to expect494    expect(result.success).to.be.true;495    expect(collection.Sponsorship).to.be.deep.equal({496      confirmed: sender.address,497    });498  });499}500501502export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed: string = '//Alice') {503  await usingApi(async (api) => {504505    // Run the transaction506    const sender = privateKey(senderSeed);507    const tx = api.tx.nft.confirmSponsorship(collectionId);508    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;509  });510}511512export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {513  await usingApi(async (api) => {514    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);515    const events = await submitTransactionAsync(sender, tx);516    const result = getGenericResult(events);517518    expect(result.success).to.be.true;519  });520}521522export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {523  await usingApi(async (api) => {524    const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);525    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;526    const result = getGenericResult(events);527528    expect(result.success).to.be.false;529  });530}531532export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {533  await usingApi(async (api) => {534    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);535    const events = await submitTransactionAsync(sender, tx);536    const result = getGenericResult(events);537538    expect(result.success).to.be.true;539  });540}541542export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {543  await usingApi(async (api) => {544    const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);545    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;546    const result = getGenericResult(events);547548    expect(result.success).to.be.false;549  });550}551552export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enabled: boolean) {553  await usingApi(async (api) => {554    const tx = api.tx.nft.toggleContractWhiteList(contractAddress, true);555    const events = await submitTransactionAsync(sender, tx);556    const result = getGenericResult(events);557558    expect(result.success).to.be.true;559  });560}561562export async function isWhitelistedInContract(contractAddress: AccountId | string, user: string) {563  let whitelisted: boolean = false;564  await usingApi(async (api) => {565    whitelisted = (await api.query.nft.contractWhiteList(contractAddress, user)).toJSON() as boolean;566  });567  return whitelisted;568}569570export async function addToContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {571  await usingApi(async (api) => {572    const tx = api.tx.nft.addToContractWhiteList(contractAddress.toString(), user.toString());573    const events = await submitTransactionAsync(sender, tx);574    const result = getGenericResult(events);575576    expect(result.success).to.be.true;577  });578}579580export async function removeFromContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {581  await usingApi(async (api) => {582    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());583    const events = await submitTransactionAsync(sender, tx);584    const result = getGenericResult(events);585586    expect(result.success).to.be.true;587  });588}589590export async function removeFromContractWhiteListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {591  await usingApi(async (api) => {592    const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());593    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;594    const result = getGenericResult(events);595596    expect(result.success).to.be.false;597  });598}599600export async function setVariableMetaDataExpectSuccess(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {601  await usingApi(async (api) => {602    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));603    const events = await submitTransactionAsync(sender, tx);604    const result = getGenericResult(events);605606    expect(result.success).to.be.true;607  });608}609610export async function setVariableMetaDataExpectFailure(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {611  await usingApi(async (api) => {612    const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));613    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;614  });615}616617export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {618  await usingApi(async (api) => {619    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));620    const events = await submitTransactionAsync(sender, tx);621    const result = getGenericResult(events);622623    expect(result.success).to.be.true;624  });625}626627export async function setOffchainSchemaExpectFailure(sender: IKeyringPair, collectionId: number, data: number[]) {628  await usingApi(async (api) => {629    const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));630    await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;631  });632}633634export interface CreateFungibleData {635  readonly Value: bigint;636}637638export interface CreateReFungibleData { }639export interface CreateNftData { }640641export type CreateItemData = {642  NFT: CreateNftData;643} | {644  Fungible: CreateFungibleData;645} | {646  ReFungible: CreateReFungibleData;647};648649export async function burnItemExpectSuccess(owner: IKeyringPair, collectionId: number, tokenId: number, value = 0) {650  await usingApi(async (api) => {651    const tx = api.tx.nft.burnItem(collectionId, tokenId, value);652    const events = await submitTransactionAsync(owner, tx);653    const result = getGenericResult(events);654    // Get the item655    const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();656    // What to expect657    // tslint:disable-next-line:no-unused-expression658    expect(result.success).to.be.true;659    // tslint:disable-next-line:no-unused-expression660    expect(item).to.be.null;661  });662}663664export async function665  approveExpectSuccess(collectionId: number,666    tokenId: number, owner: IKeyringPair, approved: IKeyringPair | CrossAccountId | string, amount: number | bigint = 1) {667  await usingApi(async (api: ApiPromise) => {668    approved = normalizeAccountId(approved);669    const allowanceBefore =670      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;671    const approveNftTx = api.tx.nft.approve(approved, collectionId, tokenId, amount);672    const events = await submitTransactionAsync(owner, approveNftTx);673    const result = getCreateItemResult(events);674    // tslint:disable-next-line:no-unused-expression675    expect(result.success).to.be.true;676    const allowanceAfter =677      await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;678    expect(allowanceAfter.sub(allowanceBefore).toString()).to.be.equal(amount.toString());679  });680}681682export async function683  transferFromExpectSuccess(collectionId: number,684    tokenId: number,685    accountApproved: IKeyringPair,686    accountFrom: IKeyringPair | CrossAccountId,687    accountTo: IKeyringPair | CrossAccountId,688    value: number | bigint = 1,689    type: string = 'NFT') {690  await usingApi(async (api: ApiPromise) => {691    const to = normalizeAccountId(accountTo);692    let balanceBefore = new BN(0);693    if (type === 'Fungible') {694      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;695    }696    const transferFromTx = api.tx.nft.transferFrom(697      normalizeAccountId(accountFrom), to, collectionId, tokenId, value);698    const events = await submitTransactionAsync(accountApproved, transferFromTx);699    const result = getCreateItemResult(events);700    // tslint:disable-next-line:no-unused-expression701    expect(result.success).to.be.true;702    if (type === 'NFT') {703      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON() as ITokenDataType;704      expect(nftItemData.Owner).to.be.deep.equal(to);705    }706    if (type === 'Fungible') {707      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;708      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());709    }710    if (type === 'ReFungible') {711      const nftItemData =712        (await api.query.nft.reFungibleItemList(collectionId, tokenId) as any).toJSON() as IReFungibleTokenDataType;713      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(normalizeAccountId(to));714      expect(nftItemData.Owner[0].Fraction).to.be.equal(value);715    }716  });717}718719export async function720  transferFromExpectFail(collectionId: number,721    tokenId: number,722    accountApproved: IKeyringPair,723    accountFrom: IKeyringPair,724    accountTo: IKeyringPair,725    value: number | bigint = 1) {726  await usingApi(async (api: ApiPromise) => {727    const transferFromTx = api.tx.nft.transferFrom(728      normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);729    const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;730    const result = getCreateCollectionResult(events);731    // tslint:disable-next-line:no-unused-expression732    expect(result.success).to.be.false;733  });734}735736async function getBlockNumber(api: ApiPromise): Promise<number> {737  return new Promise<number>(async (resolve, reject) => {738    const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {739        unsubscribe();740        resolve(head.number.toNumber());741    });742  });743}744745export async function746scheduleTransferExpectSuccess(collectionId: number,747                      tokenId: number,748                      sender: IKeyringPair,749                      recipient: IKeyringPair,750                      value: number | bigint = 1,751                      type: string = 'NFT') {752  await usingApi(async (api: ApiPromise) => {753    let balanceBefore = new BN(0);754755756    let blockNumber: number | undefined = await getBlockNumber(api);757    let expectedBlockNumber = blockNumber + 2;758759    expect(blockNumber).to.be.greaterThan(0);760    const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value); 761    const scheduleTx = await api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx);762763    const events = await submitTransactionAsync(sender, scheduleTx);764765    const sponsorBalanceBefore = new BigNumber((await api.query.system.account(sender.address)).data.free.toString());766    const recipientBalanceBefore = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());767768    const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;769    expect(nftItemDataBefore.Owner.toString()).to.be.equal(sender.address);770771    // sleep for 2 blocks772    await new Promise(resolve => setTimeout(resolve, 6000 * 2));773774    const sponsorBalanceAfter = new BigNumber((await api.query.system.account(sender.address)).data.free.toString());775    const recipientBalanceAfter = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());776777    const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;778    expect(nftItemData.Owner.toString()).to.be.equal(recipient.address);779    expect(recipientBalanceAfter.toNumber()).to.be.equal(recipientBalanceBefore.toNumber());780  });781}782783784export async function785  transferExpectSuccess(collectionId: number,786    tokenId: number,787    sender: IKeyringPair,788    recipient: IKeyringPair | CrossAccountId,789    value: number | bigint = 1,790    type: string = 'NFT') {791  await usingApi(async (api: ApiPromise) => {792    const to = normalizeAccountId(recipient);793794    let balanceBefore = new BN(0);795    if (type === 'Fungible') {796      balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;797    }798    const transferTx = api.tx.nft.transfer(to, collectionId, tokenId, value);799    const events = await submitTransactionAsync(sender, transferTx);800    const result = getTransferResult(events);801    // tslint:disable-next-line:no-unused-expression802    expect(result.success).to.be.true;803    expect(result.collectionId).to.be.equal(collectionId);804    expect(result.itemId).to.be.equal(tokenId);805    expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));806    expect(result.recipient).to.be.deep.equal(to);807    expect(result.value.toString()).to.be.equal(value.toString());808    if (type === 'NFT') {809      const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;810      expect(nftItemData.Owner).to.be.deep.equal(to);811    }812    if (type === 'Fungible') {813      const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;814      expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());815    }816    if (type === 'ReFungible') {817      const nftItemData =818        (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;819      expect(nftItemData.Owner[0].Owner).to.be.deep.equal(to);820      expect(nftItemData.Owner[0].Fraction.toString()).to.be.equal(value.toString());821    }822  });823}824825export async function826  transferExpectFail(collectionId: number,827    tokenId: number,828    sender: IKeyringPair,829    recipient: IKeyringPair,830    value: number | bigint = 1,831    type: string = 'NFT') {832  await usingApi(async (api: ApiPromise) => {833    const transferTx = api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);834    const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;835    if (events && Array.isArray(events)) {836      const result = getCreateCollectionResult(events);837      // tslint:disable-next-line:no-unused-expression838      expect(result.success).to.be.false;839    }840  });841}842843export async function844  approveExpectFail(collectionId: number,845    tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1) {846  await usingApi(async (api: ApiPromise) => {847    const approveNftTx = api.tx.nft.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);848    const events = await expect(submitTransactionExpectFailAsync(owner, approveNftTx)).to.be.rejected;849    const result = getCreateCollectionResult(events);850    // tslint:disable-next-line:no-unused-expression851    expect(result.success).to.be.false;852  });853}854855export async function getFungibleBalance(856  collectionId: number,857  owner: string,858) {859  return await usingApi(async (api) => {860    const response = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON() as unknown as { Value: string };861    return BigInt(response.Value);862  });863}864865export async function createFungibleItemExpectSuccess(866  sender: IKeyringPair,867  collectionId: number,868  data: CreateFungibleData,869  owner: CrossAccountId | string = sender.address,870) {871  return await usingApi(async (api) => {872    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), { Fungible: data });873874    const events = await submitTransactionAsync(sender, tx);875    const result = getCreateItemResult(events);876877    expect(result.success).to.be.true;878    return result.itemId;879  });880}881882export async function createItemExpectSuccess(883  sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {884  let newItemId: number = 0;885  await usingApi(async (api) => {886    const to = normalizeAccountId(owner);887    const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);888    const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();889    const AItemBalance = new BigNumber(Aitem.Value);890891    let tx;892    if (createMode === 'Fungible') {893      const createData = { fungible: { value: 10 } };894      tx = api.tx.nft.createItem(collectionId, to, createData);895    } else if (createMode === 'ReFungible') {896      const createData = { refungible: { const_data: [], variable_data: [], pieces: 100 } };897      tx = api.tx.nft.createItem(collectionId, to, createData);898    } else {899      tx = api.tx.nft.createItem(collectionId, to, createMode);900    }901902    const events = await submitTransactionAsync(sender, tx);903    const result = getCreateItemResult(events);904905    const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);906    const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();907    const BItemBalance = new BigNumber(Bitem.Value);908909    // What to expect910    // tslint:disable-next-line:no-unused-expression911    expect(result.success).to.be.true;912    if (createMode === 'Fungible') {913      expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10);914    } else {915      expect(BItemCount).to.be.equal(AItemCount + 1);916    }917    expect(collectionId).to.be.equal(result.collectionId);918    expect(BItemCount.toString()).to.be.equal(result.itemId.toString());919    expect(to).to.be.deep.equal(result.recipient);920    newItemId = result.itemId;921  });922  return newItemId;923}924925export async function createItemExpectFailure(926  sender: IKeyringPair, collectionId: number, createMode: string, owner: string = sender.address) {927  await usingApi(async (api) => {928    const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), createMode);929    930    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;931    const result = getCreateItemResult(events);932933    expect(result.success).to.be.false;934  });935}936937export async function setPublicAccessModeExpectSuccess(938  sender: IKeyringPair, collectionId: number,939  accessMode: 'Normal' | 'WhiteList',940) {941  await usingApi(async (api) => {942943    // Run the transaction944    const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);945    const events = await submitTransactionAsync(sender, tx);946    const result = getGenericResult(events);947948    // Get the collection949    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();950951    // What to expect952    // tslint:disable-next-line:no-unused-expression953    expect(result.success).to.be.true;954    expect(collection.Access).to.be.equal(accessMode);955  });956}957958export async function enableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {959  await setPublicAccessModeExpectSuccess(sender, collectionId, 'WhiteList');960}961962export async function disableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {963  await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');964}965966export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {967  await usingApi(async (api) => {968969    // Run the transaction970    const tx = api.tx.nft.setMintPermission(collectionId, enabled);971    const events = await submitTransactionAsync(sender, tx);972    const result = getGenericResult(events);973974    // Get the collection975    const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();976977    // What to expect978    // tslint:disable-next-line:no-unused-expression979    expect(result.success).to.be.true;980    expect(collection.MintMode).to.be.equal(enabled);981  });982}983984export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {985  await setMintPermissionExpectSuccess(sender, collectionId, true);986}987988export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {989  await usingApi(async (api) => {990    // Run the transaction991    const tx = api.tx.nft.setMintPermission(collectionId, enabled);992    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;993    const result = getCreateCollectionResult(events);994    // tslint:disable-next-line:no-unused-expression995    expect(result.success).to.be.false;996  });997}998999export async function isWhitelisted(collectionId: number, address: string) {1000  let whitelisted: boolean = false;1001  await usingApi(async (api) => {1002    whitelisted = (await api.query.nft.whiteList(collectionId, address)).toJSON() as unknown as boolean;1003  });1004  return whitelisted;1005}10061007export async function addToWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1008  await usingApi(async (api) => {10091010    const whiteListedBefore = (await api.query.nft.whiteList(collectionId, address)).toJSON();10111012    // Run the transaction1013    const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1014    const events = await submitTransactionAsync(sender, tx);1015    const result = getGenericResult(events);10161017    const whiteListedAfter = (await api.query.nft.whiteList(collectionId, address)).toJSON();10181019    // What to expect1020    // tslint:disable-next-line:no-unused-expression1021    expect(result.success).to.be.true;1022    // tslint:disable-next-line: no-unused-expression1023    expect(whiteListedBefore).to.be.false;1024    // tslint:disable-next-line: no-unused-expression1025    expect(whiteListedAfter).to.be.true;1026  });1027}10281029export async function removeFromWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1030  await usingApi(async (api) => {1031    // Run the transaction1032    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1033    const events = await submitTransactionAsync(sender, tx);1034    const result = getGenericResult(events);10351036    // What to expect1037    // tslint:disable-next-line:no-unused-expression1038    expect(result.success).to.be.true;1039  });1040}10411042export async function removeFromWhiteListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1043  await usingApi(async (api) => {1044    // Run the transaction1045    const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1046    const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1047    const result = getGenericResult(events);10481049    // What to expect1050    // tslint:disable-next-line:no-unused-expression1051    expect(result.success).to.be.false;1052  });1053}10541055export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)1056  : Promise<ICollectionInterface | null> => {1057  return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1058};10591060export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {1061  // set global object - collectionsCount1062  return (await api.query.nft.createdCollectionCount() as unknown as BN).toNumber();1063};10641065export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {1066  return await usingApi(async (api) => {1067    return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1068  });1069}