git.delta.rocks / unique-network / refs/commits / 8154d7d843bf

difftreelog

transferSuccess

kpozdnikin2021-01-19parent: #567e35d.patch.diff
in: master

5 files changed

modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -28,7 +28,8 @@
     "testTransferFrom": "mocha --timeout 9999999 -r ts-node/register ./**/transferFrom.test.ts",
     "testCreateCollection": "mocha --timeout 9999999 -r ts-node/register ./**/createCollection.test.ts",
     "testToggleContractWhiteList": "mocha --timeout 9999999 -r ts-node/register ./**/toggleContractWhiteList.test.ts",
-    "testAddToContractWhiteList": "mocha --timeout 9999999 -r ts-node/register ./**/addToContractWhiteList.test.ts"
+    "testAddToContractWhiteList": "mocha --timeout 9999999 -r ts-node/register ./**/addToContractWhiteList.test.ts",
+    "testTransfer": "mocha --timeout 9999999 -r ts-node/register ./**/transfer.test.ts"
   },
   "author": "",
   "license": "Apache 2.0",
modifiedtests/src/substrate/get-balance.tsdiffbeforeafterboth
--- a/tests/src/substrate/get-balance.ts
+++ b/tests/src/substrate/get-balance.ts
@@ -3,12 +3,12 @@
 // file 'LICENSE', which is part of this source code package.
 //
 
-import { ApiPromise } from "@polkadot/api";
-import promisifySubstrate from "./promisify-substrate";
-import {AccountInfo} from "@polkadot/types/interfaces/system";
+import { ApiPromise } from '@polkadot/api';
+import {AccountInfo} from '@polkadot/types/interfaces/system';
+import promisifySubstrate from './promisify-substrate';
 
