difftreelog
test owner/admin unnest
in: master
2 files changed
tests/src/nesting/nest.test.tsdiffbeforeafterboth161617import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';18import {expect, itSub, Pallets, usingPlaygrounds} from '../util';18import {expect, itSub, Pallets, usingPlaygrounds} from '../util';19import {UniqueNFToken, UniqueRFToken} from '../util/playgrounds/unique';201921describe('Integration Test: Composite nesting tests', () => {20describe('Integration Test: Composite nesting tests', () => {22 let alice: IKeyringPair;21 let alice: IKeyringPair;139 before(async () => {138 before(async () => {140 await usingPlaygrounds(async (helper, privateKey) => {139 await usingPlaygrounds(async (helper, privateKey) => {141 const donor = await privateKey({filename: __filename});140 const donor = await privateKey({filename: __filename});142 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 20n, 20n], donor);141 [alice, bob, charlie] = await helper.arrange.createAccounts([50n, 10n, 10n], donor);143 });142 });144 });143 });145144337 expect(await newToken.getBalance(targetToken.nestingAccount())).to.be.equal(2n);336 expect(await newToken.getBalance(targetToken.nestingAccount())).to.be.equal(2n);338 });337 });339340 async function checkNestedRft({341 expectedBalance,342 childrenShouldPresent,343 nestedRft,344 targetNft,345 }: {346 expectedBalance: bigint,347 childrenShouldPresent: boolean,348 nestedRft: UniqueRFToken,349 targetNft: UniqueNFToken,350 }) {351 const balance = await nestedRft.getBalance(targetNft.nestingAccount());352 expect(balance).to.be.equal(expectedBalance);353354 const children = await targetNft.getChildren();355356 if (childrenShouldPresent) {357 expect(children[0]).to.be.deep.equal({358 collectionId: nestedRft.collectionId,359 tokenId: nestedRft.tokenId,360 });361 } else {362 expect(children.length).to.be.equal(0);363 }364 }365366 itSub.ifWithPallets('ReFungible: allows a collection owner to transfer nested token', [Pallets.ReFungible], async ({helper}) => {367 const collectionNFT = await helper.nft.mintCollection(alice);368 const collectionRFT = await helper.rft.mintCollection(alice, {369 limits: {370 ownerCanTransfer: true,371 },372 });373374 await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});375376 const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});377 const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});378379 await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);380 await checkNestedRft({381 expectedBalance: 5n,382 childrenShouldPresent: true,383 nestedRft,384 targetNft,385 });386387 await nestedRft.transferFrom(alice, targetNft.nestingAccount(), {Substrate: bob.address}, 2n);388 await checkNestedRft({389 expectedBalance: 3n,390 childrenShouldPresent: true,391 nestedRft,392 targetNft,393 });394 expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(2n);395396 await nestedRft.transferFrom(alice, targetNft.nestingAccount(), {Substrate: bob.address}, 3n);397 await checkNestedRft({398 expectedBalance: 0n,399 childrenShouldPresent: false,400 nestedRft,401 targetNft,402 });403 expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(5n);404 });405406 itSub.ifWithPallets('ReFungible: allows a collection admin to transfer nested token', [Pallets.ReFungible], async ({helper}) => {407 const collectionNFT = await helper.nft.mintCollection(alice);408 const collectionRFT = await helper.rft.mintCollection(alice, {409 limits: {410 ownerCanTransfer: true,411 },412 });413 await collectionRFT.addAdmin(alice, {Substrate: bob.address});414415 await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});416417 const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});418 const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});419420 await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);421 await checkNestedRft({422 expectedBalance: 5n,423 childrenShouldPresent: true,424 nestedRft,425 targetNft,426 });427428 await nestedRft.transferFrom(bob, targetNft.nestingAccount(), {Substrate: bob.address}, 2n);429 await checkNestedRft({430 expectedBalance: 3n,431 childrenShouldPresent: true,432 nestedRft,433 targetNft,434 });435 expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(2n);436437 await nestedRft.transferFrom(bob, targetNft.nestingAccount(), {Substrate: bob.address}, 3n);438 await checkNestedRft({439 expectedBalance: 0n,440 childrenShouldPresent: false,441 nestedRft,442 targetNft,443 });444 expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(5n);445 });446447 itSub.ifWithPallets('ReFungible: allows a collection owner to burn nested token', [Pallets.ReFungible], async ({helper}) => {448 const collectionNFT = await helper.nft.mintCollection(alice, {449 limits: {450 ownerCanTransfer: true,451 },452 });453 const collectionRFT = await helper.rft.mintCollection(alice, {454 limits: {455 ownerCanTransfer: true,456 },457 });458459 await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});460461 const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});462 const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});463464 await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);465 await checkNestedRft({466 expectedBalance: 5n,467 childrenShouldPresent: true,468 nestedRft,469 targetNft,470 });471472 await nestedRft.burnFrom(alice, targetNft.nestingAccount(), 2n);473 await checkNestedRft({474 expectedBalance: 3n,475 childrenShouldPresent: true,476 nestedRft,477 targetNft,478 });479480 await nestedRft.burnFrom(alice, targetNft.nestingAccount(), 3n);481 await checkNestedRft({482 expectedBalance: 0n,483 childrenShouldPresent: false,484 nestedRft,485 targetNft,486 });487488 // Check if we can burn target NFT when all nested RFTs are gone489 await targetNft.burnFrom(alice, {Substrate: charlie.address});490 });491492 itSub.ifWithPallets('ReFungible: allows a collection admin to burn nested token', [Pallets.ReFungible], async ({helper}) => {493 const collectionNFT = await helper.nft.mintCollection(alice, {494 limits: {495 ownerCanTransfer: true,496 },497 });498 const collectionRFT = await helper.rft.mintCollection(alice, {499 limits: {500 ownerCanTransfer: true,501 },502 });503 await collectionNFT.addAdmin(alice, {Substrate: bob.address});504 await collectionRFT.addAdmin(alice, {Substrate: bob.address});505506 await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});507508 const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});509 const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});510511 await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);512 await checkNestedRft({513 expectedBalance: 5n,514 childrenShouldPresent: true,515 nestedRft,516 targetNft,517 });518519 await nestedRft.burnFrom(bob, targetNft.nestingAccount(), 2n);520 await checkNestedRft({521 expectedBalance: 3n,522 childrenShouldPresent: true,523 nestedRft,524 targetNft,525 });526527 await nestedRft.burnFrom(bob, targetNft.nestingAccount(), 3n);528 await checkNestedRft({529 expectedBalance: 0n,530 childrenShouldPresent: false,531 nestedRft,532 targetNft,533 });534535 // Check if we can burn target NFT when all nested RFTs are gone536 await targetNft.burnFrom(bob, {Substrate: charlie.address});537 });538});338});539339540describe('Negative Test: Nesting', () => {340describe('Negative Test: Nesting', () => {tests/src/nesting/unnest.test.tsdiffbeforeafterboth--- a/tests/src/nesting/unnest.test.ts
+++ b/tests/src/nesting/unnest.test.ts
@@ -16,14 +16,17 @@
import {IKeyringPair} from '@polkadot/types/types';
import {expect, itSub, Pallets, usingPlaygrounds} from '../util';
+import {UniqueFTCollection, UniqueNFToken, UniqueRFToken} from '../util/playgrounds/unique';
describe('Integration Test: Unnesting', () => {
let alice: IKeyringPair;
+ let bob: IKeyringPair;
+ let charlie: IKeyringPair;
before(async () => {
await usingPlaygrounds(async (helper, privateKey) => {
const donor = await privateKey({filename: __filename});
- [alice] = await helper.arrange.createAccounts([50n], donor);
+ [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 50n, 50n], donor);
});
});
@@ -83,6 +86,188 @@
expect(await token.getBalance(targetToken.nestingAccount())).to.be.equal(0n);
expect(await targetToken.getChildren()).to.be.length(0);
});
+
+ async function checkNestedAmountState({
+ expectedBalance,
+ childrenShouldPresent,
+ nested,
+ targetNft,
+ }: {
+ expectedBalance: bigint,
+ childrenShouldPresent: boolean,
+ nested: UniqueFTCollection | UniqueRFToken,
+ targetNft: UniqueNFToken,
+ }) {
+ const balance = await nested.getBalance(targetNft.nestingAccount());
+ expect(balance).to.be.equal(expectedBalance);
+
+ const children = await targetNft.getChildren();
+
+ if (childrenShouldPresent) {
+ expect(children[0]).to.be.deep.equal({
+ collectionId: nested.collectionId,
+ tokenId: (nested instanceof UniqueFTCollection) ? 0 : nested.tokenId,
+ });
+ } else {
+ expect(children.length).to.be.equal(0);
+ }
+ }
+
+ function ownerOrAdminUnnestCases(modes: ('ft' | 'nft' | 'rft')[]): {
+ mode: 'ft' | 'nft' | 'rft',
+ sender: string,
+ op: 'transfer' | 'burn',
+ requiredPallets: Pallets[],
+ }[] {
+ const senders = ['owner', 'admin'];
+ const ops = ['transfer', 'burn'];
+
+ const cases = [];
+ for (const mode of modes) {
+ const requiredPallets = (mode === 'rft')
+ ? [Pallets.ReFungible]
+ : [];
+
+ for (const sender of senders) {
+ for (const op of ops) {
+ cases.push({
+ mode: mode as 'ft' | 'nft' | 'rft',
+ sender,
+ op: op as 'transfer' | 'burn',
+ requiredPallets,
+ });
+ }
+ }
+ }
+
+ return cases;
+ }
+
+ ownerOrAdminUnnestCases(['ft', 'rft']).map(testCase =>
+ itSub.ifWithPallets(`[${testCase.mode}]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, testCase.requiredPallets, async({helper}) => {
+ const owner = alice;
+ const admin = bob;
+
+ const unnester = (testCase.sender === 'owner')
+ ? owner
+ : admin;
+
+ const collectionNFT = await helper.nft.mintCollection(owner);
+ await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});
+
+ const collectionNested = await helper[testCase.mode as 'ft' | 'rft'].mintCollection(owner, {
+ limits: {
+ ownerCanTransfer: true,
+ },
+ });
+ await collectionNested.addAdmin(owner, {Substrate: admin.address});
+
+ const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});
+
+ let nested: UniqueFTCollection | UniqueRFToken;
+ const totalAmount = 5n;
+ const firstUnnestAmount = 2n;
+ const restUnnestAmount = totalAmount - firstUnnestAmount;
+
+ if (collectionNested instanceof UniqueFTCollection) {
+ await collectionNested.mint(owner, totalAmount, {Substrate: charlie.address});
+ nested = collectionNested;
+ } else {
+ nested = await collectionNested.mintToken(owner, totalAmount, {Substrate: charlie.address});
+ }
+
+ // transfer/burn `amount` of nested assets by `unnester`.
+ const doOperationAndCheck = async ({
+ amount,
+ shouldBeNestedAfterOp,
+ }: {
+ amount: bigint,
+ shouldBeNestedAfterOp: boolean,
+ }) => {
+ const nestedBalanceBeforeOp = await nested.getBalance(targetNft.nestingAccount());
+
+ if (testCase.op === 'transfer') {
+ const bobBalanceBeforeOp = await nested.getBalance({Substrate: bob.address});
+
+ await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address}, amount);
+ expect(await nested.getBalance({Substrate: bob.address})).to.be.equal(bobBalanceBeforeOp + amount);
+ } else {
+ if (nested instanceof UniqueFTCollection) {
+ await nested.burnTokensFrom(unnester, targetNft.nestingAccount(), amount);
+ } else {
+ await nested.burnFrom(unnester, targetNft.nestingAccount(), amount);
+ }
+ }
+
+ await checkNestedAmountState({
+ expectedBalance: nestedBalanceBeforeOp - amount,
+ childrenShouldPresent: shouldBeNestedAfterOp,
+ nested,
+ targetNft,
+ });
+ };
+
+ // Initial setup: nest (fungibles/rft parts).
+ // Check NFT's balance of nested assets and NFT's children.
+ await nested.transfer(charlie, targetNft.nestingAccount(), totalAmount);
+ await checkNestedAmountState({
+ expectedBalance: totalAmount,
+ childrenShouldPresent: true,
+ nested,
+ targetNft,
+ });
+
+ // Transfer/burn only a part of nested assets.
+ // Check that NFT's balance of the nested assets correctly decreased and NFT's children are not changed.
+ await doOperationAndCheck({
+ amount: firstUnnestAmount,
+ shouldBeNestedAfterOp: true,
+ });
+
+ // Transfer/burn all remaining nested assets.
+ // Check that NFT's balance of the nested assets is 0 and NFT has no more children.
+ await doOperationAndCheck({
+ amount: restUnnestAmount,
+ shouldBeNestedAfterOp: false,
+ });
+ }));
+
+ ownerOrAdminUnnestCases(['nft']).map(testCase =>
+ itSub(`[nft]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, async ({helper}) => {
+ const owner = alice;
+ const admin = bob;
+
+ const unnester = (testCase.sender === 'owner')
+ ? owner
+ : admin;
+
+ const collectionNFT = await helper.nft.mintCollection(owner);
+ await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});
+
+ const collectionNested = await helper.nft.mintCollection(owner, {
+ limits: {
+ ownerCanTransfer: true,
+ },
+ });
+ await collectionNested.addAdmin(owner, {Substrate: admin.address});
+
+ const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});
+ const nested = await collectionNested.mintToken(owner, {Substrate: charlie.address});
+
+ await nested.transfer(charlie, targetNft.nestingAccount());
+ expect(await targetNft.getChildren()).to.be.deep.equal([{
+ collectionId: nested.collectionId,
+ tokenId: nested.tokenId,
+ }]);
+
+ if (testCase.op === 'transfer') {
+ await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address});
+ } else {
+ await nested.burnFrom(unnester, targetNft.nestingAccount());
+ }
+
+ expect((await targetNft.getChildren()).length).to.be.equal(0);
+ }));
});
describe('Negative Test: Unnesting', () => {