git.delta.rocks / unique-network / refs/commits / 88a8aa611cb6

difftreelog

Merge pull request #404 from UniqueNetwork/test/unique-refungible

ut-akuznetsov2022-06-24parents: #421f362 #db7a4ac.patch.diff
in: master

2 files changed

addedtests/src/refungible.test.tsdiffbeforeafterboth
after · tests/src/refungible.test.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import {default as usingApi} from './substrate/substrate-api';18import {IKeyringPair} from '@polkadot/types/types';19import {20  createCollectionExpectSuccess,21  getBalance,22  createMultipleItemsExpectSuccess,23  isTokenExists,24  getLastTokenId,25  getAllowance,26  approve,27  transferFrom,28  createCollection,29  createRefungibleToken,30  transfer,31  burnItem,32} from './util/helpers';3334import chai from 'chai';35import chaiAsPromised from 'chai-as-promised';36chai.use(chaiAsPromised);37const expect = chai.expect;3839let alice: IKeyringPair;40let bob: IKeyringPair;4142describe('integration test: Refungible functionality:', () => {43  before(async () => {44    await usingApi(async (api, privateKeyWrapper) => {45      alice = privateKeyWrapper('//Alice');46      bob = privateKeyWrapper('//Bob');47    });48  });4950  it('Create refungible collection and token', async () => {51    await usingApi(async api => {52      const createCollectionResult = await createCollection(api, alice, {mode: {type: 'ReFungible'}});53      expect(createCollectionResult.success).to.be.true;    54      const collectionId  = createCollectionResult.collectionId;5556      const itemCountBefore = await getLastTokenId(api, collectionId);57      const result = await createRefungibleToken(api, alice, collectionId, 100n);5859      const itemCountAfter = await getLastTokenId(api, collectionId);6061      // What to expect62      // tslint:disable-next-line:no-unused-expression63      expect(result.success).to.be.true;64      expect(itemCountAfter).to.be.equal(itemCountBefore + 1);65      expect(collectionId).to.be.equal(result.collectionId);66      expect(itemCountAfter.toString()).to.be.equal(result.itemId.toString());67    });68  });6970  it('Transfer token pieces', async () => {71    await usingApi(async api => {72      const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;73      const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n)).itemId;7475      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(100n);76      expect(await transfer(api, collectionId, tokenId, alice, bob, 60n)).to.be.true;7778      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(40n);79      expect(await getBalance(api, collectionId, bob, tokenId)).to.be.equal(60n);80      await expect(transfer(api, collectionId, tokenId, alice, bob, 41n)).to.eventually.be.rejected;81    });82  });8384  it('Create multiple tokens', async () => {85    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});86    const args = [87      {ReFungible: {pieces: 1}},88      {ReFungible: {pieces: 2}},89      {ReFungible: {pieces: 100}},90    ];91    await createMultipleItemsExpectSuccess(alice, collectionId, args);9293    await usingApi(async api => {      94      const tokenId = await getLastTokenId(api, collectionId);95      expect(tokenId).to.be.equal(3);96      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(100n);97    });98  });99100  it('Burn some pieces', async () => {101    await usingApi(async api => {   102      const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;103      const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n)).itemId;104      expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;105      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(100n);106      expect(await burnItem(api, alice, collectionId, tokenId, 99n)).to.be.true;107      expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;108      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(1n);109    });110  });111112  it('Burn all pieces', async () => {113    await usingApi(async api => {   114      const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;115      const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n)).itemId;116      expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;117      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(100n);118      expect(await burnItem(api, alice, collectionId, tokenId, 100n)).to.be.true;119      expect(await isTokenExists(api, collectionId, tokenId)).to.be.false;120    });121  });122123  it('Burn some pieces for multiple users', async () => {124    await usingApi(async api => {   125      const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;126      const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n)).itemId;127      expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;128129      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(100n);130      expect(await transfer(api, collectionId, tokenId, alice, bob, 60n)).to.be.true;131132      133      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(40n);134      expect(await getBalance(api, collectionId, bob, tokenId)).to.be.equal(60n);135      expect(await burnItem(api, alice, collectionId, tokenId, 40n)).to.be.true;136137      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(0n);138      expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;139      expect(await burnItem(api, bob, collectionId, tokenId, 59n)).to.be.true;140141      expect(await getBalance(api, collectionId, bob, tokenId)).to.be.equal(1n);142      expect(await isTokenExists(api, collectionId, tokenId)).to.be.true;143      expect(await burnItem(api, bob, collectionId, tokenId, 1n)).to.be.true;144      145      expect(await isTokenExists(api, collectionId, tokenId)).to.be.false;146    });147  });148149  it('Set allowance for token', async () => {150    await usingApi(async api => {151      const collectionId = (await createCollection(api, alice, {mode: {type: 'ReFungible'}})).collectionId;152      const tokenId = (await createRefungibleToken(api, alice, collectionId, 100n)).itemId;153154      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(100n);155156      expect(await approve(api, collectionId, tokenId, alice, bob, 60n)).to.be.true;157      expect(await getAllowance(api, collectionId, alice, bob, tokenId)).to.be.equal(60n);158159      expect(await transferFrom(api, collectionId, tokenId, bob, alice, bob,  20n)).to.be.true;160      expect(await getBalance(api, collectionId, alice, tokenId)).to.be.equal(80n);161      expect(await getBalance(api, collectionId, bob, tokenId)).to.be.equal(20n);162      expect(await getAllowance(api, collectionId, alice, bob, tokenId)).to.be.equal(40n);163    });164  });165});
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -318,6 +318,33 @@
   tokenPrefix: 'prefix',
 };
 
+export async function
+createCollection(
+  api: ApiPromise,
+  sender: IKeyringPair,
+  params: Partial<CreateCollectionParams> = {},
+): Promise<CreateCollectionResult> {
+  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 submitTransactionAsync(sender, tx);
+  return getCreateCollectionResult(events);
+}
+
 export async function createCollectionExpectSuccess(params: Partial<CreateCollectionParams> = {}): Promise<number> {
   const {name, description, mode, tokenPrefix} = {...defaultCreateCollectionParams, ...params};
 
@@ -329,23 +356,7 @@
     // 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,
-    });
-    const events = await submitTransactionAsync(alicePrivateKey, tx);
-    const result = getCreateCollectionResult(events);
+    const result = await createCollection(api, alicePrivateKey, params);
 
     // Get number of collections after the transaction
     const collectionCountAfter = await getCreatedCollectionCount(api);
@@ -490,7 +501,7 @@
   return unused;
 }
 
-export async function getAllowance(api: ApiPromise, collectionId: number, owner: CrossAccountId | string, approved: CrossAccountId | string, tokenId: number) {
+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();
 }
 
@@ -800,16 +811,19 @@
   ReFungible: CreateReFungibleData;
 };
 
-export async function burnItemExpectSuccess(sender: IKeyringPair, collectionId: number, tokenId: number, value = 1) {
+export async function burnItem(api: ApiPromise, sender: IKeyringPair, collectionId: number, tokenId: number, value: number | bigint) : Promise<boolean> {
+  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;
 
-    const tx = api.tx.unique.burnItem(collectionId, tokenId, value);
-    const events = await submitTransactionAsync(sender, tx);
-    const result = getGenericResult(events);
-    expect(result.success).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);
@@ -817,17 +831,26 @@
 }
 
 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 approveUniqueTx = api.tx.unique.approve(normalizeAccountId(approved), collectionId, tokenId, amount);
-    const events = await submitTransactionAsync(owner, approveUniqueTx);
-    const result = getGenericResult(events);
-    expect(result.success).to.be.true;
+    const result = await approve(api, collectionId, tokenId, owner, approved, amount);
+    expect(result).to.be.true;
 
-    expect(await getAllowance(api, collectionId, owner.address, approved, tokenId)).to.be.equal(BigInt(amount));
+    expect(await getAllowance(api, collectionId, owner, approved, tokenId)).to.be.equal(BigInt(amount));
   });
 }
 
