difftreelog
test(sub/nesting) children checking + orderliness
in: master
6 files changed
tests/package.jsondiffbeforeafterboth--- a/tests/package.json
+++ b/tests/package.json
@@ -39,12 +39,14 @@
"testParallelFull": "yarn testParallel && yarn testSequential",
"testParallel": "yarn _testParallel './src/**/*.test.ts'",
"testSequential": "yarn _test './src/**/*.seqtest.ts'",
- "testStructure": "yarn setup && yarn _test ./**/nesting/*.*test.ts",
- "testEth": "yarn setup && yarn _test './**/eth/**/*.*test.ts'",
- "testEthNesting": "yarn setup && yarn _test './**/eth/nesting/**/*.*test.ts'",
- "testEthFractionalizer": "yarn setup && yarn _test './**/eth/fractionalizer/**/*.*test.ts'",
- "testEthMarketplace": "yarn setup && yarn _test './**/eth/marketplace/**/*.*test.ts'",
- "testEvent": "yarn setup && yarn _test ./src/check-event/*.*test.ts",
+ "testStructure": "yarn _test ./**/nesting/*.*test.ts",
+ "testEth": "yarn _test './**/eth/**/*.*test.ts'",
+ "testEthNesting": "yarn _test './**/eth/nesting/**/*.*test.ts'",
+ "testEthFractionalizer": "yarn _test './**/eth/fractionalizer/**/*.*test.ts'",
+ "testEthMarketplace": "yarn _test './**/eth/marketplace/**/*.*test.ts'",
+ "testSub": "yarn _test './**/sub/**/*.*test.ts'",
+ "testSubNesting": "yarn _test './**/sub/nesting/**/*.*test.ts'",
+ "testEvent": "yarn _test ./src/check-event/*.*test.ts",
"testEthPayable": "yarn _test './**/eth/payable.test.ts'",
"testEvmCoder": "yarn _test './**/eth/evmCoder.test.ts'",
"testNesting": "yarn _test ./**/nest.test.ts",
tests/src/sub/nesting/admin.test.tsdiffbeforeafterboth--- a/tests/src/sub/nesting/admin.test.ts
+++ b/tests/src/sub/nesting/admin.test.ts
@@ -17,7 +17,7 @@
import {IKeyringPair} from '@polkadot/types/types';
import {expect, itSub, usingPlaygrounds} from '../../util';
-describe('Collection admin', () => {
+describe('Nesting by collection admin', () => {
let alice: IKeyringPair;
let bob: IKeyringPair;
let charlie: IKeyringPair;
@@ -84,4 +84,3 @@
expect(await newToken.getOwner()).to.be.deep.equal(targetToken.nestingAccount().toLowerCase());
});
});
-
tests/src/sub/nesting/common.test.tsdiffbeforeafterboth--- a/tests/src/sub/nesting/common.test.ts
+++ b/tests/src/sub/nesting/common.test.ts
@@ -21,130 +21,143 @@
let alice: IKeyringPair;
let bob: IKeyringPair;
-before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+describe('Common nesting tests', () => {
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);
+ });
});
-});
-[
- {mode: 'nft' as const, restrictedMode: true, requiredPallets: []},
- {mode: 'nft' as const, restrictedMode: false, requiredPallets: []},
- {mode: 'rft' as const, restrictedMode: true, requiredPallets: [Pallets.ReFungible]},
- {mode: 'rft' as const, restrictedMode: false, requiredPallets: [Pallets.ReFungible]},
-].map(testCase => {
- itSub.ifWithPallets(`Token owner can nest ${testCase.mode.toUpperCase()} in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, testCase.requiredPallets, async ({helper}) => {
- // Only NFT can be target for nesting in
- const targetNFTCollection = await helper.nft.mintCollection(alice);
- const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+ [
+ {mode: 'nft' as const, restrictedMode: true, requiredPallets: []},
+ {mode: 'nft' as const, restrictedMode: false, requiredPallets: []},
+ {mode: 'rft' as const, restrictedMode: true, requiredPallets: [Pallets.ReFungible]},
+ {mode: 'rft' as const, restrictedMode: false, requiredPallets: [Pallets.ReFungible]},
+ ].map(testCase => {
+ itSub.ifWithPallets(`Token owner can nest ${testCase.mode.toUpperCase()} in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, testCase.requiredPallets, async ({helper}) => {
+ // Only NFT can be target for nesting in
+ const targetNFTCollection = await helper.nft.mintCollection(alice);
+ const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
- const collectionForNesting = await helper[testCase.mode].mintCollection(bob);
- // permissions should be set:
- await targetNFTCollection.setPermissions(alice, {
- nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
- });
+ const collectionForNesting = await helper[testCase.mode].mintCollection(bob);
+ // permissions should be set:
+ await targetNFTCollection.setPermissions(alice, {
+ nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
+ });
- // 1. Bob can immediately create nested token:
- const nestedToken1 = testCase.mode === 'nft'
- ? await (collectionForNesting as UniqueNFTCollection).mintToken(bob, targetTokenBob.nestingAccount())
- : await (collectionForNesting as UniqueRFTCollection).mintToken(bob, 10n, targetTokenBob.nestingAccount());
- expect(await nestedToken1.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
- expect(await nestedToken1.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());
+ // 1. Bob can immediately create nested token:
+ const nestedToken1 = testCase.mode === 'nft'
+ ? await (collectionForNesting as UniqueNFTCollection).mintToken(bob, targetTokenBob.nestingAccount())
+ : await (collectionForNesting as UniqueRFTCollection).mintToken(bob, 10n, targetTokenBob.nestingAccount());
+ expect(await nestedToken1.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
+ expect(await nestedToken1.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());
- // 2. Bob can mint and nest token:
- const nestedToken2 = await collectionForNesting.mintToken(bob);
- await nestedToken2.nest(bob, targetTokenBob);
- expect(await nestedToken2.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
- expect(await nestedToken2.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());
+ // 2. Bob can mint and nest token:
+ const nestedToken2 = await collectionForNesting.mintToken(bob);
+ await nestedToken2.nest(bob, targetTokenBob);
+ expect(await nestedToken2.getTopmostOwner()).to.be.deep.equal({Substrate: bob.address});
+ expect(await nestedToken2.getOwner()).to.be.deep.equal(targetTokenBob.nestingAccount().toLowerCase());
+ });
});
-});
-[
- {restrictedMode: true},
- {restrictedMode: false},
-].map(testCase => {
- itSub(`Token owner can nest FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
- // Only NFT allows nesting, permissions should be set:
- const targetNFTCollection = await helper.nft.mintCollection(alice);
- const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+ [
+ {restrictedMode: true},
+ {restrictedMode: false},
+ ].map(testCase => {
+ itSub(`Token owner can nest FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
+ // Only NFT allows nesting, permissions should be set:
+ const targetNFTCollection = await helper.nft.mintCollection(alice);
+ const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
- const collectionForNesting = await helper.ft.mintCollection(bob);
- // permissions should be set:
- await targetNFTCollection.setPermissions(alice, {
- nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
- });
+ const collectionForNesting = await helper.ft.mintCollection(bob);
+ // permissions should be set:
+ await targetNFTCollection.setPermissions(alice, {
+ nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
+ });
- // 1. Alice can immediately create nested tokens:
- await collectionForNesting.mint(bob, 100n, targetTokenBob.nestingAccount());
- expect(await collectionForNesting.getTop10Owners()).deep.eq([targetTokenBob.nestingAccount().toLowerCase()]);
- expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(100n);
+ // 1. Alice can immediately create nested tokens:
+ await collectionForNesting.mint(bob, 100n, targetTokenBob.nestingAccount());
+ expect(await collectionForNesting.getTop10Owners()).deep.eq([targetTokenBob.nestingAccount().toLowerCase()]);
+ expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(100n);
- // 2. Alice can mint and nest token:
- await collectionForNesting.mint(bob, 100n);
- await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
- expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(150n);
+ // 2. Alice can mint and nest token:
+ await collectionForNesting.mint(bob, 100n);
+ await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
+ expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(150n);
+ expect(await targetTokenBob.getChildren()).to.be.deep.equal([{collectionId: collectionForNesting.collectionId, tokenId: 0}]);
+ });
});
-});
-[
- {restrictedMode: true},
- {restrictedMode: false},
-].map(testCase => {
- itSub(`Token owner can nest Native FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
- // Only NFT allows nesting, permissions should be set:
- const targetNFTCollection = await helper.nft.mintCollection(alice);
- const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+ [
+ {restrictedMode: true},
+ {restrictedMode: false},
+ ].map(testCase => {
+ itSub(`Token owner can nest Native FT in NFT if "tokenOwner" permission set ${testCase.restrictedMode ? 'in restricted mode': ''}`, async ({helper}) => {
+ // Only NFT allows nesting, permissions should be set:
+ const targetNFTCollection = await helper.nft.mintCollection(alice);
+ const targetTokenBob = await targetNFTCollection.mintToken(alice, {Substrate: bob.address});
+ expect(await targetTokenBob.getChildren()).to.be.empty;
- const collectionForNesting = helper.ft.getCollectionObject(0);
- // permissions should be set:
- await targetNFTCollection.setPermissions(alice, {
- nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
+ const collectionForNesting = helper.ft.getCollectionObject(0);
+ // permissions should be set:
+ await targetNFTCollection.setPermissions(alice, {
+ nesting: {tokenOwner: true, restricted: testCase.restrictedMode ? [collectionForNesting.collectionId] : null},
+ });
+
+ // Bob can nest Native FT into their NFT:
+ await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
+ expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(50n);
+ expect(await targetTokenBob.getChildren()).to.be.deep.equal([{collectionId: 0, tokenId: 0}]);
});
-
- // Bob can nest Native FT into their NFT:
- await collectionForNesting.transfer(bob, targetTokenBob.nestingAccount(), 50n);
- expect(await collectionForNesting.getBalance(targetTokenBob.nestingAccount())).eq(50n);
});
-});
-itSub.ifWithPallets('Owner can unnest tokens using transferFrom', [Pallets.ReFungible], async ({helper}) => {
- const collectionToNest = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const tokenA = await collectionToNest.mintToken(alice);
- const tokenB = await collectionToNest.mintToken(alice);
+ itSub.ifWithPallets('Owner can unnest tokens using transferFrom', [Pallets.ReFungible], async ({helper}) => {
+ const collectionToNest = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const tokenA = await collectionToNest.mintToken(alice);
+ const tokenB = await collectionToNest.mintToken(alice);
- // Create a nested token
- const nftCollectionToBeNested = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const rftCollectionToBeNested = await helper.rft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const ftCollectionToBeNested = await helper.ft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
- const nativeFtCollectionToBeNested = helper.ft.getCollectionObject(0);
+ // Create a nested token
+ const nftCollectionToBeNested = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const rftCollectionToBeNested = await helper.rft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const ftCollectionToBeNested = await helper.ft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
+ const nativeFtCollectionToBeNested = helper.ft.getCollectionObject(0);
- const nestedNFT = await nftCollectionToBeNested.mintToken(alice, tokenA.nestingAccount());
- const nestedRFT = await rftCollectionToBeNested.mintToken(alice, 100n, tokenA.nestingAccount());
- const _nestedFT = await ftCollectionToBeNested.mint(alice, 100n, tokenA.nestingAccount());
- await nativeFtCollectionToBeNested.transfer(alice, tokenA.nestingAccount(), 100n);
- expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());
- expect(await nestedRFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());
- expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
- expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
+ const nestedNFT = await nftCollectionToBeNested.mintToken(alice, tokenA.nestingAccount());
+ const nestedRFT = await rftCollectionToBeNested.mintToken(alice, 100n, tokenA.nestingAccount());
+ const _nestedFT = await ftCollectionToBeNested.mint(alice, 100n, tokenA.nestingAccount());
+ await nativeFtCollectionToBeNested.transfer(alice, tokenA.nestingAccount(), 100n);
+ expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());
+ expect(await nestedRFT.getOwner()).to.be.deep.equal(tokenA.nestingAccount().toLowerCase());
+ expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
+ expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(100n);
- // Transfer the nested token to another token
- await nestedNFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount());
- await nestedRFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
- await ftCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
- await nativeFtCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
+ expect(await tokenA.getChildren()).to.be.length(4);
+ expect(await tokenB.getChildren()).to.be.length(0);
- expect(await nestedNFT.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
- expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenB.nestingAccount().toLowerCase());
+ // Transfer the nested token to another token
+ await nestedNFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount());
+ await nestedRFT.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
+ await ftCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
+ await nativeFtCollectionToBeNested.transferFrom(alice, tokenA.nestingAccount(), tokenB.nestingAccount(), 25n);
- expect(await nestedRFT.getBalance(tokenB.nestingAccount())).to.equal(25n);
- expect(await nestedRFT.getBalance(tokenA.nestingAccount())).to.equal(75n);
+ expect(await nestedNFT.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});
+ expect(await nestedNFT.getOwner()).to.be.deep.equal(tokenB.nestingAccount().toLowerCase());
+
+ expect(await nestedRFT.getBalance(tokenB.nestingAccount())).to.equal(25n);
+ expect(await nestedRFT.getBalance(tokenA.nestingAccount())).to.equal(75n);
+
+ expect(await ftCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
+ expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
- expect(await ftCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
- expect(await ftCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
+ expect(await nativeFtCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
+ expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
- expect(await nativeFtCollectionToBeNested.getBalance(tokenB.nestingAccount())).to.equal(25n);
- expect(await nativeFtCollectionToBeNested.getBalance(tokenA.nestingAccount())).to.equal(75n);
+ // RFT, FT, and native FT
+ expect(await tokenA.getChildren()).to.be.length(3);
+ // NFT, RFT, FT, and native FT
+ expect(await tokenB.getChildren()).to.be.length(4);
+ });
});
tests/src/sub/nesting/e2e.test.tsdiffbeforeafterboth--- a/tests/src/sub/nesting/e2e.test.ts
+++ b/tests/src/sub/nesting/e2e.test.ts
@@ -32,7 +32,7 @@
const collectionA = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});
const collectionB = await helper.ft.mintCollection(alice);
const collectionC = await helper.rft.mintCollection(alice);
- const collectionD = helper.ft.getCollectionObject(0);
+ const collectionNative = helper.ft.getCollectionObject(0);
const targetToken = await collectionA.mintToken(alice);
expect((await targetToken.getChildren()).length).to.be.equal(0, 'Children length check at creation');
@@ -75,12 +75,12 @@
]).and.has.length(3);
// Nest native fungible token into another collection
- await collectionD.transfer(alice, targetToken.nestingAccount(), 2n);
+ await collectionNative.transfer(alice, targetToken.nestingAccount(), 2n);
expect(await targetToken.getChildren()).to.have.deep.members([
{tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
{tokenId: 0, collectionId: collectionB.collectionId},
{tokenId: tokenC.tokenId, collectionId: collectionC.collectionId},
- {tokenId: 0, collectionId: collectionD.collectionId},
+ {tokenId: 0, collectionId: collectionNative.collectionId},
]).and.has.length(4);
// Burn all nested pieces
@@ -88,7 +88,7 @@
expect(await targetToken.getChildren()).to.have.deep.members([
{tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
{tokenId: 0, collectionId: collectionB.collectionId},
- {tokenId: 0, collectionId: collectionD.collectionId},
+ {tokenId: 0, collectionId: collectionNative.collectionId},
])
.and.has.length(3);
@@ -97,7 +97,7 @@
expect(await targetToken.getChildren()).to.be.have.deep.members([
{tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
{tokenId: 0, collectionId: collectionB.collectionId},
- {tokenId: 0, collectionId: collectionD.collectionId},
+ {tokenId: 0, collectionId: collectionNative.collectionId},
]).and.has.length(3);
// Nested token also has children now:
expect(await tokenA.getChildren()).to.have.deep.members([
@@ -108,7 +108,7 @@
await collectionB.transferFrom(alice, targetToken.nestingAccount(), tokenA.nestingAccount(), 1n);
expect(await targetToken.getChildren()).to.have.deep.members([
{tokenId: tokenA.tokenId, collectionId: collectionA.collectionId},
- {tokenId: 0, collectionId: collectionD.collectionId},
+ {tokenId: 0, collectionId: collectionNative.collectionId},
]).and.has.length(2);
expect(await tokenA.getChildren()).to.have.deep.members([
{tokenId: 0, collectionId: collectionB.collectionId},
tests/src/sub/nesting/nesting.negative.test.tsdiffbeforeafterboth1// 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 {IKeyringPair} from '@polkadot/types/types';18import {expect, itSub, Pallets, usingPlaygrounds} from '../../util';19import {UniqueFTCollection, UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection, UniqueRFToken} from '../../util/playgrounds/unique';20import {itEth} from '../../eth/util';2122let alice: IKeyringPair;23let bob: IKeyringPair;24let charlie: IKeyringPair;2526before(async () => {27 await usingPlaygrounds(async (helper, privateKey) => {28 const donor = await privateKey({url: import.meta.url});29 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);30 });31});3233[34 {mode: 'nft' as const, requiredPallets: []},35 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},36].map(testCase => {37 itSub.ifWithPallets(`Owner cannot nest ${testCase.mode.toUpperCase()} if nesting is disabled`, testCase.requiredPallets, async ({helper}) => {38 // Create default collection, permissions are not set:39 const aliceNFTCollection = await helper.nft.mintCollection(alice);40 const targetToken = await aliceNFTCollection.mintToken(alice);4142 const collectionForNesting = await helper[testCase.mode].mintCollection(alice);4344 // 1. Alice cannot create immediately nested tokens:45 const nestingTx = testCase.mode === 'nft'46 ? (collectionForNesting as UniqueNFTCollection).mintToken(alice, targetToken.nestingAccount())47 : (collectionForNesting as UniqueRFTCollection).mintToken(alice, 10n, targetToken.nestingAccount());48 await expect(nestingTx).to.be.rejectedWith('common.UserIsNotAllowedToNest');4950 // 2. Alice cannot mint and nest token:51 const nestedToken2 = await collectionForNesting.mintToken(alice);52 await expect(nestedToken2.nest(alice, targetToken)).to.be.rejectedWith('common.UserIsNotAllowedToNest');53 });54});5556[57 {mode: 'ft'},58 {mode: 'nativeFt'},59].map(testCase => {60 itSub(`Owner cannot nest [${testCase.mode}] if nesting is disabled`, async ({helper}) => {61 // Create default collection, permissions are not set:62 const aliceNFTCollection = await helper.nft.mintCollection(alice);63 const targetToken = await aliceNFTCollection.mintToken(alice);6465 const collectionForNesting = testCase.mode === 'ft' ? await helper.ft.mintCollection(alice) : helper.ft.getCollectionObject(0);6667 // Alice cannot create immediately nested tokens:68 await expect(testCase.mode === 'ft'69 ? collectionForNesting.mint(alice, 100n, targetToken.nestingAccount())70 : collectionForNesting.transfer(alice, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');7172 // Alice can't mint and nest tokens:73 if (testCase.mode === 'ft') {74 await collectionForNesting.mint(alice, 100n);75 }76 await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');77 });78});7980[81 {mode: 'nft' as const},82 {mode: 'rft' as const},83 {mode: 'ft' as const},84 {mode: 'native ft' as const},85].map(testCase => {86 itSub(`Non-owner and non-admin cannot nest ${testCase.mode.toUpperCase()} in someone else's tokens`, async ({helper}) => {87 const targetCollection = await helper.nft.mintCollection(alice, {permissions:88 {nesting: {tokenOwner: true, collectionAdmin: true}},89 });90 const targetToken = await targetCollection.mintToken(alice);9192 const nestedCollectionBob = await (93 testCase.mode === 'native ft'94 ? helper.ft.getCollectionObject(0)95 : helper[testCase.mode].mintCollection(bob)96 );9798 let nestedTokenBob: UniqueNFToken | UniqueRFToken;99 switch (testCase.mode) {100 case 'nft': nestedTokenBob = await (nestedCollectionBob as UniqueNFTCollection).mintToken(bob); break;101 case 'rft': nestedTokenBob = await (nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n); break;102 case 'ft': await (nestedCollectionBob as UniqueFTCollection).mint(bob, 100n); break;103 case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n)).to.be.rejectedWith('common.UnsupportedOperation'); break;104 }105106 // Bob non-owner of targetToken and non admin of targetCollection, so107 // 1. cannot mint nested token:108 switch (testCase.mode) {109 case 'nft': await expect((nestedCollectionBob as UniqueNFTCollection).mintToken(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;110 case 'rft': await expect((nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;111 case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;112 case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UnsupportedOperation'); break;113 }114115 // 2. cannot nest existing token:116 switch (testCase.mode) {117 case 'nft':118 case 'rft': await expect(nestedTokenBob!.transfer(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;119 case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;120 case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;121 }122 });123});124125[126 {mode: 'nft' as const, nesting: {tokenOwner: true, collectionAdmin: false}},127 {mode: 'nft' as const, nesting: {tokenOwner: false, collectionAdmin: true}},128].map(testCase => {129 itSub(`${testCase.nesting.tokenOwner'Admin''Token owner'} cannot nest when only ${testCase.nesting.tokenOwner'tokenOwner''collectionAdmin'} is allowed`, async ({helper}) => {130 // Create collection with tokenOwner or create collection with collectionAdmin permission:131 const targetCollection = await helper.nft.mintCollection(alice, {permissions: {nesting: testCase.nesting}});132 const targetTokenCharlie = await targetCollection.mintToken(alice, {Substrate: charlie.address});133 await targetCollection.addAdmin(alice, {Substrate: bob.address});134135 const nestedCollectionCharlie = await helper[testCase.mode].mintCollection(charlie);136 const nestedCollectionBob = await helper[testCase.mode].mintCollection(bob);137 // if nesting permissions restricted for token owner – minter is bob (admin),138 // if collectionAdmin – charlie (owner)139 testCase.nesting.tokenOwner140 ? await expect(nestedCollectionBob.mintToken(bob, targetTokenCharlie.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/)141 : await expect(nestedCollectionCharlie.mintToken(charlie, targetTokenCharlie.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);142 });143});144145itSub.ifWithPallets('Cannot nest in non existing token', [Pallets.ReFungible], async ({helper}) => {146 const collection = await helper.nft.mintCollection(alice);147 // To avoid UserIsNotAllowedToNest error148 await helper.collection.setPermissions(alice, collection.collectionId, {nesting: {collectionAdmin: true}});149150 // The list of non-existing tokens:151 const tokenFromNonExistingCollection = helper.nft.getTokenObject(9999999, 1);152 const tokenBurnt = await collection.mintToken(alice);153 await tokenBurnt.burn(alice);154 const tokenNotMintedYet = helper.nft.getTokenObject(collection.collectionId, 2);155156 // The list of collections to nest tokens from:157 const nftCollectionForNesting = await helper.nft.mintCollection(alice);158 const rftCollectionForNesting = await helper.rft.mintCollection(alice);159 const ftCollectionForNesting = await helper.ft.mintCollection(alice);160 const nativeFtCollectionForNesting = helper.ft.getCollectionObject(0);161162 const testCases = [163 {token: tokenFromNonExistingCollection, error: 'CollectionNotFound'},164 {token: tokenBurnt, error: 'TokenNotFound'},165 {token: tokenNotMintedYet, error: 'TokenNotFound'},166 ];167168 for(const testCase of testCases) {169 // 1. Alice cannot create nested token to non-existing token170 await expect(nftCollectionForNesting.mintToken(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);171 await expect(rftCollectionForNesting.mintToken(alice, 10n, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);172 await expect(ftCollectionForNesting.mint(alice, 10n, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);173174 // 2. Alice cannot mint and nest token:175 const nft = await nftCollectionForNesting.mintToken(alice);176 const rft = await rftCollectionForNesting.mintToken(alice, 100n);177 const _ft = await ftCollectionForNesting.mint(alice, 100n);178 await expect(nft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);179 await expect(rft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);180 await expect(ftCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.rejectedWith(testCase.error);181 await expect(nativeFtCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.rejectedWith(testCase.error);182 }183});184185itEth.ifWithPallets('Cannot nest in collection address', [Pallets.ReFungible], async({helper}) => {186 const existingCollection = await helper.nft.mintCollection(alice);187 const existingCollectionAddress = helper.ethAddress.fromCollectionId(existingCollection.collectionId);188 const futureCollectionAddress = helper.ethAddress.fromCollectionId(99999999);189190 const nftCollectionForNesting = await helper.nft.mintCollection(alice);191192 // 1. Alice cannot create nested token to collection address193 await expect(nftCollectionForNesting.mintToken(alice, {Ethereum: existingCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');194 await expect(nftCollectionForNesting.mintToken(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');195196 // 2. Alice cannot mint and nest token to collection address:197 const nft = await nftCollectionForNesting.mintToken(alice);198 await expect(nft.transfer(alice, {Ethereum: existingCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');199 await expect(nft.transfer(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');200});201202itEth.ifWithPallets('Cannot nest in RFT or FT', [Pallets.ReFungible], async ({helper}) => {203 // Create default collection, permissions are not set:204 const rftCollection = await helper.rft.mintCollection(alice);205 const ftCollection = await helper.ft.mintCollection(alice);206 const nativeFtCollection = helper.ft.getCollectionObject(0);207208 const rftToken = await rftCollection.mintToken(alice);209 const _ftToken = await ftCollection.mint(alice, 100n);210211 const collectionForNesting = await helper.nft.mintCollection(alice);212213 // 1. Alice cannot create immediately nested tokens:214 await expect(collectionForNesting.mintToken(alice, rftToken.nestingAccount())).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');215 await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');216 await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.rejectedWith('common.UnsupportedOperation');217218 // 2. Alice cannot mint and nest token:219 const nestedToken2 = await collectionForNesting.mintToken(alice);220 await expect(nestedToken2.nest(alice, rftToken)).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');221 await expect(ftCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');222 await expect(nativeFtCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.rejectedWith('common.UnsupportedOperation');223});224225itSub('Cannot nest in restricted collection if collection is not in the list', async ({helper}) => {226 const {collectionId: allowedCollectionId} = await helper.nft.mintCollection(alice);227 const notAllowedCollectionNFT = await helper.nft.mintCollection(alice);228 const notAllowedCollectionRFT = await helper.rft.mintCollection(alice);229 const notAllowedCollectionFT = await helper.ft.mintCollection(alice);230 const notAllowedCollectionNativeFT = helper.ft.getCollectionObject(0);231232 // Collection restricted to allowedCollectionId233 const restrictedCollectionA = await helper.nft.mintCollection(alice, {permissions:234 {nesting: {tokenOwner: true, restricted: [allowedCollectionId]}},235 });236 // Create collection with restricted nesting -- even self is not allowed237 const restrictedCollectionB = await helper.nft.mintCollection(alice, {permissions:238 {nesting: {tokenOwner: true, restricted: []}},239 });240241 const targetTokenA = await restrictedCollectionA.mintToken(alice);242 const targetTokenB = await restrictedCollectionB.mintToken(alice);243244 // 1. Cannot mint in own collection after allowlisting the accounts:245 await expect(restrictedCollectionA.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);246 await expect(restrictedCollectionB.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);247248 // 2. Cannot mint from notAllowedCollection:249 await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);250 await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);251 await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);252 await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);253 await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);254 await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);255 await expect(notAllowedCollectionNativeFT.transfer(alice, targetTokenA.nestingAccount(), 100n)).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);256 await expect(notAllowedCollectionNativeFT.transfer(alice, targetTokenB.nestingAccount(), 100n)).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);257});258259itSub('Cannot create nesting chains greater than 5', async ({helper}) => {260 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});261 let token = await collection.mintToken(alice);262263 const maxNestingLevel = 5;264265 // Create a nested-token matryoshka266 for (let i = 0; i < maxNestingLevel; i++) {267 token = await collection.mintToken(alice, token.nestingAccount());268 }269270 // The nesting depth is limited by `maxNestingLevel`271 // 1. Cannot mint:272 await expect(collection.mintToken(alice, token.nestingAccount()))273 .to.be.rejectedWith(/structure\.DepthLimit/);274 // 2. Cannot transfer:275 const anotherToken = await collection.mintToken(alice);276 await expect(anotherToken.transfer(alice, token.nestingAccount()))277 .to.be.rejectedWith(/structure\.DepthLimit/);278 // 3. Cannot nest FT pieces:279 const ftCollection = await helper.ft.mintCollection(alice);280 await expect(ftCollection.mint(alice, 100n, token.nestingAccount()))281 .to.be.rejectedWith(/structure\.DepthLimit/);282283 expect(await token.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});284 expect(await token.getChildren()).to.has.length(0);285});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 {IKeyringPair} from '@polkadot/types/types';18import {expect, itSub, Pallets, usingPlaygrounds} from '../../util';19import {UniqueFTCollection, UniqueNFTCollection, UniqueNFToken, UniqueRFTCollection, UniqueRFToken} from '../../util/playgrounds/unique';20import {itEth} from '../../eth/util';2122let alice: IKeyringPair;23let bob: IKeyringPair;24let charlie: IKeyringPair;2526describe('Negative Test: Nesting', () => {27 before(async () => {28 await usingPlaygrounds(async (helper, privateKey) => {29 const donor = await privateKey({url: import.meta.url});30 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);31 });32 });3334 [35 {mode: 'nft' as const, requiredPallets: []},36 {mode: 'rft' as const, requiredPallets: [Pallets.ReFungible]},37 ].map(testCase => {38 itSub.ifWithPallets(`Owner cannot nest ${testCase.mode.toUpperCase()} if nesting is disabled`, testCase.requiredPallets, async ({helper}) => {39 // Create default collection, permissions are not set:40 const aliceNFTCollection = await helper.nft.mintCollection(alice);41 const targetToken = await aliceNFTCollection.mintToken(alice);4243 const collectionForNesting = await helper[testCase.mode].mintCollection(alice);4445 // 1. Alice cannot create immediately nested tokens:46 const nestingTx = testCase.mode === 'nft'47 ? (collectionForNesting as UniqueNFTCollection).mintToken(alice, targetToken.nestingAccount())48 : (collectionForNesting as UniqueRFTCollection).mintToken(alice, 10n, targetToken.nestingAccount());49 await expect(nestingTx).to.be.rejectedWith('common.UserIsNotAllowedToNest');5051 // 2. Alice cannot mint and nest token:52 const nestedToken2 = await collectionForNesting.mintToken(alice);53 await expect(nestedToken2.nest(alice, targetToken)).to.be.rejectedWith('common.UserIsNotAllowedToNest');54 });55 });5657 [58 {mode: 'ft'},59 {mode: 'nativeFt'},60 ].map(testCase => {61 itSub(`Owner cannot nest [${testCase.mode}] if nesting is disabled`, async ({helper}) => {62 // Create default collection, permissions are not set:63 const aliceNFTCollection = await helper.nft.mintCollection(alice);64 const targetToken = await aliceNFTCollection.mintToken(alice);6566 const collectionForNesting = testCase.mode === 'ft' ? await helper.ft.mintCollection(alice) : helper.ft.getCollectionObject(0);6768 // Alice cannot create immediately nested tokens:69 await expect(testCase.mode === 'ft'70 ? collectionForNesting.mint(alice, 100n, targetToken.nestingAccount())71 : collectionForNesting.transfer(alice, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');7273 // Alice can't mint and nest tokens:74 if (testCase.mode === 'ft') {75 await collectionForNesting.mint(alice, 100n);76 }77 await expect(collectionForNesting.transfer(alice, targetToken.nestingAccount(), 50n)).to.be.rejectedWith('common.UserIsNotAllowedToNest');78 });79 });8081 [82 {mode: 'nft' as const},83 {mode: 'rft' as const},84 {mode: 'ft' as const},85 {mode: 'native ft' as const},86 ].map(testCase => {87 itSub(`Non-owner and non-admin cannot nest ${testCase.mode.toUpperCase()} in someone else's tokens`, async ({helper}) => {88 const targetCollection = await helper.nft.mintCollection(alice, {permissions:89 {nesting: {tokenOwner: true, collectionAdmin: true}},90 });91 const targetToken = await targetCollection.mintToken(alice);9293 const nestedCollectionBob = await (94 testCase.mode === 'native ft'95 ? helper.ft.getCollectionObject(0)96 : helper[testCase.mode].mintCollection(bob)97 );9899 let nestedTokenBob: UniqueNFToken | UniqueRFToken;100 switch (testCase.mode) {101 case 'nft': nestedTokenBob = await (nestedCollectionBob as UniqueNFTCollection).mintToken(bob); break;102 case 'rft': nestedTokenBob = await (nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n); break;103 case 'ft': await (nestedCollectionBob as UniqueFTCollection).mint(bob, 100n); break;104 case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n)).to.be.rejectedWith('common.UnsupportedOperation'); break;105 }106107 // Bob non-owner of targetToken and non admin of targetCollection, so108 // 1. cannot mint nested token:109 switch (testCase.mode) {110 case 'nft': await expect((nestedCollectionBob as UniqueNFTCollection).mintToken(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;111 case 'rft': await expect((nestedCollectionBob as UniqueRFTCollection).mintToken(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;112 case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;113 case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).mint(bob, 100n, targetToken.nestingAccount())).to.be.rejectedWith('common.UnsupportedOperation'); break;114 }115116 // 2. cannot nest existing token:117 switch (testCase.mode) {118 case 'nft':119 case 'rft': await expect(nestedTokenBob!.transfer(bob, targetToken.nestingAccount())).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;120 case 'ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;121 case 'native ft': await expect((nestedCollectionBob as UniqueFTCollection).transfer(bob, targetToken.nestingAccount(), 100n)).to.be.rejectedWith('common.UserIsNotAllowedToNest'); break;122 }123 });124 });125126 [127 {mode: 'nft' as const, nesting: {tokenOwner: true, collectionAdmin: false}},128 {mode: 'nft' as const, nesting: {tokenOwner: false, collectionAdmin: true}},129 ].map(testCase => {130 itSub(`${testCase.nesting.tokenOwner'Admin''Token owner'} cannot nest when only ${testCase.nesting.tokenOwner'tokenOwner''collectionAdmin'} is allowed`, async ({helper}) => {131 // Create collection with tokenOwner or create collection with collectionAdmin permission:132 const targetCollection = await helper.nft.mintCollection(alice, {permissions: {nesting: testCase.nesting}});133 const targetTokenCharlie = await targetCollection.mintToken(alice, {Substrate: charlie.address});134 await targetCollection.addAdmin(alice, {Substrate: bob.address});135136 const nestedCollectionCharlie = await helper[testCase.mode].mintCollection(charlie);137 const nestedCollectionBob = await helper[testCase.mode].mintCollection(bob);138 // if nesting permissions restricted for token owner – minter is bob (admin),139 // if collectionAdmin – charlie (owner)140 testCase.nesting.tokenOwner141 ? await expect(nestedCollectionBob.mintToken(bob, targetTokenCharlie.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/)142 : await expect(nestedCollectionCharlie.mintToken(charlie, targetTokenCharlie.nestingAccount())).to.be.rejectedWith(/common\.UserIsNotAllowedToNest/);143 });144 });145146 itSub.ifWithPallets('Cannot nest in non existing token', [Pallets.ReFungible], async ({helper}) => {147 const collection = await helper.nft.mintCollection(alice);148 // To avoid UserIsNotAllowedToNest error149 await helper.collection.setPermissions(alice, collection.collectionId, {nesting: {collectionAdmin: true}});150151 // The list of non-existing tokens:152 const tokenFromNonExistingCollection = helper.nft.getTokenObject(9999999, 1);153 const tokenBurnt = await collection.mintToken(alice);154 await tokenBurnt.burn(alice);155 const tokenNotMintedYet = helper.nft.getTokenObject(collection.collectionId, 2);156157 // The list of collections to nest tokens from:158 const nftCollectionForNesting = await helper.nft.mintCollection(alice);159 const rftCollectionForNesting = await helper.rft.mintCollection(alice);160 const ftCollectionForNesting = await helper.ft.mintCollection(alice);161 const nativeFtCollectionForNesting = helper.ft.getCollectionObject(0);162163 const testCases = [164 {token: tokenFromNonExistingCollection, error: 'CollectionNotFound'},165 {token: tokenBurnt, error: 'TokenNotFound'},166 {token: tokenNotMintedYet, error: 'TokenNotFound'},167 ];168169 for(const testCase of testCases) {170 // 1. Alice cannot create nested token to non-existing token171 await expect(nftCollectionForNesting.mintToken(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);172 await expect(rftCollectionForNesting.mintToken(alice, 10n, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);173 await expect(ftCollectionForNesting.mint(alice, 10n, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);174175 // 2. Alice cannot mint and nest token:176 const nft = await nftCollectionForNesting.mintToken(alice);177 const rft = await rftCollectionForNesting.mintToken(alice, 100n);178 const _ft = await ftCollectionForNesting.mint(alice, 100n);179 await expect(nft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);180 await expect(rft.transfer(alice, testCase.token.nestingAccount())).to.be.rejectedWith(testCase.error);181 await expect(ftCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.rejectedWith(testCase.error);182 await expect(nativeFtCollectionForNesting.transfer(alice, testCase.token.nestingAccount(), 50n)).to.be.rejectedWith(testCase.error);183 }184 });185186 itEth.ifWithPallets('Cannot nest in collection address', [Pallets.ReFungible], async({helper}) => {187 const existingCollection = await helper.nft.mintCollection(alice);188 const existingCollectionAddress = helper.ethAddress.fromCollectionId(existingCollection.collectionId);189 const futureCollectionAddress = helper.ethAddress.fromCollectionId(99999999);190191 const nftCollectionForNesting = await helper.nft.mintCollection(alice);192193 // 1. Alice cannot create nested token to collection address194 await expect(nftCollectionForNesting.mintToken(alice, {Ethereum: existingCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');195 await expect(nftCollectionForNesting.mintToken(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');196197 // 2. Alice cannot mint and nest token to collection address:198 const nft = await nftCollectionForNesting.mintToken(alice);199 await expect(nft.transfer(alice, {Ethereum: existingCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');200 await expect(nft.transfer(alice, {Ethereum: futureCollectionAddress})).to.be.rejectedWith('CantNestTokenUnderCollection');201 });202203 itEth.ifWithPallets('Cannot nest in RFT or FT', [Pallets.ReFungible], async ({helper}) => {204 // Create default collection, permissions are not set:205 const rftCollection = await helper.rft.mintCollection(alice);206 const ftCollection = await helper.ft.mintCollection(alice);207 const nativeFtCollection = helper.ft.getCollectionObject(0);208209 const rftToken = await rftCollection.mintToken(alice);210 const _ftToken = await ftCollection.mint(alice, 100n);211212 const collectionForNesting = await helper.nft.mintCollection(alice);213214 // 1. Alice cannot create immediately nested tokens:215 await expect(collectionForNesting.mintToken(alice, rftToken.nestingAccount())).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');216 await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');217 await expect(collectionForNesting.mintToken(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.rejectedWith('common.UnsupportedOperation');218219 // 2. Alice cannot mint and nest token:220 const nestedToken2 = await collectionForNesting.mintToken(alice);221 await expect(nestedToken2.nest(alice, rftToken)).to.be.rejectedWith('refungible.RefungibleDisallowsNesting');222 await expect(ftCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(ftCollection.collectionId, 0)})).to.be.rejectedWith('fungible.FungibleDisallowsNesting');223 await expect(nativeFtCollection.transfer(alice, {Ethereum: helper.ethAddress.fromTokenId(nativeFtCollection.collectionId, 0)})).to.be.rejectedWith('common.UnsupportedOperation');224 });225226 itSub('Cannot nest in restricted collection if collection is not in the list', async ({helper}) => {227 const {collectionId: allowedCollectionId} = await helper.nft.mintCollection(alice);228 const notAllowedCollectionNFT = await helper.nft.mintCollection(alice);229 const notAllowedCollectionRFT = await helper.rft.mintCollection(alice);230 const notAllowedCollectionFT = await helper.ft.mintCollection(alice);231 const notAllowedCollectionNativeFT = helper.ft.getCollectionObject(0);232233 // Collection restricted to allowedCollectionId234 const restrictedCollectionA = await helper.nft.mintCollection(alice, {permissions:235 {nesting: {tokenOwner: true, restricted: [allowedCollectionId]}},236 });237 // Create collection with restricted nesting -- even self is not allowed238 const restrictedCollectionB = await helper.nft.mintCollection(alice, {permissions:239 {nesting: {tokenOwner: true, restricted: []}},240 });241242 const targetTokenA = await restrictedCollectionA.mintToken(alice);243 const targetTokenB = await restrictedCollectionB.mintToken(alice);244245 // 1. Cannot mint in own collection after allowlisting the accounts:246 await expect(restrictedCollectionA.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);247 await expect(restrictedCollectionB.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);248249 // 2. Cannot mint from notAllowedCollection:250 await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);251 await expect(notAllowedCollectionNFT.mintToken(alice, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);252 await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);253 await expect(notAllowedCollectionRFT.mintToken(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);254 await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenA.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);255 await expect(notAllowedCollectionFT.mint(alice, 100n, targetTokenB.nestingAccount())).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);256 await expect(notAllowedCollectionNativeFT.transfer(alice, targetTokenA.nestingAccount(), 100n)).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);257 await expect(notAllowedCollectionNativeFT.transfer(alice, targetTokenB.nestingAccount(), 100n)).to.be.rejectedWith(/common\.SourceCollectionIsNotAllowedToNest/);258 });259260 itSub('Cannot create nesting chains greater than 5', async ({helper}) => {261 const collection = await helper.nft.mintCollection(alice, {permissions: {nesting: {tokenOwner: true}}});262 let token = await collection.mintToken(alice);263264 const maxNestingLevel = 5;265266 // Create a nested-token matryoshka267 for (let i = 0; i < maxNestingLevel; i++) {268 token = await collection.mintToken(alice, token.nestingAccount());269 }270271 // The nesting depth is limited by `maxNestingLevel`272 // 1. Cannot mint:273 await expect(collection.mintToken(alice, token.nestingAccount()))274 .to.be.rejectedWith(/structure\.DepthLimit/);275 // 2. Cannot transfer:276 const anotherToken = await collection.mintToken(alice);277 await expect(anotherToken.transfer(alice, token.nestingAccount()))278 .to.be.rejectedWith(/structure\.DepthLimit/);279 // 3. Cannot nest FT pieces:280 const ftCollection = await helper.ft.mintCollection(alice);281 await expect(ftCollection.mint(alice, 100n, token.nestingAccount()))282 .to.be.rejectedWith(/structure\.DepthLimit/);283284 expect(await token.getTopmostOwner()).to.be.deep.equal({Substrate: alice.address});285 expect(await token.getChildren()).to.has.length(0);286 });287});tests/src/sub/nesting/refungible.test.tsdiffbeforeafterboth--- a/tests/src/sub/nesting/refungible.test.ts
+++ b/tests/src/sub/nesting/refungible.test.ts
@@ -17,44 +17,45 @@
import {IKeyringPair} from '@polkadot/types/types';
import {expect, itSub, Pallets, usingPlaygrounds} from '../../util';
-// ReFungible specific nesting tests
-let alice: IKeyringPair;
+describe('ReFungible-specific nesting tests', () => {
+ let alice: IKeyringPair;
-before(async () => {
- await usingPlaygrounds(async (helper, privateKey) => {
- const donor = await privateKey({url: import.meta.url});
- [alice] = await helper.arrange.createAccounts([200n], donor);
+ before(async () => {
+ await usingPlaygrounds(async (helper, privateKey) => {
+ const donor = await privateKey({url: import.meta.url});
+ [alice] = await helper.arrange.createAccounts([200n], donor);
+ });
});
-});
-itSub.ifWithPallets('ReFungible: getTopmostOwner works correctly with Nesting', [Pallets.ReFungible], async({helper}) => {
- const collectionNFT = await helper.nft.mintCollection(alice, {
- permissions: {
- nesting: {
- tokenOwner: true,
+ itSub.ifWithPallets('ReFungible: getTopmostOwner works correctly with Nesting', [Pallets.ReFungible], async({helper}) => {
+ const collectionNFT = await helper.nft.mintCollection(alice, {
+ permissions: {
+ nesting: {
+ tokenOwner: true,
+ },
},
- },
- });
- const collectionRFT = await helper.rft.mintCollection(alice);
+ });
+ const collectionRFT = await helper.rft.mintCollection(alice);
- const nft = await collectionNFT.mintToken(alice, {Substrate: alice.address});
- const rft = await collectionRFT.mintToken(alice, 100n, {Substrate: alice.address});
+ const nft = await collectionNFT.mintToken(alice, {Substrate: alice.address});
+ const rft = await collectionRFT.mintToken(alice, 100n, {Substrate: alice.address});
- expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
+ expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
- await rft.transfer(alice, nft.nestingAccount(), 40n);
+ await rft.transfer(alice, nft.nestingAccount(), 40n);
- expect(await rft.getTopmostOwner()).deep.equal(null);
+ expect(await rft.getTopmostOwner()).deep.equal(null);
- await rft.transfer(alice, nft.nestingAccount(), 60n);
+ await rft.transfer(alice, nft.nestingAccount(), 60n);
- expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
+ expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
- await rft.transferFrom(alice, nft.nestingAccount(), {Substrate: alice.address}, 30n);
+ await rft.transferFrom(alice, nft.nestingAccount(), {Substrate: alice.address}, 30n);
- expect(await rft.getTopmostOwner()).deep.equal(null);
+ expect(await rft.getTopmostOwner()).deep.equal(null);
- await rft.transferFrom(alice, nft.nestingAccount(), {Substrate: alice.address}, 70n);
+ await rft.transferFrom(alice, nft.nestingAccount(), {Substrate: alice.address}, 70n);
- expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
+ expect(await rft.getTopmostOwner()).deep.equal({Substrate: alice.address});
+ });
});