difftreelog
transferSuccess
in: master
5 files changed
tests/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",
tests/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());
}
tests/src/substrate/substrate-api.tsdiffbeforeafterboth1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56import { 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}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}tests/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 () => {
+
+ });
});
tests/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) => {