-export default async function getBalance(api: ApiPromise, accounts: string[]): Promise<bigint[]> {
-  const balance = promisifySubstrate(api, (accounts: string[]) => api.query.system.account.multi(accounts));
+export default async function getBalance(api: ApiPromise, accounts: string[]): Promise<Array<bigint>> {
+  const balance = promisifySubstrate(api, (acc: string[]) => api.query.system.account.multi(acc));
   const responce = await balance(accounts) as unknown as AccountInfo[];
-  return responce.map(r => r.data.free.toBigInt().valueOf());
+  return responce.map((r) => r.data.free.toBigInt().valueOf());
 }
modifiedtests/src/substrate/substrate-api.tsdiffbeforeafterboth
before · tests/src/substrate/substrate-api.ts
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56import { WsProvider, ApiPromise } from "@polkadot/api";7import type { AccountId, Address, ApplyExtrinsicResult, DispatchError, DispatchInfo, EventRecord, Extrinsic, ExtrinsicStatus, Hash, RuntimeDispatchInfo } from '@polkadot/types/interfaces';8import { IKeyringPair } from "@polkadot/types/types";910import config from "../config";11import promisifySubstrate from "./promisify-substrate";12import { ApiOptions, SubmittableExtrinsic, ApiTypes } from "@polkadot/api/types";13import rtt from "../../../runtime_types.json";1415function defaultApiOptions(): ApiOptions {16  const wsProvider = new WsProvider(config.substrateUrl);17  return { provider: wsProvider, types: rtt };18}1920export default async function usingApi(action: (api: ApiPromise) => Promise<void>, settings: ApiOptions | undefined = undefined): Promise<void> {21  settings = settings || defaultApiOptions();22  let api: ApiPromise = new ApiPromise(settings);2324  try {25    await promisifySubstrate(api, async () => {26      if(api) {27        await api.isReadyOrError;28        await action(api);29      }30    })();31  } finally {32    await api.disconnect();33  }34}3536enum TransactionStatus {37  Success,38  Fail,39  NotReady40}4142function getTransactionStatus(events: EventRecord[], status: ExtrinsicStatus): TransactionStatus {43  if (status.isReady) {44    return TransactionStatus.NotReady;45  }46  if (status.isBroadcast) {47    return TransactionStatus.NotReady;48  } 49  if (status.isInBlock || status.isFinalized) {50    if(events.filter(e => e.event.data.method === 'ExtrinsicFailed').length > 0) {51      return TransactionStatus.Fail;52    }53    if(events.filter(e => e.event.data.method === 'ExtrinsicSuccess').length > 0) {54      return TransactionStatus.Success;55    }56  }5758  return TransactionStatus.Fail;59}6061export function submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {62  return new Promise(async function(resolve, reject) {63    try {64      await transaction.signAndSend(sender, ({ events = [], status }) => {65        const transactionStatus = getTransactionStatus(events, status);6667        if (transactionStatus == TransactionStatus.Success) {68          resolve(events);69        } else if (transactionStatus == TransactionStatus.Fail) {70          console.log(`Something went wrong with transaction. Status: ${status}`);71          reject(events);72        }73      });74    } catch (e) {75      console.log("Error: ", e);76      reject(e);77    }78  });79}8081export function submitTransactionExpectFailAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {82  const consoleError = console.error;83  const consoleLog = console.log;84  console.error = () => {};85  console.log = () => {};8687  return new Promise<EventRecord[]>(async function(res, rej) {88    const resolve = (rec: EventRecord[]) => {89      setTimeout(() => {90        res(rec);91        console.error = consoleError;92        console.log = consoleLog;93      });94    };95    const reject = (errror: any) => {96      setTimeout(() => {97        rej(errror);98        console.error = consoleError;99        console.log = consoleLog;100      });101    };102    try {103      await transaction.signAndSend(sender, ({ events = [], status }) => {104        const transactionStatus = getTransactionStatus(events, status);105106        console.log('transactionStatus', transactionStatus, 'events', events);107108        if (transactionStatus == TransactionStatus.Success) {109          resolve(events);110        } else if (transactionStatus == TransactionStatus.Fail) {111          reject(events);112        }113      });114    } catch (e) {115      reject(e);116    }117  });118}
after · tests/src/substrate/substrate-api.ts
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56import { WsProvider, ApiPromise } from "@polkadot/api";7import type { AccountId, Address, ApplyExtrinsicResult, DispatchError, DispatchInfo, EventRecord, Extrinsic, ExtrinsicStatus, Hash, RuntimeDispatchInfo } from '@polkadot/types/interfaces';8import { IKeyringPair } from "@polkadot/types/types";910import config from "../config";11import promisifySubstrate from "./promisify-substrate";12import { ApiOptions, SubmittableExtrinsic, ApiTypes } from "@polkadot/api/types";13import rtt from "../../../runtime_types.json";1415function defaultApiOptions(): ApiOptions {16  const wsProvider = new WsProvider(config.substrateUrl);17  return { provider: wsProvider, types: rtt };18}1920export default async function usingApi(action: (api: ApiPromise) => Promise<void>, settings: ApiOptions | undefined = undefined): Promise<void> {21  settings = settings || defaultApiOptions();22  let api: ApiPromise = new ApiPromise(settings);2324  try {25    await promisifySubstrate(api, async () => {26      if(api) {27        await api.isReadyOrError;28        await action(api);29      }30    })();31  } finally {32    await api.disconnect();33  }34}3536enum TransactionStatus {37  Success,38  Fail,39  NotReady40}4142function getTransactionStatus(events: EventRecord[], status: ExtrinsicStatus): TransactionStatus {43  if (status.isReady) {44    return TransactionStatus.NotReady;45  }46  if (status.isBroadcast) {47    return TransactionStatus.NotReady;48  } 49  if (status.isInBlock || status.isFinalized) {50    if(events.filter(e => e.event.data.method === 'ExtrinsicFailed').length > 0) {51      return TransactionStatus.Fail;52    }53    if(events.filter(e => e.event.data.method === 'ExtrinsicSuccess').length > 0) {54      return TransactionStatus.Success;55    }56  }5758  return TransactionStatus.Fail;59}6061export function62submitTransactionAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {63  return new Promise(async (resolve, reject) => {64    try {65      await transaction.signAndSend(sender, ({ events = [], status }) => {66        const transactionStatus = getTransactionStatus(events, status);6768        if (transactionStatus === TransactionStatus.Success) {69          resolve(events);70        } else if (transactionStatus === TransactionStatus.Fail) {71          console.log(`Something went wrong with transaction. Status: ${status}`);72          reject(events);73        }74      });75    } catch (e) {76      console.log('Error: ', e);77      reject(e);78    }79  });80}8182export function submitTransactionExpectFailAsync(sender: IKeyringPair, transaction: SubmittableExtrinsic<ApiTypes>): Promise<EventRecord[]> {83  const consoleError = console.error;84  const consoleLog = console.log;85  console.error = () => {};86  console.log = () => {};8788  return new Promise<EventRecord[]>(async function(res, rej) {89    const resolve = (rec: EventRecord[]) => {90      setTimeout(() => {91        res(rec);92        console.error = consoleError;93        console.log = consoleLog;94      });95    };96    const reject = (errror: any) => {97      setTimeout(() => {98        rej(errror);99        console.error = consoleError;100        console.log = consoleLog;101      });102    };103    try {104      await transaction.signAndSend(sender, ({ events = [], status }) => {105        const transactionStatus = getTransactionStatus(events, status);106107        console.log('transactionStatus', transactionStatus, 'events', events);108109        if (transactionStatus == TransactionStatus.Success) {110          resolve(events);111        } else if (transactionStatus == TransactionStatus.Fail) {112          reject(events);113        }114      });115    } catch (e) {116      reject(e);117    }118  });119}
modifiedtests/src/transfer.test.tsdiffbeforeafterboth
--- a/tests/src/transfer.test.ts
+++ b/tests/src/transfer.test.ts
@@ -3,49 +3,99 @@
 // file 'LICENSE', which is part of this source code package.
 //
 
-import { expect, assert } from "chai";
-import { default as usingApi, submitTransactionAsync } from "./substrate/substrate-api";
-import { alicesPublicKey, bobsPublicKey, ferdiesPublicKey } from "./accounts";
-import privateKey from "./substrate/privateKey";
-import getBalance from "./substrate/get-balance";
-import { BigNumber } from 'bignumber.js';
-import { findUnusedAddress } from './util/helpers'
+import { ApiPromise } from '@polkadot/api';
+import { expect } from 'chai';
+import { alicesPublicKey, bobsPublicKey } from './accounts';
+import getBalance from './substrate/get-balance';
+import privateKey from './substrate/privateKey';
+import {default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api';
+import {
+  approveExpectSuccess,
+  createCollectionExpectSuccess, createItemExpectSuccess,
+  findUnusedAddress,
+  getCreateCollectionResult,
+  getCreateItemResult,
+  transferExpectSuccess,
+} from './util/helpers';
 
-describe('Transfer', () => {
-  it('Balance transfers', async () => {
-    await usingApi(async api => {
+describe('Integration Test Transfer(recipient, collection_id, item_id, value)', () => {
+  it('Balance transfers and check balance', async () => {
+    await usingApi(async (api: ApiPromise) => {
       const [alicesBalanceBefore, bobsBalanceBefore] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);
 
       const alicePrivateKey = privateKey('//Alice');
-      
+
       const transfer = api.tx.balances.transfer(bobsPublicKey, 1n);
-      const result = await submitTransactionAsync(alicePrivateKey, transfer);
+      const events = await submitTransactionAsync(alicePrivateKey, transfer);
+      const result = getCreateItemResult(events);
+      // tslint:disable-next-line:no-unused-expression
+      expect(result.success).to.be.true;
 
       const [alicesBalanceAfter, bobsBalanceAfter] = await getBalance(api, [alicesPublicKey, bobsPublicKey]);
 
+      // tslint:disable-next-line:no-unused-expression
       expect(alicesBalanceAfter < alicesBalanceBefore).to.be.true;
+      // tslint:disable-next-line:no-unused-expression
       expect(bobsBalanceAfter > bobsBalanceBefore).to.be.true;
     });
   });
 
   it('Inability to pay fees error message is correct', async () => {
-    await usingApi(async api => {
+    await usingApi(async (api) => {
       // Find unused address
       const pk = await findUnusedAddress(api);
 
-      const error = console.error;
-      const log = console.log;
-      console.log = function () {};
-      console.error = function () {};
-  
       const badTransfer = api.tx.balances.transfer(bobsPublicKey, 1n);
-      const badTransaction = async function () { 
-        const result = await submitTransactionAsync(pk, badTransfer);
+      // const events = await submitTransactionAsync(pk, badTransfer);
+      const badTransaction = async () => {
+        const events = await submitTransactionAsync(pk, badTransfer);
+        const result = getCreateCollectionResult(events);
+        // tslint:disable-next-line:no-unused-expression
+        expect(result.success).to.be.false;
       };
-      await expect(badTransaction()).to.be.rejectedWith("Inability to pay some fees");
-
-      console.log = log;
-      console.error = error;
+      expect(badTransaction()).to.be.rejectedWith('Inability to pay some fees , e.g. account balance too low');
     });
   });
+
+  it('Create collection, balance transfers and check balance', async () => {
+    const Alice = privateKey('//Alice');
+    const Bob = privateKey('//Bob');
+    const Charlie = privateKey('//CHARLIE');
+    // nft
+    const nftCollectionId = await createCollectionExpectSuccess();
+    const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
+
+    await transferExpectSuccess(nftCollectionId, newNftTokenId, Alice, Bob, 1, 'NFT');
+
+    // fungible
+    const fungibleCollectionId = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+    const newFungibleTokenId = await createItemExpectSuccess(Alice, fungibleCollectionId, 'Fungible');
+    await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob);
+    await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');
+    // reFungible
+    const reFungibleCollectionId = await
+      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+    const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
+    await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob);
+    await transferExpectSuccess(reFungibleCollectionId,
+      newReFungibleTokenId, Alice, Bob, 1, 'ReFungible');
+  });
+});
+
+describe('Negative Integration Test Transfer(recipient, collection_id, item_id, value)', () => {
+  it('Transfer with not existed collection_id', async () => {
+
+  });
+  it('Transfer with deleted collection_id', async () => {
+
+  });
+  it('Transfer with not existed item_id', async () => {
+
+  });
+  it('Transfer with deleted item_id', async () => {
+
+  });
+  it('Transfer with recipient that is not owner', async () => {
+
+  });
 });
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -462,6 +462,40 @@
 }
 
 export async function
+transferExpectSuccess(collectionId: number,
+                      tokenId: number,
+                      sender: IKeyringPair,
+                      recipient: IKeyringPair,
+                      value: number = 1,
+                      type: string = 'NFT') {
+  await usingApi(async (api: ApiPromise) => {
+    let balanceBefore = new BN(0);
+    if (type === 'Fungible') {
+      balanceBefore = await api.query.nft.balance(collectionId, recipient.address) as unknown as BN;
+    }
+    const transferTx = await api.tx.nft.transfer(recipient.address, collectionId, tokenId, value);
+    const events = await submitTransactionAsync(sender, transferTx);
+    const result = getCreateItemResult(events);
+    // tslint:disable-next-line:no-unused-expression
+    expect(result.success).to.be.true;
+    if (type === 'NFT') {
+      const nftItemData = await api.query.nft.nftItemList(collectionId, tokenId) as unknown as ITokenDataType;
+      expect(nftItemData.Owner.toString()).to.be.equal(recipient.address);
+    }
+    if (type === 'Fungible') {
+      const balanceAfter = await api.query.nft.balance(collectionId, recipient.address) as unknown as BN;
+      expect(balanceAfter.sub(balanceBefore).toNumber()).to.be.equal(value);
+    }
+    if (type === 'ReFungible') {
+      const nftItemData =
+        await api.query.nft.reFungibleItemList(collectionId, tokenId) as unknown as IReFungibleTokenDataType;
+      expect(nftItemData.Owner[0].Owner.toString()).to.be.equal(recipient.address);
+      expect(nftItemData.Owner[0].Fraction.toNumber()).to.be.equal(value);
+    }
+  });
+}
+
+export async function
 approveExpectFail(collectionId: number,
                   tokenId: number, owner: IKeyringPair, approved: IKeyringPair, amount: number = 1) {
   await usingApi(async (api: ApiPromise) => {