@@ -846,6 +869,23 @@
 }
 
 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,
@@ -862,11 +902,7 @@
     if (type === 'Fungible' || type === 'ReFungible') {
       balanceBefore = await getBalance(api, collectionId, to, tokenId);
     }
-    const transferFromTx = api.tx.unique.transferFrom(normalizeAccountId(accountFrom), to, collectionId, tokenId, value);
-    const events = await submitTransactionAsync(accountApproved, transferFromTx);
-    const result = getGenericResult(events);
-    // tslint:disable-next-line:no-unused-expression
-    expect(result.success).to.be.true;
+    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);
     }
@@ -1071,6 +1107,20 @@
 }
 
 export async function
+transfer(
+  api: ApiPromise,
+  collectionId: number,
+  tokenId: number,
+  sender: IKeyringPair,
+  recipient: IKeyringPair | CrossAccountId,
+  value: number | bigint,
+) : Promise<boolean> {
+  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,
@@ -1084,13 +1134,14 @@
     const to = normalizeAccountId(recipient);
 
     let balanceBefore = 0n;
-    if (type === 'Fungible') {
+    if (type === 'Fungible' || type === 'ReFungible') {
       balanceBefore = await getBalance(api, collectionId, to, tokenId);
     }
-    const transferTx = api.tx.unique.transfer(to, collectionId, tokenId, value);
-    const events = await executeTransaction(api, sender, transferTx);
 
+    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));
@@ -1100,7 +1151,7 @@
     if (type === 'NFT') {
       expect(await getTokenOwner(api, collectionId, tokenId)).to.be.deep.equal(to);
     }
-    if (type === 'Fungible') {
+    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));
@@ -1108,9 +1159,6 @@
         expect(balanceAfter).to.be.equal(balanceBefore);
       }
     }
-    if (type === 'ReFungible') {
-      expect(await getBalance(api, collectionId, to, tokenId) >= value).to.be.true;
-    }
   });
 }
 
@@ -1151,7 +1199,7 @@
 export async function getBalance(
   api: ApiPromise,
   collectionId: number,
-  owner: string | CrossAccountId,
+  owner: string | CrossAccountId | IKeyringPair,
   token: number,
 ): Promise<bigint> {
   return (await api.rpc.unique.balance(collectionId, normalizeAccountId(owner), token)).toBigInt();
@@ -1226,6 +1274,16 @@
   });
 }
 
+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);
@@ -1359,6 +1417,14 @@
   return newItemId;
 }
 
+export async function createRefungibleToken(api: ApiPromise, sender: IKeyringPair, collectionId: number, amount: bigint, owner: CrossAccountId | IKeyringPair | string = sender.address) : Promise<CreateItemResult> {
+  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);