difftreelog
Tests can build
in: master
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 }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}