difftreelog
Merge branch 'master' of github.com:usetech-llc/nft_parachain
in: master
14 files changed
.editorconfigdiffbeforeafterboth--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,13 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+
+[*.ts]
+indent_style = space
+indent_size = 2
+
+[*.yaml]
+indent_style = space
+indent_size = 2
.gitignorediffbeforeafterboth--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,6 @@
chain-data*/
einstein_key_file
-*store_key*.json
\ No newline at end of file
+*store_key*.json
+
+/.idea/
\ No newline at end of file
tests/.gitignorediffbeforeafterboth--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1 @@
+/node_modules/
tests/.vscode/launch.jsondiffbeforeafterboth--- /dev/null
+++ b/tests/.vscode/launch.json
@@ -0,0 +1,42 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Mocha Current File",
+ "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
+ "args": [
+ "--timeout",
+ "9999999",
+ "--colors",
+ "--recursive",
+ "--require",
+ "ts-node/register",
+ "${file}"
+ ],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen"
+ },
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Mocha All tests",
+ "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",
+ "args": [
+ "--timeout",
+ "9999999",
+ "--colors",
+ "--recursive",
+ "--require",
+ "ts-node/register",
+ "./**/*.test.ts"
+ ],
+ "console": "integratedTerminal",
+ "internalConsoleOptions": "neverOpen"
+ }
+ ]
+}
\ No newline at end of file
tests/package-lock.jsondiffbeforeafterbothno changes
tests/package.jsondiffbeforeafterboth--- /dev/null
+++ b/tests/package.json
@@ -0,0 +1,43 @@
+{
+ "name": "NftTests",
+ "version": "1.0.0",
+ "description": "Substrate Nft tests",
+ "main": "",
+ "devDependencies": {
+ "@polkadot/dev": "^0.52.11",
+ "@polkadot/ts": "^0.3.41",
+ "@types/bn.js": "^4.11.6",
+ "@types/chai": "^4.2.12",
+ "@types/chai-as-promised": "^7.1.3",
+ "@types/mocha": "^8.0.3",
+ "chai": "^4.2.0",
+ "mocha": "^8.1.1",
+ "ts-node": "^9.0.0",
+ "tslint": "^5.20.1",
+ "typescript": "^3.9.7"
+ },
+ "scripts": {
+ "test": "mocha --timeout 9999999 -r ts-node/register ./**/*.test.ts"
+ },
+ "author": "",
+ "license": "Apache 2.0",
+ "homepage": "",
+ "dependencies": {
+ "@polkadot/api": "^1.31.2",
+ "@polkadot/types": "^1.31.2",
+ "@polkadot/util": "^2.18.1",
+ "@types/bn.js": "^4.11.6",
+ "chai-as-promised": "^7.1.1"
+ },
+ "standard": {
+ "globals": [
+ "it",
+ "assert",
+ "beforeEach",
+ "afterEach",
+ "describe",
+ "contract",
+ "artifacts"
+ ]
+ }
+}
tests/src/config.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/config.ts
@@ -0,0 +1,71 @@
+import process from 'process';
+
+const config = {
+ substrateUrl: process.env.substrateUrl || 'ws://127.0.0.1:9944',
+ customTypes: process.env.customTypes || `{
+ "Schedule": {
+ "version": "u32",
+ "put_code_per_byte_cost": "Gas",
+ "grow_mem_cost": "Gas",
+ "regular_op_cost": "Gas",
+ "return_data_per_byte_cost": "Gas",
+ "event_data_per_byte_cost": "Gas",
+ "event_per_topic_cost": "Gas",
+ "event_base_cost": "Gas",
+ "call_base_cost": "Gas",
+ "instantiate_base_cost": "Gas",
+ "dispatch_base_cost": "Gas",
+ "sandbox_data_read_cost": "Gas",
+ "sandbox_data_write_cost": "Gas",
+ "transfer_cost": "Gas",
+ "instantiate_cost": "Gas",
+ "max_event_topics": "u32",
+ "max_stack_height": "u32",
+ "max_memory_pages": "u32",
+ "max_table_size": "u32",
+ "enable_println": "bool",
+ "max_subject_len": "u32"
+ },
+ "CollectionMode": {
+ "_enum": {
+ "Invalid": null,
+ "NFT": "u32",
+ "Fungible": "u32",
+ "ReFungible": "(u32, u32)"
+ }
+ },
+ "NftItemType": {
+ "Collection": "u64",
+ "Owner": "AccountId",
+ "Data": "Vec<u8>"
+ },
+ "Ownership": {
+ "owner": "AccountId",
+ "fraction": "u128"
+ },
+ "ReFungibleItemType": {
+ "Collection": "u64",
+ "Owner": "Vec<Ownership<AccountId>>",
+ "Data": "Vec<u8>"
+ },
+ "CollectionType": {
+ "Owner": "AccountId",
+ "Mode": "CollectionMode",
+ "Access": "u8",
+ "DecimalPoints": "u32",
+ "Name": "Vec<u16>",
+ "Description": "Vec<u16>",
+ "TokenPrefix": "Vec<u8>",
+ "CustomDataSize": "u32",
+ "OffchainSchema": "Vec<u8>",
+ "Sponsor": "AccountId",
+ "UnconfirmedSponsor": "AccountId"
+ },
+ "RawData": "Vec<u8>",
+ "Address": "AccountId",
+ "LookupSource": "AccountId",
+ "Weight": "u64"
+ }`
+}
+
+export default config;
\ No newline at end of file
tests/src/connection.test.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/connection.test.ts
@@ -0,0 +1,26 @@
+import usingApi from "./substrate/substrate-api";
+import { WsProvider } from '@polkadot/api';
+import * as chai from 'chai';
+import chaiAsPromised from 'chai-as-promised';
+
+chai.use(chaiAsPromised);
+
+const expect = chai.expect;
+
+describe('Connection', () => {
+ it('Connection can be established', async () => {
+ await usingApi(async api => {
+ const health = await api.rpc.system.health();
+ expect(health).to.be.not.empty;
+ });
+ });
+
+ it('Cannot connect to 0.0.0.0', () => {
+ const neverConnectProvider = new WsProvider('ws://0.0.0.0:9944');
+ expect((async () => {
+ await usingApi(async api => {
+ const health = await api.rpc.system.health();
+ }, { provider: neverConnectProvider });
+ })()).to.be.eventually.rejected;
+ });
+});
\ No newline at end of file
tests/src/substrate/promisify-substrate.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/substrate/promisify-substrate.ts
@@ -0,0 +1,32 @@
+import ApiPromise from "@polkadot/api/promise/Api";
+
+type PromiseType<T> = T extends PromiseLike<infer TInner> ? TInner : T;
+
+export default function promisifySubstrate<T extends (...args: any[]) => any>(api: ApiPromise, action: T): (...args: Parameters<T>) => Promise<PromiseType<ReturnType<T>>> {
+ return (...args: Parameters<T>) => {
+ const promise = new Promise<PromiseType<ReturnType<T>>>((resolve, reject) => {
+ const cleanup = () => {
+ api.off('disconnected', fail);
+ api.off('error', fail);
+ };
+
+ const success = (r: any) => {
+ cleanup();
+ resolve(r);
+ };
+ const fail = (error: any) => {
+ cleanup();
+ reject(error);
+ };
+
+ api.on('disconnected', fail);
+ api.on('error', fail);
+
+ const result = action(...args);
+ Promise.resolve(result)
+ .then(success, fail);
+
+ });
+ return promise as any;
+ };
+}
tests/src/substrate/substrate-api.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/substrate/substrate-api.ts
@@ -0,0 +1,22 @@
+import { WsProvider, ApiPromise } from "@polkadot/api";
+import config from "../config";
+import promisifySubstrate from "./promisify-substrate";
+import { ApiOptions } from "@polkadot/api/types";
+
+function defaultApiOptions(): ApiOptions {
+ const wsProvider = new WsProvider(config.substrateUrl);
+ return { provider: wsProvider, types: JSON.parse(config.customTypes) };
+}
+
+export default async function usingApi(action: (api: ApiPromise) => Promise<void>, settings: ApiOptions | undefined = undefined): Promise<void> {
+ settings = settings || defaultApiOptions();
+ let api: ApiPromise | undefined = undefined;
+
+ try {
+ api = new ApiPromise(settings);
+ await promisifySubstrate(api, () => api && api.isReady)();
+ await action(api);
+ } finally {
+ api && api.disconnect();
+ }
+}
\ No newline at end of file
tests/src/substrate/wait-new-blocks.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/substrate/wait-new-blocks.ts
@@ -0,0 +1,17 @@
+import { ApiPromise } from "@polkadot/api";
+
+export default function waitNewBlocks(api: ApiPromise, blocksCount: number = 1): Promise<void> {
+ const promise = new Promise<void>(async (resolve, reject) => {
+
+ const unsubscribe = await api.rpc.chain.subscribeNewHeads(head => {
+ if(blocksCount > 0) {
+ blocksCount--;
+ }else {
+ unsubscribe();
+ resolve();
+ }
+ });
+ });
+
+ return promise;
+}
\ No newline at end of file
tests/src/transfer.test.tsdiffbeforeafterboth--- /dev/null
+++ b/tests/src/transfer.test.ts
@@ -0,0 +1,38 @@
+import createSubstrateApi from "./substrate/substrate-api";
+import { Keyring, ApiPromise } from "@polkadot/api";
+import {AccountInfo} from "@polkadot/types/interfaces/system";
+import { expect } from "chai";
+import usingApi from "./substrate/substrate-api";
+import promisifySubstrate from "./substrate/promisify-substrate";
+import waitNewBlocks from "./substrate/wait-new-blocks";
+
+async function getBalance(api: ApiPromise, accounts: string[]): Promise<bigint[]> {
+ const balance = promisifySubstrate(api, (accounts: string[]) => api.query.system.account.multi(accounts));
+ const responce = await balance(accounts) as unknown as AccountInfo[];
+ return responce.map(r => r.data.free.toBigInt().valueOf());
+}
+
+describe('Transfer', () => {
+ it('Balance transfers', async () => {
+ const bobsPublicKey = '5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty';
+ const alicesPublicKey = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
+ await usingApi(async api => {
+ const [alicesBalanceBefore, bobsBalanceBefore] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);
+
+ const keyring = new Keyring({ type: 'sr25519' });
+
+ const alicePrivateKey = keyring.addFromUri('//Alice');
+
+ const transfer = api.tx.balances.transfer(bobsPublicKey, 1n);
+
+ const hash = await transfer.signAndSend(alicePrivateKey);
+
+ await waitNewBlocks(api);
+
+ const [alicesBalanceAfter, bobsBalanceAfter] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);
+
+ expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;
+ expect(bobsBalanceAfter > bobsBalanceBefore).to.be.true;
+ });
+ });
+});
tests/tsconfig.jsondiffbeforeafterboth--- /dev/null
+++ b/tests/tsconfig.json
@@ -0,0 +1,22 @@
+{
+ "exclude": [
+ "node_modules",
+ "node_modules/**/*",
+ "**/node_modules/**/*"
+ ],
+ "compilerOptions": {
+ "target": "ES2020",
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "resolveJsonModule": true,
+ "module": "commonjs",
+ "sourceMap": true,
+ "outDir": "dist",
+ "rootDir": "src",
+ "strict": true
+ },
+ "include": [
+ "src/**/*"
+ ],
+ "lib": ["es2017"]
+}
tests/tslint.jsondiffbeforeafterboth--- /dev/null
+++ b/tests/tslint.json
@@ -0,0 +1,11 @@
+{
+ "defaultSeverity": "error",
+ "extends": ["tslint:recommended"],
+ "jsRules": {},
+ "rules": {
+ "indent": [false, "spaces"],
+ "no-console": false,
+ "quotemark": [true, "single", "avoid-escape", "avoid-template"]
+ },
+ "rulesDirectory": []
+}