--- a/tests/src/deprecated-helpers/contracthelpers.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see .
-
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import {submitTransactionAsync, submitTransactionExpectFailAsync} from '../substrate/substrate-api';
-import fs from 'fs';
-import {Abi, CodePromise, ContractPromise as Contract} from '@polkadot/api-contract';
-import {IKeyringPair} from '@polkadot/types/types';
-import {ApiPromise} from '@polkadot/api';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-import {findUnusedAddress, getGenericResult} from './helpers';
-
-const value = 0;
-const gasLimit = '200000000000';
-const endowment = '100000000000000000';
-
-/* eslint no-async-promise-executor: "off" */
-function deployContract(alice: IKeyringPair, code: CodePromise, constructor = 'default', ...args: any[]): Promise {
- return new Promise(async (resolve) => {
- const unsub = await (code as any)
- .tx[constructor]({value: endowment, gasLimit}, ...args)
- .signAndSend(alice, (result: any) => {
- if (result.status.isInBlock || result.status.isFinalized) {
- // here we have an additional field in the result, containing the blueprint
- resolve((result as any).contract);
- unsub();
- }
- });
- });
-}
-
-async function prepareDeployer(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair) {
- // Find unused address
- const deployer = await findUnusedAddress(api, privateKeyWrapper);
-
- // Transfer balance to it
- const alice = privateKeyWrapper('//Alice');
- const amount = BigInt(endowment) + 10n**15n;
- const tx = api.tx.balances.transfer(deployer.address, amount);
- await submitTransactionAsync(alice, tx);
-
- return deployer;
-}
-
-export async function deployFlipper(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair): Promise<[Contract, IKeyringPair]> {
- const metadata = JSON.parse(fs.readFileSync('./src/flipper/metadata.json').toString('utf-8'));
- const abi = new Abi(metadata);
-
- const deployer = await prepareDeployer(api, privateKeyWrapper);
-
- const wasm = fs.readFileSync('./src/flipper/flipper.wasm');
-
- const code = new CodePromise(api, abi, wasm);
-
- const contract = (await deployContract(deployer, code, 'new', true)) as Contract;
-
- const initialGetResponse = await getFlipValue(contract, deployer);
- expect(initialGetResponse).to.be.true;
-
- return [contract, deployer];
-}
-
-export async function getFlipValue(contract: Contract, deployer: IKeyringPair) {
- const result = await contract.query.get(deployer.address, {value, gasLimit});
-
- if(!result.result.isOk) {
- throw 'Failed to get flipper value';
- }
- return (result.result.asOk.data[0] == 0x00) ? false : true;
-}
-
-export async function toggleFlipValueExpectSuccess(sender: IKeyringPair, contract: Contract) {
- const tx = contract.tx.flip({value, gasLimit});
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- expect(result.success).to.be.true;
-}
-
-export async function toggleFlipValueExpectFailure(sender: IKeyringPair, contract: Contract) {
- const tx = contract.tx.flip({value, gasLimit});
- await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
-}
-
-export async function deployTransferContract(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair): Promise<[Contract, IKeyringPair]> {
- const metadata = JSON.parse(fs.readFileSync('./src/transfer_contract/metadata.json').toString('utf-8'));
- const abi = new Abi(metadata);
-
- const deployer = await prepareDeployer(api, privateKeyWrapper);
-
- const wasm = fs.readFileSync('./src/transfer_contract/nft_transfer.wasm');
-
- const code = new CodePromise(api, abi, wasm);
-
- const contract = await deployContract(deployer, code);
-
- return [contract, deployer];
-}
--- a/tests/src/deprecated-helpers/eth/helpers.d.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see .
-
-declare module 'solc';
\ No newline at end of file
--- a/tests/src/deprecated-helpers/eth/helpers.ts
+++ /dev/null
@@ -1,451 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see .
-
-// eslint-disable-next-line @typescript-eslint/triple-slash-reference
-///
-
-import {ApiPromise} from '@polkadot/api';
-import {IKeyringPair} from '@polkadot/types/types';
-import {addressToEvm, evmToAddress} from '@polkadot/util-crypto';
-import {expect} from 'chai';
-import * as solc from 'solc';
-import Web3 from 'web3';
-import config from '../../config';
-import getBalance from '../../substrate/get-balance';
-import usingApi, {submitTransactionAsync} from '../../substrate/substrate-api';
-import waitNewBlocks from '../../substrate/wait-new-blocks';
-import {CollectionMode, CrossAccountId, getDetailedCollectionInfo, getGenericResult, UNIQUE} from '../helpers';
-import collectionHelpersAbi from '../../eth/collectionHelpersAbi.json';
-import fungibleAbi from '../../eth/fungibleAbi.json';
-import nonFungibleAbi from '../../eth/nonFungibleAbi.json';
-import refungibleAbi from '../../eth/reFungibleAbi.json';
-import refungibleTokenAbi from '../../eth/reFungibleTokenAbi.json';
-import contractHelpersAbi from '../../eth/util/contractHelpersAbi.json';
-
-export const GAS_ARGS = {gas: 2500000};
-
-export enum SponsoringMode {
- Disabled = 0,
- Allowlisted = 1,
- Generous = 2,
-}
-
-let web3Connected = false;
-export async function usingWeb3(cb: (web3: Web3) => Promise | T): Promise {
- if (web3Connected) throw new Error('do not nest usingWeb3 calls');
- web3Connected = true;
-
- const provider = new Web3.providers.WebsocketProvider(config.substrateUrl);
- const web3 = new Web3(provider);
-
- try {
- return await cb(web3);
- } finally {
- // provider.disconnect(3000, 'normal disconnect');
- provider.connection.close();
- web3Connected = false;
- }
-}
-
-function encodeIntBE(v: number): number[] {
- if (v >= 0xffffffff || v < 0) throw new Error('id overflow');
- return [
- v >> 24,
- (v >> 16) & 0xff,
- (v >> 8) & 0xff,
- v & 0xff,
- ];
-}
-
-export async function getCollectionAddressFromResult(api: ApiPromise, result: any) {
- const collectionIdAddress = normalizeAddress(result.events.CollectionCreated.returnValues.collectionId);
- const collectionId = collectionIdFromAddress(collectionIdAddress);
- const collection = (await getDetailedCollectionInfo(api, collectionId))!;
- return {collectionIdAddress, collectionId, collection};
-}
-
-export function collectionIdToAddress(collection: number): string {
- const buf = Buffer.from([0x17, 0xc4, 0xe6, 0x45, 0x3c, 0xc4, 0x9a, 0xaa, 0xae, 0xac, 0xa8, 0x94, 0xe6, 0xd9, 0x68, 0x3e,
- ...encodeIntBE(collection),
- ]);
- return Web3.utils.toChecksumAddress('0x' + buf.toString('hex'));
-}
-export function collectionIdFromAddress(address: string): number {
- if (!address.startsWith('0x'))
- throw 'address not starts with "0x"';
- if (address.length > 42)
- throw 'address length is more than 20 bytes';
- return Number('0x' + address.substring(address.length - 8));
-}
-
-export function normalizeAddress(address: string): string {
- return '0x' + address.substring(address.length - 40);
-}
-
-export function tokenIdToAddress(collection: number, token: number): string {
- const buf = Buffer.from([0xf8, 0x23, 0x8c, 0xcf, 0xff, 0x8e, 0xd8, 0x87, 0x46, 0x3f, 0xd5, 0xe0,
- ...encodeIntBE(collection),
- ...encodeIntBE(token),
- ]);
- return Web3.utils.toChecksumAddress('0x' + buf.toString('hex'));
-}
-
-export function tokenIdFromAddress(address: string) {
- if (!address.startsWith('0x'))
- throw 'address not starts with "0x"';
- if (address.length > 42)
- throw 'address length is more than 20 bytes';
- return {
- collectionId: Number('0x' + address.substring(address.length - 16, address.length - 8)),
- tokenId: Number('0x' + address.substring(address.length - 8)),
- };
-}
-
-export function tokenIdToCross(collection: number, token: number): CrossAccountId {
- return {
- Ethereum: tokenIdToAddress(collection, token),
- };
-}
-
-export function createEthAccount(web3: Web3) {
- const account = web3.eth.accounts.create();
- web3.eth.accounts.wallet.add(account.privateKey);
- return account.address;
-}
-
-export async function createEthAccountWithBalance(api: ApiPromise, web3: Web3, privateKeyWrapper: (account: string) => IKeyringPair) {
- const alice = privateKeyWrapper('//Alice');
- const account = createEthAccount(web3);
- await transferBalanceToEth(api, alice, account);
-
- return account;
-}
-
-export async function transferBalanceToEth(api: ApiPromise, source: IKeyringPair, target: string, amount = 1000n * UNIQUE) {
- const tx = api.tx.balances.transfer(evmToAddress(target), amount);
- const events = await submitTransactionAsync(source, tx);
- const result = getGenericResult(events);
- expect(result.success).to.be.true;
-}
-
-export async function createRFTCollection(api: ApiPromise, web3: Web3, owner: string) {
- const collectionHelper = evmCollectionHelpers(web3, owner);
- const result = await collectionHelper.methods
- .createRFTCollection('A', 'B', 'C')
- .send({value: Number(2n * UNIQUE)});
- return await getCollectionAddressFromResult(api, result);
-}
-
-
-export async function createNonfungibleCollection(api: ApiPromise, web3: Web3, owner: string) {
- const collectionHelper = evmCollectionHelpers(web3, owner);
- const result = await collectionHelper.methods
- .createNonfungibleCollection('A', 'B', 'C')
- .send({value: Number(2n * UNIQUE)});
- return await getCollectionAddressFromResult(api, result);
-}
-
-export function uniqueNFT(web3: Web3, address: string, owner: string) {
- return new web3.eth.Contract(nonFungibleAbi as any, address, {
- from: owner,
- ...GAS_ARGS,
- });
-}
-
-export function uniqueRefungible(web3: Web3, collectionAddress: string, owner: string) {
- return new web3.eth.Contract(refungibleAbi as any, collectionAddress, {
- from: owner,
- ...GAS_ARGS,
- });
-}
-
-export function uniqueRefungibleToken(web3: Web3, tokenAddress: string, owner: string | undefined = undefined) {
- return new web3.eth.Contract(refungibleTokenAbi as any, tokenAddress, {
- from: owner,
- ...GAS_ARGS,
- });
-}
-
-export async function itWeb3(name: string, cb: (apis: { web3: Web3, api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair }) => any, opts: { only?: boolean, skip?: boolean } = {}) {
- let i: any = it;
- if (opts.only) i = i.only;
- else if (opts.skip) i = i.skip;
- i(name, async () => {
- await usingApi(async (api, privateKeyWrapper) => {
- await usingWeb3(async web3 => {
- await cb({api, web3, privateKeyWrapper});
- });
- });
- });
-}
-itWeb3.only = (name: string, cb: (apis: { web3: Web3, api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair }) => any) => itWeb3(name, cb, {only: true});
-itWeb3.skip = (name: string, cb: (apis: { web3: Web3, api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair }) => any) => itWeb3(name, cb, {skip: true});
-
-export async function generateSubstrateEthPair(web3: Web3) {
- const account = web3.eth.accounts.create();
- evmToAddress(account.address);
-}
-
-type NormalizedEvent = {
- address: string,
- event: string,
- args: { [key: string]: string }
-};
-
-export function normalizeEvents(events: any): NormalizedEvent[] {
- const output = [];
- for (const key of Object.keys(events)) {
- if (key.match(/^[0-9]+$/)) {
- output.push(events[key]);
- } else if (Array.isArray(events[key])) {
- output.push(...events[key]);
- } else {
- output.push(events[key]);
- }
- }
- output.sort((a, b) => a.logIndex - b.logIndex);
- return output.map(({address, event, returnValues}) => {
- const args: { [key: string]: string } = {};
- for (const key of Object.keys(returnValues)) {
- if (!key.match(/^[0-9]+$/)) {
- args[key] = returnValues[key];
- }
- }
- return {
- address,
- event,
- args,
- };
- });
-}
-
-export async function recordEvents(contract: any, action: () => Promise): Promise {
- const out: any = [];
- contract.events.allEvents((_: any, event: any) => {
- out.push(event);
- });
- await action();
- return normalizeEvents(out);
-}
-
-export function subToEthLowercase(eth: string): string {
- const bytes = addressToEvm(eth);
- return '0x' + Buffer.from(bytes).toString('hex');
-}
-
-export function subToEth(eth: string): string {
- return Web3.utils.toChecksumAddress(subToEthLowercase(eth));
-}
-
-export interface CompiledContract {
- abi: any,
- object: string,
-}
-
-export function compileContract(name: string, src: string) : CompiledContract {
- const out = JSON.parse(solc.compile(JSON.stringify({
- language: 'Solidity',
- sources: {
- [`${name}.sol`]: {
- content: `
- // SPDX-License-Identifier: UNLICENSED
- pragma solidity ^0.8.6;
-
- ${src}
- `,
- },
- },
- settings: {
- outputSelection: {
- '*': {
- '*': ['*'],
- },
- },
- },
- }))).contracts[`${name}.sol`][name];
-
- return {
- abi: out.abi,
- object: '0x' + out.evm.bytecode.object,
- };
-}
-
-export async function deployFlipper(web3: Web3, deployer: string) {
- const compiled = compileContract('Flipper', `
- contract Flipper {
- bool value = false;
- function flip() public {
- value = !value;
- }
- function getValue() public view returns (bool) {
- return value;
- }
- }
- `);
- const flipperContract = new web3.eth.Contract(compiled.abi, undefined, {
- data: compiled.object,
- from: deployer,
- ...GAS_ARGS,
- });
- const flipper = await flipperContract.deploy({data: compiled.object}).send({from: deployer});
-
- return flipper;
-}
-
-export async function deployCollector(web3: Web3, deployer: string) {
- const compiled = compileContract('Collector', `
- contract Collector {
- uint256 collected;
- fallback() external payable {
- giveMoney();
- }
- function giveMoney() public payable {
- collected += msg.value;
- }
- function getCollected() public view returns (uint256) {
- return collected;
- }
- function getUnaccounted() public view returns (uint256) {
- return address(this).balance - collected;
- }
-
- function withdraw(address payable target) public {
- target.transfer(collected);
- collected = 0;
- }
- }
- `);
- const collectorContract = new web3.eth.Contract(compiled.abi, undefined, {
- data: compiled.object,
- from: deployer,
- ...GAS_ARGS,
- });
- const collector = await collectorContract.deploy({data: compiled.object}).send({from: deployer});
-
- return collector;
-}
-
-/**
- * pallet evm_contract_helpers
- * @param web3
- * @param caller - eth address
- * @returns
- */
-export function contractHelpers(web3: Web3, caller: string) {
- return new web3.eth.Contract(contractHelpersAbi as any, '0x842899ECF380553E8a4de75bF534cdf6fBF64049', {from: caller, ...GAS_ARGS});
-}
-
-/**
- * evm collection helper
- * @param web3
- * @param caller - eth address
- * @returns
- */
-export function evmCollectionHelpers(web3: Web3, caller: string) {
- return new web3.eth.Contract(collectionHelpersAbi as any, '0x6c4e9fe1ae37a41e93cee429e8e1881abdcbb54f', {from: caller, ...GAS_ARGS});
-}
-
-/**
- * evm collection
- * @param web3
- * @param caller - eth address
- * @returns
- */
-export function evmCollection(web3: Web3, caller: string, collection: string, mode: CollectionMode = {type: 'NFT'}) {
- let abi;
- switch (mode.type) {
- case 'Fungible':
- abi = fungibleAbi;
- break;
-
- case 'NFT':
- abi = nonFungibleAbi;
- break;
-
- case 'ReFungible':
- abi = refungibleAbi;
- break;
-
- default:
- throw 'Bad collection mode';
- }
- const contract = new web3.eth.Contract(abi as any, collection, {from: caller, ...GAS_ARGS});
- return contract;
-}
-
-/**
- * Execute ethereum method call using substrate account
- * @param to target contract
- * @param mkTx - closure, receiving `contract.methods`, and returning method call,
- * to be used as following (assuming `to` = erc20 contract):
- * `m => m.transfer(to, amount)`
- *
- * # Example
- * ```ts
- * executeEthTxOnSub(api, alice, erc20Contract, m => m.transfer(target, amount));
- * ```
- */
-export async function executeEthTxOnSub(web3: Web3, api: ApiPromise, from: IKeyringPair, to: any, mkTx: (methods: any) => any, {value = 0}: {value?: bigint | number} = { }) {
- const tx = api.tx.evm.call(
- subToEth(from.address),
- to.options.address,
- mkTx(to.methods).encodeABI(),
- value,
- GAS_ARGS.gas,
- await web3.eth.getGasPrice(),
- null,
- null,
- [],
- );
- const events = await submitTransactionAsync(from, tx);
- expect(events.some(({event: {section, method}}) => section == 'evm' && method == 'Executed')).to.be.true;
-}
-
-export async function ethBalanceViaSub(api: ApiPromise, address: string): Promise {
- return (await getBalance(api, [evmToAddress(address)]))[0];
-}
-
-/**
- * Measure how much gas given closure consumes
- *
- * @param user which user balance will be checked
- */
-export async function recordEthFee(api: ApiPromise, user: string, call: () => Promise): Promise {
- const before = await ethBalanceViaSub(api, user);
-
- await call();
-
- // In dev mode, the transaction might not finish processing in time
- await waitNewBlocks(api, 1);
- const after = await ethBalanceViaSub(api, user);
-
- // Can't use .to.be.less, because chai doesn't supports bigint
- expect(after < before).to.be.true;
-
- return before - after;
-}
-
-type ElementOf = A extends readonly (infer T)[] ? T : never;
-// I want a fancier api, not a memory efficiency
-export function* cartesian>, R extends Array>(internalRest: [...R], ...args: [...T]): Generator<[...R, ...{[K in keyof T]: ElementOf}]> {
- if(args.length === 0) {
- yield internalRest as any;
- return;
- }
- for(const value of args[0]) {
- yield* cartesian([...internalRest, value], ...args.slice(1)) as any;
- }
-}
\ No newline at end of file
--- a/tests/src/deprecated-helpers/helpers.ts
+++ /dev/null
@@ -1,1873 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see .
-
-import '../interfaces/augment-api-rpc';
-import '../interfaces/augment-api-query';
-import {ApiPromise, Keyring} from '@polkadot/api';
-import type {AccountId, EventRecord, Event, BlockNumber} from '@polkadot/types/interfaces';
-import type {GenericEventData} from '@polkadot/types';
-import {AnyTuple, IEvent, IKeyringPair} from '@polkadot/types/types';
-import {evmToAddress} from '@polkadot/util-crypto';
-import {AnyNumber} from '@polkadot/types-codec/types';
-import BN from 'bn.js';
-import chai from 'chai';
-import chaiAsPromised from 'chai-as-promised';
-import {default as usingApi, executeTransaction, submitTransactionAsync, submitTransactionExpectFailAsync} from '../substrate/substrate-api';
-import {hexToStr, strToUTF16, utf16ToStr} from './util';
-import {UpDataStructsRpcCollection, UpDataStructsCreateItemData, UpDataStructsProperty} from '@polkadot/types/lookup';
-import {UpDataStructsTokenChild} from '../interfaces';
-import {Context} from 'mocha';
-
-chai.use(chaiAsPromised);
-const expect = chai.expect;
-
-export type CrossAccountId = {
- Substrate: string,
-} | {
- Ethereum: string,
-};
-
-
-export enum Pallets {
- Inflation = 'inflation',
- RmrkCore = 'rmrkcore',
- RmrkEquip = 'rmrkequip',
- ReFungible = 'refungible',
- Fungible = 'fungible',
- NFT = 'nonfungible',
- Scheduler = 'scheduler',
- AppPromotion = 'apppromotion',
-}
-
-export async function isUnique(): Promise {
- return usingApi(async api => {
- const chain = await api.rpc.system.chain();
-
- return chain.eq('UNIQUE');
- });
-}
-
-export async function isQuartz(): Promise {
- return usingApi(async api => {
- const chain = await api.rpc.system.chain();
-
- return chain.eq('QUARTZ');
- });
-}
-
-let modulesNames: any;
-export function getModuleNames(api: ApiPromise): string[] {
- if (typeof modulesNames === 'undefined')
- modulesNames = api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());
- return modulesNames;
-}
-
-export async function missingRequiredPallets(requiredPallets: string[]): Promise {
- return await usingApi(async api => {
- const pallets = getModuleNames(api);
-
- return requiredPallets.filter(p => !pallets.includes(p));
- });
-}
-
-export async function checkPalletsPresence(requiredPallets: string[]): Promise {
- return (await missingRequiredPallets(requiredPallets)).length == 0;
-}
-
-export async function requirePallets(mocha: Context, requiredPallets: string[]) {
- const missingPallets = await missingRequiredPallets(requiredPallets);
-
- if (missingPallets.length > 0) {
- const skippingTestMsg = `\tSkipping test "${mocha.test?.title}".`;
- const missingPalletsMsg = `\tThe following pallets are missing:\n\t- ${missingPallets.join('\n\t- ')}`;
- const skipMsg = `${skippingTestMsg}\n${missingPalletsMsg}`;
-
- console.error('\x1b[38:5:208m%s\x1b[0m', skipMsg);
-
- mocha.skip();
- }
-}
-
-export function bigIntToSub(api: ApiPromise, number: bigint) {
- return api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();
-}
-
-export function bigIntToDecimals(number: bigint, decimals = 18): string {
- const numberStr = number.toString();
- const dotPos = numberStr.length - decimals;
-
- if (dotPos <= 0) {
- return '0.' + '0'.repeat(Math.abs(dotPos)) + numberStr;
- } else {
- const intPart = numberStr.substring(0, dotPos);
- const fractPart = numberStr.substring(dotPos);
- return intPart + '.' + fractPart;
- }
-}
-
-export function normalizeAccountId(input: string | AccountId | CrossAccountId | IKeyringPair): CrossAccountId {
- if (typeof input === 'string') {
- if (input.length >= 47) {
- return {Substrate: input};
- } else if (input.length === 42 && input.startsWith('0x')) {
- return {Ethereum: input.toLowerCase()};
- } else if (input.length === 40 && !input.startsWith('0x')) {
- return {Ethereum: '0x' + input.toLowerCase()};
- } else {
- throw new Error(`Unknown address format: "${input}"`);
- }
- }
- if ('address' in input) {
- return {Substrate: input.address};
- }
- if ('Ethereum' in input) {
- return {
- Ethereum: input.Ethereum.toLowerCase(),
- };
- } else if ('ethereum' in input) {
- return {
- Ethereum: (input as any).ethereum.toLowerCase(),
- };
- } else if ('Substrate' in input) {
- return input;
- } else if ('substrate' in input) {
- return {
- Substrate: (input as any).substrate,
- };
- }
-
- // AccountId
- return {Substrate: input.toString()};
-}
-export function toSubstrateAddress(input: string | CrossAccountId | IKeyringPair): string {
- input = normalizeAccountId(input);
- if ('Substrate' in input) {
- return input.Substrate;
- } else {
- return evmToAddress(input.Ethereum);
- }
-}
-
-export const U128_MAX = (1n << 128n) - 1n;
-
-const MICROUNIQUE = 1_000_000_000_000n;
-const MILLIUNIQUE = 1_000n * MICROUNIQUE;
-const CENTIUNIQUE = 10n * MILLIUNIQUE;
-export const UNIQUE = 100n * CENTIUNIQUE;
-
-interface GenericResult {
- success: boolean;
- data: T | null;
-}
-
-interface CreateCollectionResult {
- success: boolean;
- collectionId: number;
-}
-
-interface CreateItemResult {
- success: boolean;
- collectionId: number;
- itemId: number;
- recipient?: CrossAccountId;
- amount?: number;
-}
-
-interface DestroyItemResult {
- success: boolean;
- collectionId: number;
- itemId: number;
- owner: CrossAccountId;
- amount: number;
-}
-
-interface TransferResult {
- collectionId: number;
- itemId: number;
- sender?: CrossAccountId;
- recipient?: CrossAccountId;
- value: bigint;
-}
-
-interface IReFungibleOwner {
- fraction: BN;
- owner: number[];
-}
-
-interface IGetMessage {
- checkMsgUnqMethod: string;
- checkMsgTrsMethod: string;
- checkMsgSysMethod: string;
-}
-
-export interface IFungibleTokenDataType {
- value: number;
-}
-
-export interface IChainLimits {
- collectionNumbersLimit: number;
- accountTokenOwnershipLimit: number;
- collectionsAdminsLimit: number;
- customDataLimit: number;
- nftSponsorTransferTimeout: number;
- fungibleSponsorTransferTimeout: number;
- refungibleSponsorTransferTimeout: number;
- //offchainSchemaLimit: number;
- //constOnChainSchemaLimit: number;
-}
-
-export interface IReFungibleTokenDataType {
- owner: IReFungibleOwner[];
-}
-
-export function uniqueEventMessage(events: EventRecord[]): IGetMessage {
- let checkMsgUnqMethod = '';
- let checkMsgTrsMethod = '';
- let checkMsgSysMethod = '';
- events.forEach(({event: {method, section}}) => {
- if (section === 'common') {
- checkMsgUnqMethod = method;
- } else if (section === 'treasury') {
- checkMsgTrsMethod = method;
- } else if (section === 'system') {
- checkMsgSysMethod = method;
- } else { return null; }
- });
- const result: IGetMessage = {
- checkMsgUnqMethod,
- checkMsgTrsMethod,
- checkMsgSysMethod,
- };
- return result;
-}
-
-export function getEvent(events: EventRecord[], check: (event: IEvent) => event is T): T | undefined {
- const event = events.find(r => check(r.event));
- if (!event) return;
- return event.event as T;
-}
-
-export function getGenericResult(events: EventRecord[]): GenericResult;
-export function getGenericResult(
- events: EventRecord[],
- expectSection: string,
- expectMethod: string,
- extractAction: (data: GenericEventData) => T
-): GenericResult;
-
-export function getGenericResult(
- events: EventRecord[],
- expectSection?: string,
- expectMethod?: string,
- extractAction?: (data: GenericEventData) => T,
-): GenericResult {
- let success = false;
- let successData = null;
-
- events.forEach(({event: {data, method, section}}) => {
- // console.log(` ${phase}: ${section}.${method}:: ${data}`);
- if (method === 'ExtrinsicSuccess') {
- success = true;
- } else if ((expectSection == section) && (expectMethod == method)) {
- successData = extractAction!(data as any);
- }
- });
-
- const result: GenericResult = {
- success,
- data: successData,
- };
- return result;
-}
-
-export function getCreateCollectionResult(events: EventRecord[]): CreateCollectionResult {
- const genericResult = getGenericResult(events, 'common', 'CollectionCreated', (data) => parseInt(data[0].toString(), 10));
- const result: CreateCollectionResult = {
- success: genericResult.success,
- collectionId: genericResult.data ?? 0,
- };
- return result;
-}
-
-export function getCreateItemsResult(events: EventRecord[]): CreateItemResult[] {
- const results: CreateItemResult[] = [];
-
- const genericResult = getGenericResult(events, 'common', 'ItemCreated', (data) => {
- const collectionId = parseInt(data[0].toString(), 10);
- const itemId = parseInt(data[1].toString(), 10);
- const recipient = normalizeAccountId(data[2].toJSON() as any);
- const amount = parseInt(data[3].toString(), 10);
-
- const itemRes: CreateItemResult = {
- success: true,
- collectionId,
- itemId,
- recipient,
- amount,
- };
-
- results.push(itemRes);
- return results;
- });
-
- if (!genericResult.success) return [];
- return results;
-}
-
-export function getCreateItemResult(events: EventRecord[]): CreateItemResult {
- const genericResult = getGenericResult(events, 'common', 'ItemCreated', (data) => data.map(function(value) { return value.toJSON(); }));
-
- if (genericResult.data == null)
- return {
- success: genericResult.success,
- collectionId: 0,
- itemId: 0,
- amount: 0,
- };
- else
- return {
- success: genericResult.success,
- collectionId: genericResult.data[0] as number,
- itemId: genericResult.data[1] as number,
- recipient: normalizeAccountId(genericResult.data![2] as any),
- amount: genericResult.data[3] as number,
- };
-}
-
-export function getDestroyItemsResult(events: EventRecord[]): DestroyItemResult[] {
- const results: DestroyItemResult[] = [];
-
- const genericResult = getGenericResult(events, 'common', 'ItemDestroyed', (data) => {
- const collectionId = parseInt(data[0].toString(), 10);
- const itemId = parseInt(data[1].toString(), 10);
- const owner = normalizeAccountId(data[2].toJSON() as any);
- const amount = parseInt(data[3].toString(), 10);
-
- const itemRes: DestroyItemResult = {
- success: true,
- collectionId,
- itemId,
- owner,
- amount,
- };
-
- results.push(itemRes);
- return results;
- });
-
- if (!genericResult.success) return [];
- return results;
-}
-
-export function getTransferResult(api: ApiPromise, events: EventRecord[]): TransferResult {
- for (const {event} of events) {
- if (api.events.common.Transfer.is(event)) {
- const [collection, token, sender, recipient, value] = event.data;
- return {
- collectionId: collection.toNumber(),
- itemId: token.toNumber(),
- sender: normalizeAccountId(sender.toJSON() as any),
- recipient: normalizeAccountId(recipient.toJSON() as any),
- value: value.toBigInt(),
- };
- }
- }
- throw new Error('no transfer event');
-}
-
-interface Nft {
- type: 'NFT';
-}
-
-interface Fungible {
- type: 'Fungible';
- decimalPoints: number;
-}
-
-interface ReFungible {
- type: 'ReFungible';
-}
-
-export type CollectionMode = Nft | Fungible | ReFungible;
-
-export type Property = {
- key: any,
- value: any,
-};
-
-type Permission = {
- mutable: boolean;
- collectionAdmin: boolean;
- tokenOwner: boolean;
-}
-
-type PropertyPermission = {
- key: any;
- permission: Permission;
-}
-
-export type CreateCollectionParams = {
- mode: CollectionMode,
- name: string,
- description: string,
- tokenPrefix: string,
- properties?: Array,
- propPerm?: Array
-};
-
-const defaultCreateCollectionParams: CreateCollectionParams = {
- description: 'description',
- mode: {type: 'NFT'},
- name: 'name',
- tokenPrefix: 'prefix',
-};
-
-export async function
-createCollection(
- api: ApiPromise,
- sender: IKeyringPair,
- params: Partial = {},
-): Promise {
- const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};
-
- let modeprm = {};
- if (mode.type === 'NFT') {
- modeprm = {nft: null};
- } else if (mode.type === 'Fungible') {
- modeprm = {fungible: mode.decimalPoints};
- } else if (mode.type === 'ReFungible') {
- modeprm = {refungible: null};
- }
-
- const tx = api.tx.unique.createCollectionEx({
- name: strToUTF16(name),
- description: strToUTF16(description),
- tokenPrefix: strToUTF16(tokenPrefix),
- mode: modeprm as any,
- });
- const events = await executeTransaction(api, sender, tx);
- return getCreateCollectionResult(events);
-}
-
-export async function createCollectionExpectSuccess(params: Partial = {}): Promise {
- const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};
-
- let collectionId = 0;
- await usingApi(async (api, privateKeyWrapper) => {
- // Get number of collections before the transaction
- const collectionCountBefore = await getCreatedCollectionCount(api);
-
- // Run the CreateCollection transaction
- const alicePrivateKey = privateKeyWrapper('//Alice');
-
- const result = await createCollection(api, alicePrivateKey, params);
-
- // Get number of collections after the transaction
- const collectionCountAfter = await getCreatedCollectionCount(api);
-
- // Get the collection
- const collection = await queryCollectionExpectSuccess(api, result.collectionId);
-
- // What to expect
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.true;
- expect(result.collectionId).to.be.equal(collectionCountAfter);
- // tslint:disable-next-line:no-unused-expression
- expect(collection).to.be.not.null;
- expect(collectionCountAfter).to.be.equal(collectionCountBefore + 1, 'Error: NFT collection NOT created.');
- expect(collection.owner.toString()).to.be.equal(toSubstrateAddress(alicePrivateKey));
- expect(utf16ToStr(collection.name.toJSON() as any)).to.be.equal(name);
- expect(utf16ToStr(collection.description.toJSON() as any)).to.be.equal(description);
- expect(hexToStr(collection.tokenPrefix.toJSON())).to.be.equal(tokenPrefix);
-
- collectionId = result.collectionId;
- });
-
- return collectionId;
-}
-
-export async function createCollectionWithPropsExpectSuccess(params: Partial = {}): Promise {
- const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};
-
- let collectionId = 0;
- await usingApi(async (api, privateKeyWrapper) => {
- // Get number of collections before the transaction
- const collectionCountBefore = await getCreatedCollectionCount(api);
-
- // Run the CreateCollection transaction
- const alicePrivateKey = privateKeyWrapper('//Alice');
-
- let modeprm = {};
- if (mode.type === 'NFT') {
- modeprm = {nft: null};
- } else if (mode.type === 'Fungible') {
- modeprm = {fungible: mode.decimalPoints};
- } else if (mode.type === 'ReFungible') {
- modeprm = {refungible: null};
- }
-
- const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any, properties: params.properties, tokenPropertyPermissions: params.propPerm});
- const events = await submitTransactionAsync(alicePrivateKey, tx);
- const result = getCreateCollectionResult(events);
-
- // Get number of collections after the transaction
- const collectionCountAfter = await getCreatedCollectionCount(api);
-
- // Get the collection
- const collection = await queryCollectionExpectSuccess(api, result.collectionId);
-
- // What to expect
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.true;
- expect(result.collectionId).to.be.equal(collectionCountAfter);
- // tslint:disable-next-line:no-unused-expression
- expect(collection).to.be.not.null;
- expect(collectionCountAfter).to.be.equal(collectionCountBefore + 1, 'Error: NFT collection NOT created.');
- expect(collection.owner.toString()).to.be.equal(toSubstrateAddress(alicePrivateKey));
- expect(utf16ToStr(collection.name.toJSON() as any)).to.be.equal(name);
- expect(utf16ToStr(collection.description.toJSON() as any)).to.be.equal(description);
- expect(hexToStr(collection.tokenPrefix.toJSON())).to.be.equal(tokenPrefix);
-
-
- collectionId = result.collectionId;
- });
-
- return collectionId;
-}
-
-export async function createCollectionWithPropsExpectFailure(params: Partial = {}) {
- const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};
-
- await usingApi(async (api, privateKeyWrapper) => {
- // Get number of collections before the transaction
- const collectionCountBefore = await getCreatedCollectionCount(api);
-
- // Run the CreateCollection transaction
- const alicePrivateKey = privateKeyWrapper('//Alice');
-
- let modeprm = {};
- if (mode.type === 'NFT') {
- modeprm = {nft: null};
- } else if (mode.type === 'Fungible') {
- modeprm = {fungible: mode.decimalPoints};
- } else if (mode.type === 'ReFungible') {
- modeprm = {refungible: null};
- }
-
- const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any, properties: params.properties, tokenPropertyPermissions: params.propPerm});
- await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;
-
-
- // Get number of collections after the transaction
- const collectionCountAfter = await getCreatedCollectionCount(api);
-
- expect(collectionCountAfter).to.be.equal(collectionCountBefore, 'Error: Collection with incorrect data created.');
- });
-}
-
-export async function createCollectionExpectFailure(params: Partial = {}) {
- const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};
-
- let modeprm = {};
- if (mode.type === 'NFT') {
- modeprm = {nft: null};
- } else if (mode.type === 'Fungible') {
- modeprm = {fungible: mode.decimalPoints};
- } else if (mode.type === 'ReFungible') {
- modeprm = {refungible: null};
- }
-
- await usingApi(async (api, privateKeyWrapper) => {
- // Get number of collections before the transaction
- const collectionCountBefore = await getCreatedCollectionCount(api);
-
- // Run the CreateCollection transaction
- const alicePrivateKey = privateKeyWrapper('//Alice');
- const tx = api.tx.unique.createCollectionEx({name: strToUTF16(name), description: strToUTF16(description), tokenPrefix: strToUTF16(tokenPrefix), mode: modeprm as any});
- await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;
-
- // Get number of collections after the transaction
- const collectionCountAfter = await getCreatedCollectionCount(api);
-
- // What to expect
- expect(collectionCountAfter).to.be.equal(collectionCountBefore, 'Error: Collection with incorrect data created.');
- });
-}
-
-export async function findUnusedAddress(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, seedAddition = ''): Promise {
- let bal = 0n;
- let unused;
- do {
- const randomSeed = 'seed' + Math.floor(Math.random() * Math.floor(10000)) + seedAddition;
- unused = privateKeyWrapper(`//${randomSeed}`);
- bal = (await api.query.system.account(unused.address)).data.free.toBigInt();
- } while (bal !== 0n);
- return unused;
-}
-
-export async function getAllowance(api: ApiPromise, collectionId: number, owner: CrossAccountId | string | IKeyringPair, approved: CrossAccountId | string | IKeyringPair, tokenId: number) {
- return (await api.rpc.unique.allowance(collectionId, normalizeAccountId(owner), normalizeAccountId(approved), tokenId)).toBigInt();
-}
-
-export function findUnusedAddresses(api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair, amount: number): Promise {
- return Promise.all(new Array(amount).fill(null).map(() => findUnusedAddress(api, privateKeyWrapper, '_' + Date.now())));
-}
-
-export async function findNotExistingCollection(api: ApiPromise): Promise {
- const totalNumber = await getCreatedCollectionCount(api);
- const newCollection: number = totalNumber + 1;
- return newCollection;
-}
-
-function getDestroyResult(events: EventRecord[]): boolean {
- let success = false;
- events.forEach(({event: {method}}) => {
- if (method == 'ExtrinsicSuccess') {
- success = true;
- }
- });
- return success;
-}
-
-export async function destroyCollectionExpectFailure(collectionId: number, senderSeed = '//Alice') {
- await usingApi(async (api, privateKeyWrapper) => {
- // Run the DestroyCollection transaction
- const alicePrivateKey = privateKeyWrapper(senderSeed);
- const tx = api.tx.unique.destroyCollection(collectionId);
- await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;
- });
-}
-
-export async function destroyCollectionExpectSuccess(collectionId: number, senderSeed = '//Alice') {
- await usingApi(async (api, privateKeyWrapper) => {
- // Run the DestroyCollection transaction
- const alicePrivateKey = privateKeyWrapper(senderSeed);
- const tx = api.tx.unique.destroyCollection(collectionId);
- const events = await submitTransactionAsync(alicePrivateKey, tx);
- const result = getDestroyResult(events);
- expect(result).to.be.true;
-
- // What to expect
- expect(await getDetailedCollectionInfo(api, collectionId)).to.be.null;
- });
-}
-
-export async function setCollectionLimitsExpectSuccess(sender: IKeyringPair, collectionId: number, limits: any) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.setCollectionLimits(collectionId, limits);
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- expect(result.success).to.be.true;
- });
-}
-
-export const setCollectionPermissionsExpectSuccess = async (sender: IKeyringPair, collectionId: number, permissions: any) => {
- await usingApi(async(api) => {
- const tx = api.tx.unique.setCollectionPermissions(collectionId, permissions);
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- expect(result.success).to.be.true;
- });
-};
-
-export async function setCollectionLimitsExpectFailure(sender: IKeyringPair, collectionId: number, limits: any) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.setCollectionLimits(collectionId, limits);
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getGenericResult(events);
-
- expect(result.success).to.be.false;
- });
-}
-
-export async function setCollectionSponsorExpectSuccess(collectionId: number, sponsor: string, sender = '//Alice') {
- await usingApi(async (api, privateKeyWrapper) => {
-
- // Run the transaction
- const senderPrivateKey = privateKeyWrapper(sender);
- const tx = api.tx.unique.setCollectionSponsor(collectionId, sponsor);
- const events = await submitTransactionAsync(senderPrivateKey, tx);
- const result = getGenericResult(events);
-
- // Get the collection
- const collection = await queryCollectionExpectSuccess(api, collectionId);
-
- // What to expect
- expect(result.success).to.be.true;
- expect(collection.sponsorship.toJSON()).to.deep.equal({
- unconfirmed: sponsor,
- });
- });
-}
-
-export async function removeCollectionSponsorExpectSuccess(collectionId: number, sender = '//Alice') {
- await usingApi(async (api, privateKeyWrapper) => {
-
- // Run the transaction
- const alicePrivateKey = privateKeyWrapper(sender);
- const tx = api.tx.unique.removeCollectionSponsor(collectionId);
- const events = await submitTransactionAsync(alicePrivateKey, tx);
- const result = getGenericResult(events);
-
- // Get the collection
- const collection = await queryCollectionExpectSuccess(api, collectionId);
-
- // What to expect
- expect(result.success).to.be.true;
- expect(collection.sponsorship.toJSON()).to.be.deep.equal({disabled: null});
- });
-}
-
-export async function removeCollectionSponsorExpectFailure(collectionId: number, senderSeed = '//Alice') {
- await usingApi(async (api, privateKeyWrapper) => {
-
- // Run the transaction
- const alicePrivateKey = privateKeyWrapper(senderSeed);
- const tx = api.tx.unique.removeCollectionSponsor(collectionId);
- await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;
- });
-}
-
-export async function setCollectionSponsorExpectFailure(collectionId: number, sponsor: string, senderSeed = '//Alice') {
- await usingApi(async (api, privateKeyWrapper) => {
-
- // Run the transaction
- const alicePrivateKey = privateKeyWrapper(senderSeed);
- const tx = api.tx.unique.setCollectionSponsor(collectionId, sponsor);
- await expect(submitTransactionExpectFailAsync(alicePrivateKey, tx)).to.be.rejected;
- });
-}
-
-export async function confirmSponsorshipExpectSuccess(collectionId: number, senderSeed = '//Alice') {
- await usingApi(async (api, privateKeyWrapper) => {
-
- // Run the transaction
- const sender = privateKeyWrapper(senderSeed);
- await confirmSponsorshipByKeyExpectSuccess(collectionId, sender);
- });
-}
-
-export async function confirmSponsorshipByKeyExpectSuccess(collectionId: number, sender: IKeyringPair) {
- await usingApi(async (api, privateKeyWrapper) => {
-
- // Run the transaction
- const tx = api.tx.unique.confirmSponsorship(collectionId);
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- // Get the collection
- const collection = await queryCollectionExpectSuccess(api, collectionId);
-
- // What to expect
- expect(result.success).to.be.true;
- expect(collection.sponsorship.toJSON()).to.be.deep.equal({
- confirmed: sender.address,
- });
- });
-}
-
-
-export async function confirmSponsorshipExpectFailure(collectionId: number, senderSeed = '//Alice') {
- await usingApi(async (api, privateKeyWrapper) => {
-
- // Run the transaction
- const sender = privateKeyWrapper(senderSeed);
- const tx = api.tx.unique.confirmSponsorship(collectionId);
- await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- });
-}
-
-export async function enableContractSponsoringExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.enableContractSponsoring(contractAddress, enable);
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- expect(result.success).to.be.true;
- });
-}
-
-export async function enableContractSponsoringExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, enable: boolean) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.enableContractSponsoring(contractAddress, enable);
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getGenericResult(events);
-
- expect(result.success).to.be.false;
- });
-}
-
-export async function setTransferFlagExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {
-
- await usingApi(async (api) => {
-
- const tx = api.tx.unique.setTransfersEnabledFlag(collectionId, enabled);
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- expect(result.success).to.be.true;
- });
-}
-
-export async function setTransferFlagExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {
-
- await usingApi(async (api) => {
-
- const tx = api.tx.unique.setTransfersEnabledFlag(collectionId, enabled);
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getGenericResult(events);
-
- expect(result.success).to.be.false;
- });
-}
-
-export async function setContractSponsoringRateLimitExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.setContractSponsoringRateLimit(contractAddress, rateLimit);
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- expect(result.success).to.be.true;
- });
-}
-
-export async function setContractSponsoringRateLimitExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, rateLimit: number) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.setContractSponsoringRateLimit(contractAddress, rateLimit);
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getGenericResult(events);
-
- expect(result.success).to.be.false;
- });
-}
-
-export async function getNextSponsored(
- api: ApiPromise,
- collectionId: number,
- account: string | CrossAccountId,
- tokenId: number,
-): Promise {
- return Number((await api.rpc.unique.nextSponsored(collectionId, account, tokenId)).unwrapOr(-1));
-}
-
-export async function toggleContractAllowlistExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, value = true) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.toggleContractAllowList(contractAddress, value);
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- expect(result.success).to.be.true;
- });
-}
-
-export async function isAllowlistedInContract(contractAddress: AccountId | string, user: string) {
- let allowlisted = false;
- await usingApi(async (api) => {
- allowlisted = (await api.query.unique.contractAllowList(contractAddress, user)).toJSON() as boolean;
- });
- return allowlisted;
-}
-
-export async function addToContractAllowListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.addToContractAllowList(contractAddress.toString(), user.toString());
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- expect(result.success).to.be.true;
- });
-}
-
-export async function removeFromContractAllowListExpectSuccess(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.removeFromContractAllowList(contractAddress.toString(), user.toString());
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- expect(result.success).to.be.true;
- });
-}
-
-export async function removeFromContractAllowListExpectFailure(sender: IKeyringPair, contractAddress: AccountId | string, user: AccountId | string) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.removeFromContractAllowList(contractAddress.toString(), user.toString());
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getGenericResult(events);
-
- expect(result.success).to.be.false;
- });
-}
-
-export interface CreateFungibleData {
- readonly Value: bigint;
-}
-
-export interface CreateReFungibleData { }
-export interface CreateNftData { }
-
-export type CreateItemData = {
- NFT: CreateNftData;
-} | {
- Fungible: CreateFungibleData;
-} | {
- ReFungible: CreateReFungibleData;
-};
-
-export async function burnItem(api: ApiPromise, sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint) : Promise {
- const tx = api.tx.unique.burnItem(collectionId, tokenId, value);
- const events = await submitTransactionAsync(sender, tx);
- return getGenericResult(events).success;
-}
-
-export async function burnItemExpectSuccess(sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint = 1) {
- await usingApi(async (api) => {
- const balanceBefore = await getBalance(api, collectionId, normalizeAccountId(sender), tokenId);
- // if burning token by admin - use adminButnItemExpectSuccess
- expect(balanceBefore >= BigInt(value)).to.be.true;
-
- expect(await burnItem(api, sender, collectionId, tokenId, value)).to.be.true;
-
- const balanceAfter = await getBalance(api, collectionId, normalizeAccountId(sender), tokenId);
- expect(balanceAfter + BigInt(value)).to.be.equal(balanceBefore);
- });
-}
-
-export async function burnItemExpectFailure(sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint = 1) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.burnItem(collectionId, tokenId, value);
-
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getCreateCollectionResult(events);
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.false;
- });
-}
-
-export async function burnFromExpectSuccess(sender: IKeyringPair, from: IKeyringPair | CrossAccountId, collectionId: number, tokenId: number, value: number | bigint = 1) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.burnFrom(collectionId, normalizeAccountId(from), tokenId, value);
- const events = await submitTransactionAsync(sender, tx);
- return getGenericResult(events).success;
- });
-}
-
-export async function
-approve(
- api: ApiPromise,
- collectionId: number,
- tokenId: number, owner: IKeyringPair, approved: CrossAccountId | string | IKeyringPair, amount: number | bigint,
-) {
- const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount);
- const events = await submitTransactionAsync(owner, approveUniqueTx);
- return getGenericResult(events).success;
-}
-
-export async function
-approveExpectSuccess(
- collectionId: number,
- tokenId: number, owner: IKeyringPair, approved: CrossAccountId | string, amount: number | bigint = 1,
-) {
- await usingApi(async (api: ApiPromise) => {
- const result = await approve(api, collectionId, tokenId, owner, approved, amount);
- expect(result).to.be.true;
-
- expect(await getAllowance(api, collectionId, owner, approved, tokenId)).to.be.equal(BigInt(amount));
- });
-}
-
-export async function adminApproveFromExpectSuccess(
- collectionId: number,
- tokenId: number, admin: IKeyringPair, owner: CrossAccountId | string, approved: CrossAccountId | string, amount: number | bigint = 1,
-) {
- await usingApi(async (api: ApiPromise) => {
- const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount);
- const events = await submitTransactionAsync(admin, approveUniqueTx);
- const result = getGenericResult(events);
- expect(result.success).to.be.true;
-
- expect(await getAllowance(api, collectionId, owner, approved, tokenId)).to.be.equal(BigInt(amount));
- });
-}
-
-export async function
-transferFrom(
- api: ApiPromise,
- collectionId: number,
- tokenId: number,
- accountApproved: IKeyringPair,
- accountFrom: IKeyringPair | CrossAccountId,
- accountTo: IKeyringPair | CrossAccountId,
- value: number | bigint,
-) {
- const from = normalizeAccountId(accountFrom);
- const to = normalizeAccountId(accountTo);
- const transferFromTx = api.tx.unique.transferFrom(from, to, collectionId, tokenId, value);
- const events = await submitTransactionAsync(accountApproved, transferFromTx);
- return getGenericResult(events).success;
-}
-
-export async function
-transferFromExpectSuccess(
- collectionId: number,
- tokenId: number,
- accountApproved: IKeyringPair,
- accountFrom: IKeyringPair | CrossAccountId,
- accountTo: IKeyringPair | CrossAccountId,
- value: number | bigint = 1,
- type = 'NFT',
-) {
- await usingApi(async (api: ApiPromise) => {
- const from = normalizeAccountId(accountFrom);
- const to = normalizeAccountId(accountTo);
- let balanceBefore = 0n;
- if (type === 'Fungible' || type === 'ReFungible') {
- balanceBefore = await getBalance(api, collectionId, to, tokenId);
- }
- expect(await transferFrom(api, collectionId, tokenId, accountApproved, accountFrom, accountTo, value)).to.be.true;
- if (type === 'NFT') {
- expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(to);
- }
- if (type === 'Fungible') {
- const balanceAfter = await getBalance(api, collectionId, to, tokenId);
- if (JSON.stringify(to) !== JSON.stringify(from)) {
- expect(balanceAfter - balanceBefore).to.be.equal(BigInt(value));
- } else {
- expect(balanceAfter).to.be.equal(balanceBefore);
- }
- }
- if (type === 'ReFungible') {
- expect(await getBalance(api, collectionId, to, tokenId)).to.be.equal(balanceBefore + BigInt(value));
- }
- });
-}
-
-export async function
-transferFromExpectFail(
- collectionId: number,
- tokenId: number,
- accountApproved: IKeyringPair,
- accountFrom: IKeyringPair,
- accountTo: IKeyringPair,
- value: number | bigint = 1,
-) {
- await usingApi(async (api: ApiPromise) => {
- const transferFromTx = api.tx.unique.transferFrom(normalizeAccountId(accountFrom.address), normalizeAccountId(accountTo.address), collectionId, tokenId, value);
- const events = await expect(submitTransactionExpectFailAsync(accountApproved, transferFromTx)).to.be.rejected;
- const result = getCreateCollectionResult(events);
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.false;
- });
-}
-
-/* eslint no-async-promise-executor: "off" */
-export async function getBlockNumber(api: ApiPromise): Promise {
- return new Promise(async (resolve) => {
- const unsubscribe = await api.rpc.chain.subscribeNewHeads((head) => {
- unsubscribe();
- resolve(head.number.toNumber());
- });
- });
-}
-
-export async function addCollectionAdminExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | CrossAccountId) {
- await usingApi(async (api) => {
- const changeAdminTx = api.tx.unique.addCollectionAdmin(collectionId, normalizeAccountId(address));
- const events = await submitTransactionAsync(sender, changeAdminTx);
- const result = getCreateCollectionResult(events);
- expect(result.success).to.be.true;
- });
-}
-
-export async function adminApproveFromExpectFail(
- collectionId: number,
- tokenId: number, admin: IKeyringPair, owner: CrossAccountId | string, approved: CrossAccountId | string, amount: number | bigint = 1,
-) {
- await usingApi(async (api: ApiPromise) => {
- const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount);
- const events = await expect(submitTransactionAsync(admin, approveUniqueTx)).to.be.rejected;
- const result = getGenericResult(events);
- expect(result.success).to.be.false;
- });
-}
-
-export async function
-getFreeBalance(account: IKeyringPair): Promise {
- let balance = 0n;
- await usingApi(async (api) => {
- balance = BigInt((await api.query.system.account(account.address)).data.free.toString());
- });
-
- return balance;
-}
-
-export async function paraSiblingSovereignAccount(paraid: number): Promise {
- return usingApi(async api => {
- // We are getting a *sibling* parachain sovereign account,
- // so we need a sibling prefix: encoded(b"sibl") == 0x7369626c
- const siblingPrefix = '0x7369626c';
-
- const encodedParaId = api.createType('u32', paraid).toHex(true).substring(2);
- const suffix = '000000000000000000000000000000000000000000000000';
-
- return siblingPrefix + encodedParaId + suffix;
- });
-}
-
-export async function transferBalanceTo(api: ApiPromise, source: IKeyringPair, target: string, amount = 1000n * UNIQUE) {
- const tx = api.tx.balances.transfer(target, amount);
- const events = await submitTransactionAsync(source, tx);
- const result = getGenericResult(events);
- expect(result.success).to.be.true;
-}
-
-export async function
-scheduleExpectSuccess(
- operationTx: any,
- sender: IKeyringPair,
- blockSchedule: number,
- scheduledId: string,
- period = 1,
- repetitions = 1,
-) {
- await usingApi(async (api: ApiPromise) => {
- const blockNumber: number | undefined = await getBlockNumber(api);
- const expectedBlockNumber = blockNumber + blockSchedule;
-
- expect(blockNumber).to.be.greaterThan(0);
- const scheduleTx = api.tx.scheduler.scheduleNamed( // schedule
- scheduledId,
- expectedBlockNumber,
- repetitions > 1 ? [period, repetitions] : null,
- 0,
- {Value: operationTx as any},
- );
-
- const events = await submitTransactionAsync(sender, scheduleTx);
- expect(getGenericResult(events).success).to.be.true;
- });
-}
-
-export async function
-scheduleExpectFailure(
- operationTx: any,
- sender: IKeyringPair,
- blockSchedule: number,
- scheduledId: string,
- period = 1,
- repetitions = 1,
-) {
- await usingApi(async (api: ApiPromise) => {
- const blockNumber: number | undefined = await getBlockNumber(api);
- const expectedBlockNumber = blockNumber + blockSchedule;
-
- expect(blockNumber).to.be.greaterThan(0);
- const scheduleTx = api.tx.scheduler.scheduleNamed( // schedule
- scheduledId,
- expectedBlockNumber,
- repetitions <= 1 ? null : [period, repetitions],
- 0,
- {Value: operationTx as any},
- );
-
- //const events =
- await expect(submitTransactionExpectFailAsync(sender, scheduleTx)).to.be.rejected;
- //expect(getGenericResult(events).success).to.be.false;
- });
-}
-
-export async function
-scheduleTransferAndWaitExpectSuccess(
- collectionId: number,
- tokenId: number,
- sender: IKeyringPair,
- recipient: IKeyringPair,
- value: number | bigint = 1,
- blockSchedule: number,
- scheduledId: string,
-) {
- await usingApi(async (api: ApiPromise) => {
- await scheduleTransferExpectSuccess(collectionId, tokenId, sender, recipient, value, blockSchedule, scheduledId);
-
- const recipientBalanceBefore = (await api.query.system.account(recipient.address)).data.free.toBigInt();
-
- // sleep for n + 1 blocks
- await waitNewBlocks(blockSchedule + 1);
-
- const recipientBalanceAfter = (await api.query.system.account(recipient.address)).data.free.toBigInt();
-
- expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(recipient.address));
- expect(recipientBalanceAfter).to.be.equal(recipientBalanceBefore);
- });
-}
-
-export async function
-scheduleTransferExpectSuccess(
- collectionId: number,
- tokenId: number,
- sender: IKeyringPair,
- recipient: IKeyringPair,
- value: number | bigint = 1,
- blockSchedule: number,
- scheduledId: string,
-) {
- await usingApi(async (api: ApiPromise) => {
- const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient.address), collectionId, tokenId, value);
-
- await scheduleExpectSuccess(transferTx, sender, blockSchedule, scheduledId);
-
- expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(normalizeAccountId(sender.address));
- });
-}
-
-export async function
-scheduleTransferFundsPeriodicExpectSuccess(
- amount: bigint,
- sender: IKeyringPair,
- recipient: IKeyringPair,
- blockSchedule: number,
- scheduledId: string,
- period: number,
- repetitions: number,
-) {
- await usingApi(async (api: ApiPromise) => {
- const transferTx = api.tx.balances.transfer(recipient.address, amount);
-
- const balanceBefore = await getFreeBalance(recipient);
-
- await scheduleExpectSuccess(transferTx, sender, blockSchedule, scheduledId, period, repetitions);
-
- expect(await getFreeBalance(recipient)).to.be.equal(balanceBefore);
- });
-}
-
-export async function
-transfer(
- api: ApiPromise,
- collectionId: number,
- tokenId: number,
- sender: IKeyringPair,
- recipient: IKeyringPair | CrossAccountId,
- value: number | bigint,
-) : Promise {
- const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient), collectionId, tokenId, value);
- const events = await executeTransaction(api, sender, transferTx);
- return getGenericResult(events).success;
-}
-
-export async function
-transferExpectSuccess(
- collectionId: number,
- tokenId: number,
- sender: IKeyringPair,
- recipient: IKeyringPair | CrossAccountId,
- value: number | bigint = 1,
- type = 'NFT',
-) {
- await usingApi(async (api: ApiPromise) => {
- const from = normalizeAccountId(sender);
- const to = normalizeAccountId(recipient);
-
- let balanceBefore = 0n;
- if (type === 'Fungible' || type === 'ReFungible') {
- balanceBefore = await getBalance(api, collectionId, to, tokenId);
- }
-
- const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient), collectionId, tokenId, value);
- const events = await executeTransaction(api, sender, transferTx);
- const result = getTransferResult(api, events);
-
- expect(result.collectionId).to.be.equal(collectionId);
- expect(result.itemId).to.be.equal(tokenId);
- expect(result.sender).to.be.deep.equal(normalizeAccountId(sender.address));
- expect(result.recipient).to.be.deep.equal(to);
- expect(result.value).to.be.equal(BigInt(value));
-
- if (type === 'NFT') {
- expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(to);
- }
- if (type === 'Fungible' || type === 'ReFungible') {
- const balanceAfter = await getBalance(api, collectionId, to, tokenId);
- if (JSON.stringify(to) !== JSON.stringify(from)) {
- expect(balanceAfter - balanceBefore).to.be.equal(BigInt(value));
- } else {
- expect(balanceAfter).to.be.equal(balanceBefore);
- }
- }
- });
-}
-
-export async function
-transferExpectFailure(
- collectionId: number,
- tokenId: number,
- sender: IKeyringPair,
- recipient: IKeyringPair | CrossAccountId,
- value: number | bigint = 1,
-) {
- await usingApi(async (api: ApiPromise) => {
- const transferTx = api.tx.unique.transfer(normalizeAccountId(recipient), collectionId, tokenId, value);
- const events = await expect(submitTransactionExpectFailAsync(sender, transferTx)).to.be.rejected;
- const result = getGenericResult(events);
- // if (events && Array.isArray(events)) {
- // const result = getCreateCollectionResult(events);
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.false;
- //}
- });
-}
-
-export async function
-approveExpectFail(
- collectionId: number,
- tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number | bigint = 1,
-) {
- await usingApi(async (api: ApiPromise) => {
- const approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved.address), collectionId, tokenId, amount);
- const events = await expect(submitTransactionExpectFailAsync(owner, approveUniqueTx)).to.be.rejected;
- const result = getCreateCollectionResult(events);
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.false;
- });
-}
-
-export async function getBalance(
- api: ApiPromise,
- collectionId: number,
- owner: string | CrossAccountId | IKeyringPair,
- token: number,
-): Promise {
- return (await api.rpc.unique.balance(collectionId, normalizeAccountId(owner), token)).toBigInt();
-}
-export async function getTokenOwner(
- api: ApiPromise,
- collectionId: number,
- token: number,
-): Promise {
- const owner = (await api.rpc.unique.tokenOwner(collectionId, token)).toJSON() as any;
- if (owner == null) throw new Error('owner == null');
- return normalizeAccountId(owner);
-}
-export async function getTopmostTokenOwner(
- api: ApiPromise,
- collectionId: number,
- token: number,
-): Promise {
- const owner = (await api.rpc.unique.topmostTokenOwner(collectionId, token)).toJSON() as any;
- if (owner == null) throw new Error('owner == null');
- return normalizeAccountId(owner);
-}
-export async function getTokenChildren(
- api: ApiPromise,
- collectionId: number,
- tokenId: number,
-): Promise {
- return (await api.rpc.unique.tokenChildren(collectionId, tokenId)).toJSON() as any;
-}
-export async function isTokenExists(
- api: ApiPromise,
- collectionId: number,
- token: number,
-): Promise {
- return (await api.rpc.unique.tokenExists(collectionId, token)).toJSON();
-}
-export async function getLastTokenId(
- api: ApiPromise,
- collectionId: number,
-): Promise {
- return (await api.rpc.unique.lastTokenId(collectionId)).toJSON();
-}
-export async function getAdminList(
- api: ApiPromise,
- collectionId: number,
-): Promise {
- return (await api.rpc.unique.adminlist(collectionId)).toHuman() as any;
-}
-export async function getTokenProperties(
- api: ApiPromise,
- collectionId: number,
- tokenId: number,
- propertyKeys: string[],
-): Promise {
- return (await api.rpc.unique.tokenProperties(collectionId, tokenId, propertyKeys)).toHuman() as any;
-}
-
-export async function createFungibleItemExpectSuccess(
- sender: IKeyringPair,
- collectionId: number,
- data: CreateFungibleData,
- owner: CrossAccountId | string = sender.address,
-) {
- return await usingApi(async (api) => {
- const tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), {Fungible: data});
-
- const events = await submitTransactionAsync(sender, tx);
- const result = getCreateItemResult(events);
-
- expect(result.success).to.be.true;
- return result.itemId;
- });
-}
-
-export async function createMultipleItemsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any, owner: CrossAccountId | string = sender.address) {
- await usingApi(async (api) => {
- const to = normalizeAccountId(owner);
- const tx = api.tx.unique.createMultipleItems(collectionId, to, itemsData);
-
- const events = await submitTransactionAsync(sender, tx);
- expect(getGenericResult(events).success).to.be.true;
- });
-}
-
-export async function createMultipleItemsWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any, owner: CrossAccountId | string = sender.address) {
- await usingApi(async (api) => {
- const to = normalizeAccountId(owner);
- const tx = api.tx.unique.createMultipleItems(collectionId, to, itemsData);
-
- const events = await submitTransactionAsync(sender, tx);
- const result = getCreateItemsResult(events);
-
- for (const res of result) {
- expect(await api.rpc.unique.tokenProperties(collectionId, res.itemId)).not.to.be.empty;
- }
- });
-}
-
-export async function createMultipleItemsExWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, itemsData: any) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.createMultipleItemsEx(collectionId, itemsData);
-
- const events = await submitTransactionAsync(sender, tx);
- const result = getCreateItemsResult(events);
-
- for (const res of result) {
- expect(await api.rpc.unique.tokenProperties(collectionId, res.itemId)).not.to.be.empty;
- }
- });
-}
-
-export async function createItemWithPropsExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, props: Array, owner: CrossAccountId | string = sender.address) {
- let newItemId = 0;
- await usingApi(async (api) => {
- const to = normalizeAccountId(owner);
- const itemCountBefore = await getLastTokenId(api, collectionId);
- const itemBalanceBefore = await getBalance(api, collectionId, to, newItemId);
-
- let tx;
- if (createMode === 'Fungible') {
- const createData = {fungible: {value: 10}};
- tx = api.tx.unique.createItem(collectionId, to, createData as any);
- } else if (createMode === 'ReFungible') {
- const createData = {refungible: {pieces: 100}};
- tx = api.tx.unique.createItem(collectionId, to, createData as any);
- } else {
- const data = api.createType('UpDataStructsCreateItemData', {NFT: {properties: props}});
- tx = api.tx.unique.createItem(collectionId, to, data as UpDataStructsCreateItemData);
- }
-
- const events = await submitTransactionAsync(sender, tx);
- const result = getCreateItemResult(events);
-
- const itemCountAfter = await getLastTokenId(api, collectionId);
- const itemBalanceAfter = await getBalance(api, collectionId, to, newItemId);
-
- if (createMode === 'NFT') {
- expect(await api.rpc.unique.tokenProperties(collectionId, result.itemId)).not.to.be.empty;
- }
-
- // What to expect
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.true;
- if (createMode === 'Fungible') {
- expect(itemBalanceAfter - itemBalanceBefore).to.be.equal(10n);
- } else {
- expect(itemCountAfter).to.be.equal(itemCountBefore + 1);
- }
- expect(collectionId).to.be.equal(result.collectionId);
- expect(itemCountAfter.toString()).to.be.equal(result.itemId.toString());
- expect(to).to.be.deep.equal(result.recipient);
- newItemId = result.itemId;
- });
- return newItemId;
-}
-
-export async function createItemWithPropsExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, props: Array, owner: CrossAccountId | string = sender.address) {
- await usingApi(async (api) => {
-
- let tx;
- if (createMode === 'NFT') {
- const data = api.createType('UpDataStructsCreateItemData', {NFT: {properties: props}}) as UpDataStructsCreateItemData;
- tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), data);
- } else {
- tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createMode);
- }
-
-
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- if(events.message && events.message.toString().indexOf('1002: Verification Error') > -1) return;
- const result = getCreateItemResult(events);
-
- expect(result.success).to.be.false;
- });
-}
-
-export async function createItemExpectSuccess(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {
- let newItemId = 0;
- await usingApi(async (api) => {
- const to = normalizeAccountId(owner);
- const itemCountBefore = await getLastTokenId(api, collectionId);
- const itemBalanceBefore = await getBalance(api, collectionId, to, newItemId);
-
- let tx;
- if (createMode === 'Fungible') {
- const createData = {fungible: {value: 10}};
- tx = api.tx.unique.createItem(collectionId, to, createData as any);
- } else if (createMode === 'ReFungible') {
- const createData = {refungible: {pieces: 100}};
- tx = api.tx.unique.createItem(collectionId, to, createData as any);
- } else {
- const createData = {nft: {}};
- tx = api.tx.unique.createItem(collectionId, to, createData as any);
- }
-
- const events = await executeTransaction(api, sender, tx);
- const result = getCreateItemResult(events);
-
- const itemCountAfter = await getLastTokenId(api, collectionId);
- const itemBalanceAfter = await getBalance(api, collectionId, to, newItemId);
-
- // What to expect
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.true;
- if (createMode === 'Fungible') {
- expect(itemBalanceAfter - itemBalanceBefore).to.be.equal(10n);
- } else {
- expect(itemCountAfter).to.be.equal(itemCountBefore + 1);
- }
- expect(collectionId).to.be.equal(result.collectionId);
- expect(itemCountAfter.toString()).to.be.equal(result.itemId.toString());
- expect(to).to.be.deep.equal(result.recipient);
- newItemId = result.itemId;
- });
- return newItemId;
-}
-
-export async function createRefungibleToken(api: ApiPromise, sender: IKeyringPair, collectionId: number, amount: bigint, owner: CrossAccountId | IKeyringPair | string = sender.address) : Promise {
- const createData = {refungible: {pieces: amount}};
- const tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createData as any);
-
- const events = await submitTransactionAsync(sender, tx);
- return getCreateItemResult(events);
-}
-
-export async function createItemExpectFailure(sender: IKeyringPair, collectionId: number, createMode: string, owner: CrossAccountId | string = sender.address) {
- await usingApi(async (api) => {
- const tx = api.tx.unique.createItem(collectionId, normalizeAccountId(owner), createMode);
-
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getCreateItemResult(events);
-
- expect(result.success).to.be.false;
- });
-}
-
-export async function setPublicAccessModeExpectSuccess(
- sender: IKeyringPair, collectionId: number,
- accessMode: 'Normal' | 'AllowList',
-) {
- await usingApi(async (api) => {
-
- // Run the transaction
- const tx = api.tx.unique.setCollectionPermissions(collectionId, {access: accessMode});
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- // Get the collection
- const collection = await queryCollectionExpectSuccess(api, collectionId);
-
- // What to expect
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.true;
- expect(collection.permissions.access.toHuman()).to.be.equal(accessMode);
- });
-}
-
-export async function setPublicAccessModeExpectFail(
- sender: IKeyringPair, collectionId: number,
- accessMode: 'Normal' | 'AllowList',
-) {
- await usingApi(async (api) => {
-
- // Run the transaction
- const tx = api.tx.unique.setCollectionPermissions(collectionId, {access: accessMode});
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getGenericResult(events);
-
- // What to expect
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.false;
- });
-}
-
-export async function enableAllowListExpectSuccess(sender: IKeyringPair, collectionId: number) {
- await setPublicAccessModeExpectSuccess(sender, collectionId, 'AllowList');
-}
-
-export async function enableAllowListExpectFail(sender: IKeyringPair, collectionId: number) {
- await setPublicAccessModeExpectFail(sender, collectionId, 'AllowList');
-}
-
-export async function disableAllowListExpectSuccess(sender: IKeyringPair, collectionId: number) {
- await setPublicAccessModeExpectSuccess(sender, collectionId, 'Normal');
-}
-
-export async function setMintPermissionExpectSuccess(sender: IKeyringPair, collectionId: number, enabled: boolean) {
- await usingApi(async (api) => {
-
- // Run the transaction
- const tx = api.tx.unique.setCollectionPermissions(collectionId, {mintMode: enabled});
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
- expect(result.success).to.be.true;
-
- // Get the collection
- const collection = await queryCollectionExpectSuccess(api, collectionId);
-
- expect(collection.permissions.mintMode.toHuman()).to.be.equal(enabled);
- });
-}
-
-export async function enablePublicMintingExpectSuccess(sender: IKeyringPair, collectionId: number) {
- await setMintPermissionExpectSuccess(sender, collectionId, true);
-}
-
-export async function setMintPermissionExpectFailure(sender: IKeyringPair, collectionId: number, enabled: boolean) {
- await usingApi(async (api) => {
- // Run the transaction
- const tx = api.tx.unique.setCollectionPermissions(collectionId, {mintMode: enabled});
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getCreateCollectionResult(events);
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.false;
- });
-}
-
-export async function setChainLimitsExpectFailure(sender: IKeyringPair, limits: IChainLimits) {
- await usingApi(async (api) => {
- // Run the transaction
- const tx = api.tx.unique.setChainLimits(limits);
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getCreateCollectionResult(events);
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.false;
- });
-}
-
-export async function isAllowlisted(api: ApiPromise, collectionId: number, address: string | CrossAccountId | IKeyringPair) {
- return (await api.rpc.unique.allowed(collectionId, normalizeAccountId(address))).toJSON();
-}
-
-export async function addToAllowListExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId | CrossAccountId) {
- await usingApi(async (api) => {
- expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.false;
-
- // Run the transaction
- const tx = api.tx.unique.addToAllowList(collectionId, normalizeAccountId(address));
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
- expect(result.success).to.be.true;
-
- expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.true;
- });
-}
-
-export async function addToAllowListAgainExpectSuccess(sender: IKeyringPair, collectionId: number, address: string | AccountId) {
- await usingApi(async (api) => {
-
- expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.true;
-
- // Run the transaction
- const tx = api.tx.unique.addToAllowList(collectionId, normalizeAccountId(address));
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
- expect(result.success).to.be.true;
-
- expect(await isAllowlisted(api, collectionId, normalizeAccountId(address))).to.be.true;
- });
-}
-
-export async function addToAllowListExpectFail(sender: IKeyringPair, collectionId: number, address: string | AccountId) {
- await usingApi(async (api) => {
-
- // Run the transaction
- const tx = api.tx.unique.addToAllowList(collectionId, normalizeAccountId(address));
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getGenericResult(events);
-
- // What to expect
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.false;
- });
-}
-
-export async function removeFromAllowListExpectSuccess(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {
- await usingApi(async (api) => {
- // Run the transaction
- const tx = api.tx.unique.removeFromAllowList(collectionId, normalizeAccountId(address));
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- // What to expect
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.true;
- });
-}
-
-export async function removeFromAllowListExpectFailure(sender: IKeyringPair, collectionId: number, address: CrossAccountId) {
- await usingApi(async (api) => {
- // Run the transaction
- const tx = api.tx.unique.removeFromAllowList(collectionId, normalizeAccountId(address));
- const events = await expect(submitTransactionExpectFailAsync(sender, tx)).to.be.rejected;
- const result = getGenericResult(events);
-
- // What to expect
- // tslint:disable-next-line:no-unused-expression
- expect(result.success).to.be.false;
- });
-}
-
-export const getDetailedCollectionInfo = async (api: ApiPromise, collectionId: number)
- : Promise => {
- return (await api.rpc.unique.collectionById(collectionId)).unwrapOr(null);
-};
-
-export const getCreatedCollectionCount = async (api: ApiPromise): Promise => {
- // set global object - collectionsCount
- return (await api.rpc.unique.collectionStats()).created.toNumber();
-};
-
-export async function queryCollectionExpectSuccess(api: ApiPromise, collectionId: number): Promise {
- return (await api.rpc.unique.collectionById(collectionId)).unwrap();
-}
-
-export async function waitNewBlocks(blocksCount = 1): Promise {
- await usingApi(async (api) => {
- const promise = new Promise(async (resolve) => {
- const unsubscribe = await api.rpc.chain.subscribeNewHeads(() => {
- if (blocksCount > 0) {
- blocksCount--;
- } else {
- unsubscribe();
- resolve();
- }
- });
- });
- return promise;
- });
-}
-
-export async function waitEvent(
- api: ApiPromise,
- maxBlocksToWait: number,
- eventSection: string,
- eventMethod: string,
-): Promise {
-
- const promise = new Promise(async (resolve) => {
- const unsubscribe = await api.rpc.chain.subscribeNewHeads(async header => {
- const blockNumber = header.number.toHuman();
- const blockHash = header.hash;
- const eventIdStr = `${eventSection}.${eventMethod}`;
- const waitLimitStr = `wait blocks remaining: ${maxBlocksToWait}`;
-
- console.log(`[Block #${blockNumber}] Waiting for event \`${eventIdStr}\` (${waitLimitStr})`);
-
- const apiAt = await api.at(blockHash);
- const eventRecords = await apiAt.query.system.events();
-
- const neededEvent = eventRecords.find(r => {
- return r.event.section == eventSection && r.event.method == eventMethod;
- });
-
- if (neededEvent) {
- unsubscribe();
- resolve(neededEvent);
- } else if (maxBlocksToWait > 0) {
- maxBlocksToWait--;
- } else {
- console.log(`Event \`${eventIdStr}\` is NOT found`);
-
- unsubscribe();
- resolve(null);
- }
- });
- });
- return promise;
-}
-
-export async function repartitionRFT(
- api: ApiPromise,
- collectionId: number,
- sender: IKeyringPair,
- tokenId: number,
- amount: bigint,
-): Promise {
- const tx = api.tx.unique.repartition(collectionId, tokenId, amount);
- const events = await submitTransactionAsync(sender, tx);
- const result = getGenericResult(events);
-
- return result.success;
-}
-
-export async function itApi(name: string, cb: (apis: { api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair }) => any, opts: { only?: boolean, skip?: boolean } = {}) {
- let i: any = it;
- if (opts.only) i = i.only;
- else if (opts.skip) i = i.skip;
- i(name, async () => {
- await usingApi(async (api, privateKeyWrapper) => {
- await cb({api, privateKeyWrapper});
- });
- });
-}
-
-itApi.only = (name: string, cb: (apis: { api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair }) => any) => itApi(name, cb, {only: true});
-itApi.skip = (name: string, cb: (apis: { api: ApiPromise, privateKeyWrapper: (account: string) => IKeyringPair }) => any) => itApi(name, cb, {skip: true});
-
-let accountSeed = 10000;
-export function generateKeyringPair(keyring: Keyring) {
- const privateKey = `0xDEADBEEF${(Date.now() + (accountSeed++)).toString(16).padStart(64 - 8, '0')}`;
- return keyring.addFromUri(privateKey);
-}
-
-export async function expectSubstrateEventsAtBlock(api: ApiPromise, blockNumber: AnyNumber | BlockNumber, section: string, methods: string[], dryRun = false) {
- const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
- const subEvents = (await api.query.system.events.at(blockHash))
- .filter(x => x.event.section === section)
- .map((x) => x.toHuman());
- const events = methods.map((m) => {
- return {
- event: {
- method: m,
- section,
- },
- };
- });
- if (!dryRun) {
- expect(subEvents).to.be.like(events);
- }
- return subEvents;
-}
--- a/tests/src/deprecated-helpers/util.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.
-// This file is part of Unique Network.
-
-// Unique Network is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Unique Network is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Unique Network. If not, see .
-
-export function strToUTF16(str: string): any {
- const buf: number[] = [];
- for (let i=0, strLen=str.length; i < strLen; i++) {
- buf.push(str.charCodeAt(i));
- }
- return buf;
-}
-
-export function utf16ToStr(buf: number[]): string {
- let str = '';
- for (let i=0, strLen=buf.length; i < strLen; i++) {
- if (buf[i] != 0) str += String.fromCharCode(buf[i]);
- else break;
- }
- return str;
-}
-
-export function hexToStr(buf: string): string {
- let str = '';
- let hexStart = buf.indexOf('0x');
- if (hexStart < 0) hexStart = 0;
- else hexStart = 2;
- for (let i=hexStart, strLen=buf.length; i < strLen; i+=2) {
- const ch = buf[i] + buf[i+1];
- const num = parseInt(ch, 16);
- if (num != 0) str += String.fromCharCode(num);
- else break;
- }
- return str;
-}