difftreelog
Merge pull request #159 from usetech-llc/feature/test_environment
in: master
Tests can build
8 files changed
Cargo.lockdiffbeforeafterboth--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5996,34 +5996,34 @@
[[package]]
name = "pallet-scheduler"
version = "3.0.0"
+source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.3#c94e0cdfe5556680dca1996004751eeb114755d7"
dependencies = [
"frame-benchmarking",
"frame-support",
"frame-system",
"log",
"parity-scale-codec 2.1.3",
- "serde",
- "sp-core",
"sp-io",
"sp-runtime",
"sp-std",
- "substrate-test-utils",
- "up-sponsorship",
]
[[package]]
name = "pallet-scheduler"
version = "3.0.0"
-source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v0.9.3#c94e0cdfe5556680dca1996004751eeb114755d7"
dependencies = [
"frame-benchmarking",
"frame-support",
"frame-system",
"log",
"parity-scale-codec 2.1.3",
+ "serde",
+ "sp-core",
"sp-io",
"sp-runtime",
"sp-std",
+ "substrate-test-utils",
+ "up-sponsorship",
]
[[package]]
launch-config.jsondiffbeforeafterboth--- a/launch-config.json
+++ b/launch-config.json
@@ -45,8 +45,15 @@
"nodes": [
{
"port": 31200,
+ "wsPort": "9944",
"name": "alice",
"flags": []
+ },
+ {
+ "port": 31201,
+ "wsPort": "9945",
+ "name": "bob",
+ "flags": []
}
]
}
runtime/src/lib.rsdiffbeforeafterboth--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -216,7 +216,7 @@
/// by Operational extrinsics.
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
/// We allow for 2 seconds of compute with a 6 second average block time.
-const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND;
+const MAXIMUM_BLOCK_WEIGHT: Weight = WEIGHT_PER_SECOND / 2;
parameter_types! {
pub const BlockHashCount: BlockNumber = 2400;
tests/src/config.tsdiffbeforeafterboth--- a/tests/src/config.ts
+++ b/tests/src/config.ts
@@ -6,7 +6,7 @@
import process from 'process';
const config = {
- substrateUrl: process.env.substrateUrl || 'ws://127.0.0.1:9844'
+ substrateUrl: process.env.substrateUrl || 'ws://127.0.0.1:9944'
}
export default config;
\ No newline at end of file
tests/src/contracts.test.tsdiffbeforeafterboth--- a/tests/src/contracts.test.ts
+++ b/tests/src/contracts.test.ts
@@ -177,7 +177,7 @@
const result = getGenericResult(events);
expect(result.success).to.be.true;
- await transferFromExpectSuccess(collectionId, tokenId, bob, contract.address.toString(), charlie, 1, 'NFT');
+ await transferFromExpectSuccess(collectionId, tokenId, bob, normalizeAccountId(contract.address.toString()), charlie, 1, 'NFT');
});
});
tests/src/removeFromWhiteList.test.tsdiffbeforeafterboth--- a/tests/src/removeFromWhiteList.test.ts
+++ b/tests/src/removeFromWhiteList.test.ts
@@ -16,6 +16,7 @@
findNotExistingCollection,
removeFromWhiteListExpectFailure,
disableWhiteListExpectSuccess,
+ normalizeAccountId
} from './util/helpers';
import { IKeyringPair } from '@polkadot/types/types';
import privateKey from './substrate/privateKey';
@@ -40,7 +41,7 @@
await enableWhiteListExpectSuccess(alice, collectionId);
await addToWhiteListExpectSuccess(alice, collectionId, bob.address);
- await removeFromWhiteListExpectSuccess(alice, collectionId, bob.address);
+ await removeFromWhiteListExpectSuccess(alice, collectionId, normalizeAccountId(bob.address));
expect(await isWhitelisted(collectionId, bob.address)).to.be.false;
});
});
@@ -52,7 +53,7 @@
await addToWhiteListExpectSuccess(alice, collectionWithoutWhitelistId, bob.address);
await disableWhiteListExpectSuccess(alice, collectionWithoutWhitelistId);
- await removeFromWhiteListExpectSuccess(alice, collectionWithoutWhitelistId, bob.address);
+ await removeFromWhiteListExpectSuccess(alice, collectionWithoutWhitelistId, normalizeAccountId(bob.address));
});
});
});
@@ -72,7 +73,7 @@
await usingApi(async (api) => {
const collectionId = await findNotExistingCollection(api);
- await removeFromWhiteListExpectFailure(alice, collectionId, bob.address);
+ await removeFromWhiteListExpectFailure(alice, collectionId, normalizeAccountId(bob.address));
});
});
@@ -83,7 +84,7 @@
await addToWhiteListExpectSuccess(alice, collectionId, bob.address);
await destroyCollectionExpectSuccess(collectionId);
- await removeFromWhiteListExpectFailure(alice, collectionId, bob.address);
+ await removeFromWhiteListExpectFailure(alice, collectionId, normalizeAccountId(bob.address));
});
});
});
tests/src/toggleContractWhiteList.test.tsdiffbeforeafterboth--- a/tests/src/toggleContractWhiteList.test.ts
+++ b/tests/src/toggleContractWhiteList.test.ts
@@ -45,14 +45,14 @@
const [contract, deployer] = await deployFlipper(api);
let flipValueBefore = await getFlipValue(contract, deployer);
- const flip = contract.exec('flip', value, gasLimit);
+ const flip = contract.tx.flip(value, gasLimit);
await submitTransactionAsync(bob, flip);
const flipValueAfter = await getFlipValue(contract,deployer);
expect(flipValueAfter).to.be.eq(!flipValueBefore, `Anyone can call new contract.`);
const deployerCanFlip = async () => {
let flipValueBefore = await getFlipValue(contract, deployer);
- const deployerFlip = contract.exec('flip', value, gasLimit);
+ const deployerFlip = contract.tx.flip(value, gasLimit);
await submitTransactionAsync(deployer, deployerFlip);
const aliceFlip1Response = await getFlipValue(contract, deployer);
expect(aliceFlip1Response).to.be.eq(!flipValueBefore, `Deployer always can flip.`);
@@ -62,7 +62,7 @@
flipValueBefore = await getFlipValue(contract, deployer);
const enableWhiteListTx = api.tx.nft.toggleContractWhiteList(contract.address, true);
const enableResult = await submitTransactionAsync(deployer, enableWhiteListTx);
- const flipWithEnabledWhiteList = contract.exec('flip', value, gasLimit);
+ const flipWithEnabledWhiteList = contract.tx.flip(value, gasLimit);
await expect(submitTransactionExpectFailAsync(bob, flipWithEnabledWhiteList)).to.be.rejected;
const flipValueAfterEnableWhiteList = await getFlipValue(contract, deployer);
expect(flipValueAfterEnableWhiteList).to.be.eq(flipValueBefore, `Enabling whitelist doesn't make it possible to call contract for everyone.`);
@@ -72,7 +72,7 @@
flipValueBefore = await getFlipValue(contract, deployer);
const addBobToWhiteListTx = api.tx.nft.addToContractWhiteList(contract.address, bob.address);
const addBobResult = await submitTransactionAsync(deployer, addBobToWhiteListTx);
- const flipWithWhitelistedBob = contract.exec('flip', value, gasLimit);
+ const flipWithWhitelistedBob = contract.tx.flip(value, gasLimit);
await submitTransactionAsync(bob, flipWithWhitelistedBob);
const flipAfterWhiteListed = await getFlipValue(contract,deployer);
expect(flipAfterWhiteListed).to.be.eq(!flipValueBefore, `Bob was whitelisted, now he can flip.`);
@@ -82,7 +82,7 @@
flipValueBefore = await getFlipValue(contract, deployer);
const removeBobFromWhiteListTx = api.tx.nft.removeFromContractWhiteList(contract.address, bob.address);
const removeBobResult = await submitTransactionAsync(deployer, removeBobFromWhiteListTx);
- const bobRemoved = contract.exec('flip', value, gasLimit);
+ const bobRemoved = contract.tx.flip(value, gasLimit);
await expect(submitTransactionExpectFailAsync(bob, bobRemoved)).to.be.rejected;
const afterBobRemoved = await getFlipValue(contract, deployer);
expect(afterBobRemoved).to.be.eq(flipValueBefore, `Bob can't call contract, now when he is removeed from white list.`);
@@ -92,7 +92,7 @@
flipValueBefore = await getFlipValue(contract, deployer);
const disableWhiteListTx = api.tx.nft.toggleContractWhiteList(contract.address, false);
const disableWhiteListResult = await submitTransactionAsync(deployer, disableWhiteListTx);
- const whiteListDisabledFlip = contract.exec('flip', value, gasLimit);
+ const whiteListDisabledFlip = contract.tx.flip(value, gasLimit);
await submitTransactionAsync(bob, whiteListDisabledFlip);
const afterWhiteListDisabled = await getFlipValue(contract,deployer);
expect(afterWhiteListDisabled).to.be.eq(!flipValueBefore, `Anyone can call contract with disabled whitelist.`);
tests/src/util/helpers.tsdiffbeforeafterboth1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56import { ApiPromise, Keyring } from '@polkadot/api';7import { Enum, Struct } from '@polkadot/types/codec';8import type { AccountId, BlockNumber, Call, EventRecord } from '@polkadot/types/interfaces';9import { u128 } from '@polkadot/types/primitive';10import { IKeyringPair } from '@polkadot/types/types';11import { evmToAddress } from '@polkadot/util-crypto';12import { BigNumber } from 'bignumber.js';13import BN from 'bn.js';14import chai from 'chai';15import chaiAsPromised from 'chai-as-promised';16import { alicesPublicKey, nullPublicKey } from '../accounts';17import privateKey from '../substrate/privateKey';18import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from '../substrate/substrate-api';19import { ICollectionInterface } from '../types';20import { hexToStr, strToUTF16, utf16ToStr } from './util';21import { Compact, Option, Raw, Vec } from '@polkadot/types/codec';22// import { AccountId, AccountIdOf, AccountIndex, Address, AssetId, Balance, BalanceOf, Block, BlockNumber, Call, ChangesTrieConfiguration, Consensus, ConsensusEngineId, Digest, DigestItem, DispatchClass, DispatchInfo, DispatchInfoTo190, EcdsaSignature, Ed25519Signature, Extrinsic, ExtrinsicEra, ExtrinsicPayload, ExtrinsicPayloadUnknown, ExtrinsicPayloadV1, ExtrinsicPayloadV2, ExtrinsicPayloadV3, ExtrinsicPayloadV4, ExtrinsicSignatureV1, ExtrinsicSignatureV2, ExtrinsicSignatureV3, ExtrinsicSignatureV4, ExtrinsicUnknown, ExtrinsicV1, ExtrinsicV2, ExtrinsicV3, ExtrinsicV4, Hash, Header, ImmortalEra, Index, Justification, KeyTypeId, KeyValue, LockIdentifier, LookupSource, LookupTarget, Moment, MortalEra, MultiSignature, Origin, Perbill, Percent, Permill, Perquintill, Phantom, PhantomData, PreRuntime, Seal, SealV0, Signature, SignedBlock, SignerPayload, Sr25519Signature, ValidatorId, Weight, WeightMultiplier } from '@polkadot/types/interfaces/runtime';2324chai.use(chaiAsPromised);25const expect = chai.expect;2627export type CrossAccountId = {28 substrate: string,29} | {30 ethereum: string,31};32export function normalizeAccountId(input: string | CrossAccountId | IKeyringPair): CrossAccountId {33 if (typeof input === 'string')34 return { substrate: input };35 if ('address' in input) {36 return { substrate: input.address };37 }38 if ('ethereum' in input) {39 input.ethereum = input.ethereum.toLowerCase();40 }41 return input;42}43export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {44 input = normalizeAccountId(input);45 if ('substrate' in input) {46 return input.substrate;47 } else {48 return evmToAddress(input.ethereum);49 }50}5152export const U128_MAX = (1n << 128n) - 1n;5354type GenericResult = {55 success: boolean,56};5758interface CreateCollectionResult {59 success: boolean;60 collectionId: number;61}6263interface CreateItemResult {64 success: boolean;65 collectionId: number;66 itemId: number;67 recipient?: CrossAccountId;68}6970interface TransferResult {71 success: boolean;72 collectionId: number;73 itemId: number;74 sender?: CrossAccountId;75 recipient?: CrossAccountId;76 value: bigint;77}7879interface IReFungibleOwner {80 Fraction: BN;81 Owner: number[];82}8384interface ITokenDataType {85 Owner: number[];86 ConstData: number[];87 VariableData: number[];88}8990interface IFungibleTokenDataType {91 Value: BN;92}9394interface IGetMessage {95 checkMsgNftMethod: string;96 checkMsgTrsMethod: string;97 checkMsgSysMethod: string;98}99100export interface IReFungibleTokenDataType {101 Owner: IReFungibleOwner[];102 ConstData: number[];103 VariableData: number[];104}105106export function nftEventMessage(events: EventRecord[]): IGetMessage {107 let checkMsgNftMethod: string = '';108 let checkMsgTrsMethod: string = '';109 let checkMsgSysMethod: string = '';110 events.forEach(({ event: { method, section } }) => {111 if (section === 'nft') {112 checkMsgNftMethod = method;113 } else if (section === 'treasury') {114 checkMsgTrsMethod = method;115 } else if (section === 'system') {116 checkMsgSysMethod = method;117 } else { return null; }118 });119 const result: IGetMessage = {120 checkMsgNftMethod,121 checkMsgTrsMethod,122 checkMsgSysMethod,123 };124 return result;125}126127export function getGenericResult(events: EventRecord[]): GenericResult {128 const result: GenericResult = {129 success: false,130 };131 events.forEach(({ phase, event: { data, method, section } }) => {132 // console.log(` ${phase}: ${section}.${method}:: ${data}`);133 if (method === 'ExtrinsicSuccess') {134 result.success = true;135 }136 });137 return result;138}139140141142export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {143 let success = false;144 let collectionId: number = 0;145 events.forEach(({ phase, event: { data, method, section } }) => {146 // console.log(` ${phase}: ${section}.${method}:: ${data}`);147 if (method == 'ExtrinsicSuccess') {148 success = true;149 } else if ((section == 'nft') && (method == 'CollectionCreated')) {150 collectionId = parseInt(data[0].toString());151 }152 });153 const result: CreateCollectionResult = {154 success,155 collectionId,156 };157 return result;158}159160export function getCreateItemResult(events: EventRecord[]): CreateItemResult {161 let success = false;162 let collectionId: number = 0;163 let itemId: number = 0;164 let recipient;165 events.forEach(({ phase, event: { data, method, section } }) => {166 // console.log(` ${phase}: ${section}.${method}:: ${data}`);167 if (method == 'ExtrinsicSuccess') {168 success = true;169 } else if ((section == 'nft') && (method == 'ItemCreated')) {170 collectionId = parseInt(data[0].toString());171 itemId = parseInt(data[1].toString());172 recipient = data[2].toJSON();173 }174 });175 const result: CreateItemResult = {176 success,177 collectionId,178 itemId,179 recipient,180 };181 return result;182}183184export function getTransferResult(events: EventRecord[]): TransferResult {185 const result: TransferResult = {186 success: false,187 collectionId: 0,188 itemId: 0,189 value: 0n,190 };191192 events.forEach(({ event: { data, method, section } }) => {193 if (method === 'ExtrinsicSuccess') {194 result.success = true;195 } else if (section === 'nft' && method === 'Transfer') {196 result.collectionId = +data[0].toString();197 result.itemId = +data[1].toString();198 result.sender = data[2].toJSON() as CrossAccountId;199 result.recipient = data[3].toJSON() as CrossAccountId;200 result.value = BigInt(data[4].toString());201 }202 });203204 return result;205}206207interface Invalid {208 type: 'Invalid';209}210211interface Nft {212 type: 'NFT';213}214215interface Fungible {216 type: 'Fungible';217 decimalPoints: number;218}219220interface ReFungible {221 type: 'ReFungible';222}223224type CollectionMode = Nft | Fungible | ReFungible | Invalid;225226export type CreateCollectionParams = {227 mode: CollectionMode,228 name: string,229 description: string,230 tokenPrefix: string,231};232233const defaultCreateCollectionParams: CreateCollectionParams = {234 description: 'description',235 mode: { type: 'NFT' },236 name: 'name',237 tokenPrefix: 'prefix',238}239240export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {241 const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };242243 let collectionId: number = 0;244 await usingApi(async (api) => {245 // Get number of collections before the transaction246 const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);247248 // Run the CreateCollection transaction249 const alicePrivateKey = privateKey('//Alice');250251 let modeprm = {};252 if (mode.type === 'NFT') {253 modeprm = { nft: null };254 } else if (mode.type === 'Fungible') {255 modeprm = { fungible: mode.decimalPoints };256 } else if (mode.type === 'ReFungible') {257 modeprm = { refungible: null };258 } else if (mode.type === 'Invalid') {259 modeprm = { invalid: null };260 }261262 const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);263 const events = await submitTransactionAsync(alicePrivateKey, tx);264 const result = getCreateCollectionResult(events);265266 // Get number of collections after the transaction267 const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10);268269 // Get the collection270 const collection: any = (await api.query.nft.collectionById(result.collectionId) as any).toJSON();271272 // What to expect273 // tslint:disable-next-line:no-unused-expression274 expect(result.success).to.be.true;275 expect(result.collectionId).to.be.equal(BcollectionCount);276 // tslint:disable-next-line:no-unused-expression277 expect(collection).to.be.not.null;278 expect(BcollectionCount).to.be.equal(AcollectionCount + 1, 'Error: NFT collection NOT created.');279 expect(collection.Owner).to.be.equal(toSubstrateAddress(alicesPublicKey));280 expect(utf16ToStr(collection.Name)).to.be.equal(name);281 expect(utf16ToStr(collection.Description)).to.be.equal(description);282 expect(hexToStr(collection.TokenPrefix)).to.be.equal(tokenPrefix);283284 collectionId = result.collectionId;285 });286287 return collectionId;288}289290export async function createCollectionExpectFailure(params: Partial<CreateCollectionParams> = {}) {291 const { name, description, mode, tokenPrefix } = { ...defaultCreateCollectionParams, ...params };292293 let modeprm = {};294 if (mode.type === 'NFT') {295 modeprm = { nft: null };296 } else if (mode.type === 'Fungible') {297 modeprm = { fungible: mode.decimalPoints };298 } else if (mode.type === 'ReFungible') {299 modeprm = { refungible: null };300 } else if (mode.type === 'Invalid') {301 modeprm = { invalid: null };302 }303304 await usingApi(async (api) => {305 // Get number of collections before the transaction306 const AcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());307308 // Run the CreateCollection transaction309 const alicePrivateKey = privateKey('//Alice');310 const tx = api.tx.nft.createCollection(strToUTF16(name), strToUTF16(description), strToUTF16(tokenPrefix), modeprm);311 const events = await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;312 const result = getCreateCollectionResult(events);313314 // Get number of collections after the transaction315 const BcollectionCount = parseInt((await api.query.nft.createdCollectionCount()).toString());316317 // What to expect318 // tslint:disable-next-line:no-unused-expression319 expect(result.success).to.be.false;320 expect(BcollectionCount).to.be.equal(AcollectionCount, 'Error: Collection with incorrect data created.');321 });322}323324export async function findUnusedAddress(api: ApiPromise, seedAddition = ''): Promise<IKeyringPair> {325 let bal = new BigNumber(0);326 let unused;327 do {328 const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;329 const keyring = new Keyring({ type: 'sr25519' });330 unused = keyring.addFromUri(`//${randomSeed}`);331 bal = new BigNumber((await api.query.system.account(unused.address)).data.free.toString());332 } while (bal.toFixed() != '0');333 return unused;334}335336export async function getAllowance(collectionId: number, tokenId: number, owner: string, approved: string) {337 return await usingApi(async (api) => {338 const bn = await api.query.nft.allowances(collectionId, [tokenId, owner, approved]) as unknown as BN;339 return BigInt(bn.toString());340 });341}342343export function findUnusedAddresses(api: ApiPromise, amount: number): Promise<IKeyringPair[]> {344 return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, '_' + Date.now())));345}346347export async function findNotExistingCollection(api: ApiPromise): Promise<number> {348 const totalNumber = parseInt((await api.query.nft.createdCollectionCount()).toString(), 10) as unknown as number;349 const newCollection: number = totalNumber + 1;350 return newCollection;351}352353function getDestroyResult(events: EventRecord[]): boolean {354 let success: boolean = false;355 events.forEach(({ phase, event: { data, method, section } }) => {356 // console.log(` ${phase}: ${section}.${method}:: ${data}`);357 if (method == 'ExtrinsicSuccess') {358 success = true;359 }360 });361 return success;362}363364export async function destroyCollectionExpectFailure(collectionId: number, senderSeed: string = '//Alice') {365 await usingApi(async (api) => {366 // Run the DestroyCollection transaction367 const alicePrivateKey = privateKey(senderSeed);368 const tx = api.tx.nft.destroyCollection(collectionId);369 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;370 });371}372373export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed: string = '//Alice') {374 await usingApi(async (api) => {375 // Run the DestroyCollection transaction376 const alicePrivateKey = privateKey(senderSeed);377 const tx = api.tx.nft.destroyCollection(collectionId);378 const events = await submitTransactionAsync(alicePrivateKey, tx);379 const result = getDestroyResult(events);380381 // Get the collection382 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();383384 // What to expect385 expect(result).to.be.true;386 expect(collection).to.be.null;387 });388}389390export async function queryCollectionLimits(collectionId: number) {391 return await usingApi(async (api) => {392 return ((await api.query.nft.collectionById(collectionId)).toJSON() as any).Limits;393 });394}395396export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {397 await usingApi(async (api) => {398 const oldLimits = await queryCollectionLimits(collectionId);399 const newLimits = { ...oldLimits as any, ...limits };400 const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);401 const events = await submitTransactionAsync(sender, tx);402 const result = getGenericResult(events);403404 expect(result.success).to.be.true;405 });406}407408export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) {409 await usingApi(async (api) => {410 const oldLimits = await queryCollectionLimits(collectionId);411 const newLimits = { ...oldLimits as any, ...limits };412 const tx = api.tx.nft.setCollectionLimits(collectionId, newLimits);413 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;414 const result = getGenericResult(events);415416 expect(result.success).to.be.false;417 });418}419420export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string) {421 await usingApi(async (api) => {422423 // Run the transaction424 const alicePrivateKey = privateKey('//Alice');425 const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);426 const events = await submitTransactionAsync(alicePrivateKey, tx);427 const result = getGenericResult(events);428429 // Get the collection430 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();431432 // What to expect433 expect(result.success).to.be.true;434 expect(collection.Sponsorship).to.deep.equal({435 unconfirmed: sponsor,436 });437 });438}439440export async function removeCollectionSponsorExpectSuccess(collectionId: number) {441 await usingApi(async (api) => {442443 // Run the transaction444 const alicePrivateKey = privateKey('//Alice');445 const tx = api.tx.nft.removeCollectionSponsor(collectionId);446 const events = await submitTransactionAsync(alicePrivateKey, tx);447 const result = getGenericResult(events);448449 // Get the collection450 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();451452 // What to expect453 expect(result.success).to.be.true;454 expect(collection.Sponsorship).to.be.deep.equal({ disabled: null });455 });456}457458export async function removeCollectionSponsorExpectFailure(collectionId: number) {459 await usingApi(async (api) => {460461 // Run the transaction462 const alicePrivateKey = privateKey('//Alice');463 const tx = api.tx.nft.removeCollectionSponsor(collectionId);464 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;465 });466}467468export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed: string = '//Alice') {469 await usingApi(async (api) => {470471 // Run the transaction472 const alicePrivateKey = privateKey(senderSeed);473 const tx = api.tx.nft.setCollectionSponsor(collectionId, sponsor);474 await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;475 });476}477478export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed: string = '//Alice') {479 await usingApi(async (api) => {480481 // Run the transaction482 const sender = privateKey(senderSeed);483 const tx = api.tx.nft.confirmSponsorship(collectionId);484 const events = await submitTransactionAsync(sender, tx);485 const result = getGenericResult(events);486487 // Get the collection488 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();489490 // What to expect491 expect(result.success).to.be.true;492 expect(collection.Sponsorship).to.be.deep.equal({493 confirmed: sender.address,494 });495 });496}497498499export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed: string = '//Alice') {500 await usingApi(async (api) => {501502 // Run the transaction503 const sender = privateKey(senderSeed);504 const tx = api.tx.nft.confirmSponsorship(collectionId);505 await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;506 });507}508509export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {510 await usingApi(async (api) => {511 const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);512 const events = await submitTransactionAsync(sender, tx);513 const result = getGenericResult(events);514515 expect(result.success).to.be.true;516 });517}518519export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {520 await usingApi(async (api) => {521 const tx = api.tx.nft.enableContractSponsoring(contractAddress, enable);522 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;523 const result = getGenericResult(events);524525 expect(result.success).to.be.false;526 });527}528529export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {530 await usingApi(async (api) => {531 const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);532 const events = await submitTransactionAsync(sender, tx);533 const result = getGenericResult(events);534535 expect(result.success).to.be.true;536 });537}538539export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {540 await usingApi(async (api) => {541 const tx = api.tx.nft.setContractSponsoringRateLimit(contractAddress, rateLimit);542 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;543 const result = getGenericResult(events);544545 expect(result.success).to.be.false;546 });547}548549export async function toggleContractWhitelistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enabled: boolean) {550 await usingApi(async (api) => {551 const tx = api.tx.nft.toggleContractWhiteList(contractAddress, true);552 const events = await submitTransactionAsync(sender, tx);553 const result = getGenericResult(events);554555 expect(result.success).to.be.true;556 });557}558559export async function isWhitelistedInContract(contractAddress: AccountId | string, user: string) {560 let whitelisted: boolean = false;561 await usingApi(async (api) => {562 whitelisted = (await api.query.nft.contractWhiteList(contractAddress, user)).toJSON() as boolean;563 });564 return whitelisted;565}566567export async function addToContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {568 await usingApi(async (api) => {569 const tx = api.tx.nft.addToContractWhiteList(contractAddress.toString(), user.toString());570 const events = await submitTransactionAsync(sender, tx);571 const result = getGenericResult(events);572573 expect(result.success).to.be.true;574 });575}576577export async function removeFromContractWhiteListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {578 await usingApi(async (api) => {579 const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());580 const events = await submitTransactionAsync(sender, tx);581 const result = getGenericResult(events);582583 expect(result.success).to.be.true;584 });585}586587export async function removeFromContractWhiteListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {588 await usingApi(async (api) => {589 const tx = api.tx.nft.removeFromContractWhiteList(contractAddress.toString(), user.toString());590 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;591 const result = getGenericResult(events);592593 expect(result.success).to.be.false;594 });595}596597export async function setVariableMetaDataExpectSuccess(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {598 await usingApi(async (api) => {599 const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));600 const events = await submitTransactionAsync(sender, tx);601 const result = getGenericResult(events);602603 expect(result.success).to.be.true;604 });605}606607export async function setVariableMetaDataExpectFailure(sender: IKeyringPair, collectionId: number, itemId: number, data: number[]) {608 await usingApi(async (api) => {609 const tx = api.tx.nft.setVariableMetaData(collectionId, itemId, '0x' + Buffer.from(data).toString('hex'));610 await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;611 });612}613614export async function setOffchainSchemaExpectSuccess(sender: IKeyringPair, collectionId: number, data: number[]) {615 await usingApi(async (api) => {616 const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));617 const events = await submitTransactionAsync(sender, tx);618 const result = getGenericResult(events);619620 expect(result.success).to.be.true;621 });622}623624export async function setOffchainSchemaExpectFailure(sender: IKeyringPair, collectionId: number, data: number[]) {625 await usingApi(async (api) => {626 const tx = api.tx.nft.setOffchainSchema(collectionId, '0x' + Buffer.from(data).toString('hex'));627 await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;628 });629}630631export interface CreateFungibleData {632 readonly Value: bigint;633}634635export interface CreateReFungibleData { }636export interface CreateNftData { }637638export type CreateItemData = {639 NFT: CreateNftData;640} | {641 Fungible: CreateFungibleData;642} | {643 ReFungible: CreateReFungibleData;644};645646export async function burnItemExpectSuccess(owner: IKeyringPair, collectionId: number, tokenId: number, value = 0) {647 await usingApi(async (api) => {648 const tx = api.tx.nft.burnItem(collectionId, tokenId, value);649 const events = await submitTransactionAsync(owner, tx);650 const result = getGenericResult(events);651 // Get the item652 const item: any = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON();653 // What to expect654 // tslint:disable-next-line:no-unused-expression655 expect(result.success).to.be.true;656 // tslint:disable-next-line:no-unused-expression657 expect(item).to.be.null;658 });659}660661export async function662 approveExpectSuccess(collectionId: number,663 tokenId: number, owner: IKeyringPair, approved: IKeyringPair | CrossAccountId | string, amount: number | bigint = 1) {664 await usingApi(async (api: ApiPromise) => {665 approved = normalizeAccountId(approved);666 const allowanceBefore =667 await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;668 const approveNftTx = api.tx.nft.approve(approved, collectionId, tokenId, amount);669 const events = await submitTransactionAsync(owner, approveNftTx);670 const result = getCreateItemResult(events);671 // tslint:disable-next-line:no-unused-expression672 expect(result.success).to.be.true;673 const allowanceAfter =674 await api.query.nft.allowances(collectionId, [tokenId, owner.address, toSubstrateAddress(approved)]) as unknown as BN;675 expect(allowanceAfter.sub(allowanceBefore).toString()).to.be.equal(amount.toString());676 });677}678679export async function680 transferFromExpectSuccess(collectionId: number,681 tokenId: number,682 accountApproved: IKeyringPair,683 accountFrom: IKeyringPair | CrossAccountId,684 accountTo: IKeyringPair | CrossAccountId,685 value: number | bigint = 1,686 type: string = 'NFT') {687 await usingApi(async (api: ApiPromise) => {688 const to = normalizeAccountId(accountTo);689 let balanceBefore = new BN(0);690 if (type === 'Fungible') {691 balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;692 }693 const transferFromTx = api.tx.nft.transferFrom(694 normalizeAccountId(accountFrom), to, collectionId, tokenId, value);695 const events = await submitTransactionAsync(accountApproved, transferFromTx);696 const result = getCreateItemResult(events);697 // tslint:disable-next-line:no-unused-expression698 expect(result.success).to.be.true;699 if (type === 'NFT') {700 const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId) as any).toJSON() as ITokenDataType;701 expect(nftItemData.Owner).to.be.deep.equal(to);702 }703 if (type === 'Fungible') {704 const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;705 expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());706 }707 if (type === 'ReFungible') {708 const nftItemData =709 (await api.query.nft.reFungibleItemList(collectionId, tokenId) as any).toJSON() as IReFungibleTokenDataType;710 expect(nftItemData.Owner[0].Owner).to.be.deep.equal(normalizeAccountId(to));711 expect(nftItemData.Owner[0].Fraction).to.be.equal(value);712 }713 });714}715716export async function717 transferFromExpectFail(collectionId: number,718 tokenId: number,719 accountApproved: IKeyringPair,720 accountFrom: IKeyringPair,721 accountTo: IKeyringPair,722 value: number | bigint = 1) {723 await usingApi(async (api: ApiPromise) => {724 const transferFromTx = api.tx.nft.transferFrom(725 normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);726 const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;727 const result = getCreateCollectionResult(events);728 // tslint:disable-next-line:no-unused-expression729 expect(result.success).to.be.false;730 });731}732733async function getBlockNumber(api: ApiPromise): Promise<number> {734 return new Promise<number>(async (resolve, reject) => {735 const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {736 unsubscribe();737 resolve(head.number.toNumber());738 });739 });740}741742export async function743scheduleTransferExpectSuccess(collectionId: number,744 tokenId: number,745 sender: IKeyringPair,746 recipient: IKeyringPair,747 value: number | bigint = 1,748 type: string = 'NFT') {749 await usingApi(async (api: ApiPromise) => {750 let balanceBefore = new BN(0);751752753 let blockNumber: number | undefined = await getBlockNumber(api);754 let expectedBlockNumber = blockNumber + 2;755756 expect(blockNumber).to.be.greaterThan(0);757 const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value); 758 const scheduleTx = await api.tx.scheduler.schedule(expectedBlockNumber, null, 0, transferTx);759760 const events = await submitTransactionAsync(sender, scheduleTx);761762 const sponsorBalanceBefore = new BigNumber((await api.query.system.account(sender.address)).data.free.toString());763 const recipientBalanceBefore = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());764765 const nftItemDataBefore = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;766 expect(nftItemDataBefore.Owner.toString()).to.be.equal(sender.address);767768 // sleep for 2 blocks769 await new Promise(resolve => setTimeout(resolve, 6000 * 2));770771 const sponsorBalanceAfter = new BigNumber((await api.query.system.account(sender.address)).data.free.toString());772 const recipientBalanceAfter = new BigNumber((await api.query.system.account(recipient.address)).data.free.toString());773774 const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;775 expect(nftItemData.Owner.toString()).to.be.equal(recipient.address);776 expect(recipientBalanceAfter.toNumber()).to.be.equal(recipientBalanceBefore.toNumber());777 });778}779780781export async function782 transferExpectSuccess(collectionId: number,783 tokenId: number,784 sender: IKeyringPair,785 recipient: IKeyringPair | CrossAccountId,786 value: number | bigint = 1,787 type: string = 'NFT') {788 await usingApi(async (api: ApiPromise) => {789 const to = normalizeAccountId(recipient);790791 let balanceBefore = new BN(0);792 if (type === 'Fungible') {793 balanceBefore = await api.query.nft.balance(collectionId, toSubstrateAddress(to)) as unknown as BN;794 }795 const transferTx = api.tx.nft.transfer(to, collectionId, tokenId, value);796 const events = await submitTransactionAsync(sender, transferTx);797 const result = getTransferResult(events);798 // tslint:disable-next-line:no-unused-expression799 expect(result.success).to.be.true;800 expect(result.collectionId).to.be.equal(collectionId);801 expect(result.itemId).to.be.equal(tokenId);802 expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));803 expect(result.recipient).to.be.deep.equal(to);804 expect(result.value.toString()).to.be.equal(value.toString());805 if (type === 'NFT') {806 const nftItemData = (await api.query.nft.nftItemList(collectionId, tokenId)).toJSON() as unknown as ITokenDataType;807 expect(nftItemData.Owner).to.be.deep.equal(to);808 }809 if (type === 'Fungible') {810 const balanceAfter = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to)) as any).Value as unknown as BN;811 expect(balanceAfter.sub(balanceBefore).toString()).to.be.equal(value.toString());812 }813 if (type === 'ReFungible') {814 const nftItemData =815 (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON() as unknown as IReFungibleTokenDataType;816 expect(nftItemData.Owner[0].Owner).to.be.deep.equal(to);817 expect(nftItemData.Owner[0].Fraction.toString()).to.be.equal(value.toString());818 }819 });820}821822export async function823 transferExpectFail(collectionId: number,824 tokenId: number,825 sender: IKeyringPair,826 recipient: IKeyringPair,827 value: number | bigint = 1,828 type: string = 'NFT') {829 await usingApi(async (api: ApiPromise) => {830 const transferTx = api.tx.nft.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);831 const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;832 if (events && Array.isArray(events)) {833 const result = getCreateCollectionResult(events);834 // tslint:disable-next-line:no-unused-expression835 expect(result.success).to.be.false;836 }837 });838}839840export async function841 approveExpectFail(collectionId: number,842 tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1) {843 await usingApi(async (api: ApiPromise) => {844 const approveNftTx = api.tx.nft.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);845 const events = await expect(submitTransactionExpectFailAsync(owner, approveNftTx)).to.be.rejected;846 const result = getCreateCollectionResult(events);847 // tslint:disable-next-line:no-unused-expression848 expect(result.success).to.be.false;849 });850}851852export async function getFungibleBalance(853 collectionId: number,854 owner: string,855) {856 return await usingApi(async (api) => {857 const response = (await api.query.nft.fungibleItemList(collectionId, owner)).toJSON() as unknown as { Value: string };858 return BigInt(response.Value);859 });860}861862export async function createFungibleItemExpectSuccess(863 sender: IKeyringPair,864 collectionId: number,865 data: CreateFungibleData,866 owner: CrossAccountId | string = sender.address,867) {868 return await usingApi(async (api) => {869 const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), { Fungible: data });870871 const events = await submitTransactionAsync(sender, tx);872 const result = getCreateItemResult(events);873874 expect(result.success).to.be.true;875 return result.itemId;876 });877}878879export async function createItemExpectSuccess(880 sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {881 let newItemId: number = 0;882 await usingApi(async (api) => {883 const to = normalizeAccountId(owner);884 const AItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);885 const Aitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();886 const AItemBalance = new BigNumber(Aitem.Value);887888 let tx;889 if (createMode === 'Fungible') {890 const createData = { fungible: { value: 10 } };891 tx = api.tx.nft.createItem(collectionId, to, createData);892 } else if (createMode === 'ReFungible') {893 const createData = { refungible: { const_data: [], variable_data: [], pieces: 100 } };894 tx = api.tx.nft.createItem(collectionId, to, createData);895 } else {896 tx = api.tx.nft.createItem(collectionId, to, createMode);897 }898899 const events = await submitTransactionAsync(sender, tx);900 const result = getCreateItemResult(events);901902 const BItemCount = parseInt((await api.query.nft.itemListIndex(collectionId)).toString(), 10);903 const Bitem: any = (await api.query.nft.fungibleItemList(collectionId, toSubstrateAddress(to))).toJSON();904 const BItemBalance = new BigNumber(Bitem.Value);905906 // What to expect907 // tslint:disable-next-line:no-unused-expression908 expect(result.success).to.be.true;909 if (createMode === 'Fungible') {910 expect(BItemBalance.minus(AItemBalance).toNumber()).to.be.equal(10);911 } else {912 expect(BItemCount).to.be.equal(AItemCount + 1);913 }914 expect(collectionId).to.be.equal(result.collectionId);915 expect(BItemCount.toString()).to.be.equal(result.itemId.toString());916 expect(to).to.be.deep.equal(result.recipient);917 newItemId = result.itemId;918 });919 return newItemId;920}921922export async function createItemExpectFailure(923 sender: IKeyringPair, collectionId: number, createMode: string, owner: string = sender.address) {924 await usingApi(async (api) => {925 const tx = api.tx.nft.createItem(collectionId, normalizeAccountId(owner), createMode);926 927 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;928 const result = getCreateItemResult(events);929930 expect(result.success).to.be.false;931 });932}933934export async function setPublicAccessModeExpectSuccess(935 sender: IKeyringPair, collectionId: number,936 accessMode: 'Normal' | 'WhiteList',937) {938 await usingApi(async (api) => {939940 // Run the transaction941 const tx = api.tx.nft.setPublicAccessMode(collectionId, accessMode);942 const events = await submitTransactionAsync(sender, tx);943 const result = getGenericResult(events);944945 // Get the collection946 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();947948 // What to expect949 // tslint:disable-next-line:no-unused-expression950 expect(result.success).to.be.true;951 expect(collection.Access).to.be.equal(accessMode);952 });953}954955export async function enableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {956 await setPublicAccessModeExpectSuccess(sender, collectionId, 'WhiteList');957}958959export async function disableWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number) {960 await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');961}962963export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {964 await usingApi(async (api) => {965966 // Run the transaction967 const tx = api.tx.nft.setMintPermission(collectionId, enabled);968 const events = await submitTransactionAsync(sender, tx);969 const result = getGenericResult(events);970971 // Get the collection972 const collection: any = (await api.query.nft.collectionById(collectionId)).toJSON();973974 // What to expect975 // tslint:disable-next-line:no-unused-expression976 expect(result.success).to.be.true;977 expect(collection.MintMode).to.be.equal(enabled);978 });979}980981export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {982 await setMintPermissionExpectSuccess(sender, collectionId, true);983}984985export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {986 await usingApi(async (api) => {987 // Run the transaction988 const tx = api.tx.nft.setMintPermission(collectionId, enabled);989 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;990 const result = getCreateCollectionResult(events);991 // tslint:disable-next-line:no-unused-expression992 expect(result.success).to.be.false;993 });994}995996export async function isWhitelisted(collectionId: number, address: string) {997 let whitelisted: boolean = false;998 await usingApi(async (api) => {999 whitelisted = (await api.query.nft.whiteList(collectionId, address)).toJSON() as unknown as boolean;1000 });1001 return whitelisted;1002}10031004export async function addToWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {1005 await usingApi(async (api) => {10061007 const whiteListedBefore = (await api.query.nft.whiteList(collectionId, address)).toJSON();10081009 // Run the transaction1010 const tx = api.tx.nft.addToWhiteList(collectionId, normalizeAccountId(address));1011 const events = await submitTransactionAsync(sender, tx);1012 const result = getGenericResult(events);10131014 const whiteListedAfter = (await api.query.nft.whiteList(collectionId, address)).toJSON();10151016 // What to expect1017 // tslint:disable-next-line:no-unused-expression1018 expect(result.success).to.be.true;1019 // tslint:disable-next-line: no-unused-expression1020 expect(whiteListedBefore).to.be.false;1021 // tslint:disable-next-line: no-unused-expression1022 expect(whiteListedAfter).to.be.true;1023 });1024}10251026export async function removeFromWhiteListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1027 await usingApi(async (api) => {1028 // Run the transaction1029 const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1030 const events = await submitTransactionAsync(sender, tx);1031 const result = getGenericResult(events);10321033 // What to expect1034 // tslint:disable-next-line:no-unused-expression1035 expect(result.success).to.be.true;1036 });1037}10381039export async function removeFromWhiteListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {1040 await usingApi(async (api) => {1041 // Run the transaction1042 const tx = api.tx.nft.removeFromWhiteList(collectionId, normalizeAccountId(address));1043 const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;1044 const result = getGenericResult(events);10451046 // What to expect1047 // tslint:disable-next-line:no-unused-expression1048 expect(result.success).to.be.false;1049 });1050}10511052export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)1053 : Promise<ICollectionInterface | null> => {1054 return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1055};10561057export const getCreatedCollectionCount = async (api: ApiPromise): Promise<number> => {1058 // set global object - collectionsCount1059 return (await api.query.nft.createdCollectionCount() as unknown as BN).toNumber();1060};10611062export async function queryCollectionExpectSuccess(collectionId: number): Promise<ICollectionInterface> {1063 return await usingApi(async (api) => {1064 return (await api.query.nft.collectionById(collectionId)).toJSON() as unknown as ICollectionInterface;1065 });1066}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}