git.delta.rocks / unique-network / refs/commits / c7ac6d04a86f

difftreelog

source

tests/src/approve.test.ts40.7 KiBsourcehistory
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 {CrossAccountId} from './util/playgrounds/unique';20212223[24  {method: 'approveToken', account: (account: IKeyringPair) => CrossAccountId.fromKeyring(account)},25  {method: 'approveTokenFromEth', account: (account: IKeyringPair) => CrossAccountId.fromKeyring(account).toEthereum()},26].map(testCase => {27  describe(`Integration Test ${testCase.method}(spender, collection_id, item_id, amount):`, () => {28    let alice: IKeyringPair;29    let bob: IKeyringPair;30    let charlie: IKeyringPair;3132    before(async () => {33      await usingPlaygrounds(async (helper, privateKey) => {34        const donor = await privateKey({url: import.meta.url});35        [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);36      });37    });3839    itSub('[nft] Execute the extrinsic and check approvedList', async ({helper}) => {40      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});41      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});42      await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});43      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;44    });4546    itSub('[fungible] Execute the extrinsic and check approvedList', async ({helper}) => {47      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);48      await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));49      const tokenId = await helper.ft.getLastTokenId(collectionId);50      await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});51      const amount = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));52      expect(amount).to.be.equal(1n);53    });5455    itSub.ifWithPallets('[refungible] Execute the extrinsic and check approvedList', [Pallets.ReFungible], async ({helper}) => {56      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});57      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});58      await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});59      const amount = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));60      expect(amount).to.be.equal(1n);61    });6263    itSub('[nft] Remove approval by using 0 amount', async ({helper}) => {64      const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});65      const collectionId = collection.collectionId;66      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});67      await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});68      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;69      await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);70      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;71    });7273    itSub('[fungible] Remove approval by using 0 amount', async ({helper}) => {74      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);75      await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));76      const tokenId = await helper.ft.getLastTokenId(collectionId);77      await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});78      const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));79      expect(amountBefore).to.be.equal(1n);8081      await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);82      const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));83      expect(amountAfter).to.be.equal(0n);84    });8586    itSub.ifWithPallets('[refungible] Remove approval by using 0 amount', [Pallets.ReFungible], async ({helper}) => {87      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});88      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});89      await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});90      const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));91      expect(amountBefore).to.be.equal(1n);9293      await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);94      const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));95      expect(amountAfter).to.be.equal(0n);96    });9798    itSub('can`t be called by collection owner on non-owned item when OwnerCanTransfer == false', async ({helper}) => {99      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});100      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});101      const result = (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: charlie.address});102      await expect(result).to.be.rejectedWith('common.CantApproveMoreThanOwned');103    });104  });105106  describe(`[${testCase.method}] Normal user can approve other users to transfer:`, () => {107    let alice: IKeyringPair;108    let bob: IKeyringPair;109    let charlie: IKeyringPair;110111    before(async () => {112      await usingPlaygrounds(async (helper, privateKey) => {113        const donor = await privateKey({url: import.meta.url});114        [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);115      });116    });117118    itSub('NFT', async ({helper}) => {119      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});120      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});121      await (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});122      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.true;123    });124125    itSub('Fungible up to an approved amount', async ({helper}) => {126      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);127      await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(bob));128      const tokenId = await helper.ft.getLastTokenId(collectionId);129      await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});130      const amount = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: charlie.address}, testCase.account(bob));131      expect(amount).to.be.equal(1n);132    });133134    itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {135      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});136      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob), pieces: 100n});137      await (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address}, 100n);138      const amount = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: charlie.address}, testCase.account(bob));139      expect(amount).to.be.equal(100n);140    });141  });142143  describe(`[${testCase.method}] Approved users can transferFrom up to approved amount:`, () => {144    let alice: IKeyringPair;145    let bob: IKeyringPair;146    let charlie: IKeyringPair;147148    before(async () => {149      await usingPlaygrounds(async (helper, privateKey) => {150        const donor = await privateKey({url: import.meta.url});151        [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);152      });153    });154155    itSub('NFT', async ({helper}) => {156      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});157      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});158      await (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});159      await helper.nft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address});160      const owner = await helper.nft.getTokenOwner(collectionId, tokenId);161      expect(owner.Substrate).to.be.equal(alice.address);162    });163164    itSub('Fungible up to an approved amount', async ({helper}) => {165      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);166      await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(bob));167      const tokenId = await helper.ft.getLastTokenId(collectionId);168      await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});169      const before = await helper.ft.getBalance(collectionId, {Substrate: alice.address});170      await helper.ft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);171      const after = await helper.ft.getBalance(collectionId, {Substrate: alice.address});172      expect(after - before).to.be.equal(1n);173    });174175    itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {176      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});177      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob), pieces: 100n});178      await (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});179      const before = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});180      await helper.rft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);181      const after = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});182      expect(after - before).to.be.equal(1n);183    });184  });185186  describe(`[${testCase.method}] Approved users cannot use transferFrom to repeat transfers if approved amount was already transferred:`, () => {187    let alice: IKeyringPair;188    let bob: IKeyringPair;189    let charlie: IKeyringPair;190191    before(async () => {192      await usingPlaygrounds(async (helper, privateKey) => {193        const donor = await privateKey({url: import.meta.url});194        [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);195      });196    });197198    itSub('NFT', async ({helper}) => {199      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});200      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});201      await (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});202      await helper.nft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address});203      const owner = await helper.nft.getTokenOwner(collectionId, tokenId);204      expect(owner.Substrate).to.be.equal(alice.address);205      const transferTokenFromTx = () => helper.nft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address});206      await expect(transferTokenFromTx()).to.be.rejectedWith('common.ApprovedValueTooLow');207    });208209    itSub('Fungible up to an approved amount', async ({helper}) => {210      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);211      await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(bob));212      const tokenId = await helper.ft.getLastTokenId(collectionId);213      await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});214      const before = await helper.ft.getBalance(collectionId, {Substrate: alice.address});215      await helper.ft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);216      const after = await helper.ft.getBalance(collectionId, {Substrate: alice.address});217      expect(after - before).to.be.equal(1n);218219      const transferTokenFromTx = () => helper.ft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);220      await expect(transferTokenFromTx()).to.be.rejectedWith('common.ApprovedValueTooLow');221    });222223    itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {224      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});225      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob), pieces: 100n});226      await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address}, 100n);227      const before = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});228      await helper.rft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 100n);229      const after = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});230      expect(after - before).to.be.equal(100n);231      const transferTokenFromTx = () => helper.rft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 100n);232      await expect(transferTokenFromTx()).to.be.rejectedWith('common.ApprovedValueTooLow');233    });234  });235236  describe(`[${testCase.method}] Approved amount decreases by the transferred amount:`, () => {237    let alice: IKeyringPair;238    let bob: IKeyringPair;239    let charlie: IKeyringPair;240    let dave: IKeyringPair;241242    before(async () => {243      await usingPlaygrounds(async (helper, privateKey) => {244        const donor = await privateKey({url: import.meta.url});245        [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);246      });247    });248249    itSub('If a user B is approved to transfer 10 Fungible tokens from user A, they can transfer 2 tokens to user C, which will result in decreasing approval from 10 to 8. Then user B can transfer 8 tokens to user D.', async ({helper}) => {250      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);251      await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));252      const tokenId = await helper.ft.getLastTokenId(collectionId);253      await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 10n);254255      const charlieBefore = await helper.ft.getBalance(collectionId, {Substrate: charlie.address});256      await helper.ft.transferTokenFrom(bob, collectionId, tokenId, testCase.account(alice), {Substrate: charlie.address}, 2n);257      const charlieAfter = await helper.ft.getBalance(collectionId, {Substrate: charlie.address});258      expect(charlieAfter - charlieBefore).to.be.equal(2n);259260      const daveBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address});261      await helper.ft.transferTokenFrom(bob, collectionId, tokenId, testCase.account(alice), {Substrate: dave.address}, 8n);262      const daveAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address});263      expect(daveAfter - daveBefore).to.be.equal(8n);264    });265  });266267  describe(`[${testCase.method}] User may clear the approvals to approving for 0 amount:`, () => {268    let alice: IKeyringPair;269    let bob: IKeyringPair;270    let charlie: IKeyringPair;271272    before(async () => {273      await usingPlaygrounds(async (helper, privateKey) => {274        const donor = await privateKey({url: import.meta.url});275        [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);276      });277    });278279    itSub('NFT', async ({helper}) => {280      const owner = testCase.account(alice);281      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});282      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: owner});283284      await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});285      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;286287      await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);288      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;289290      const transferTokenFromTx = helper.nft.transferTokenFrom(bob, collectionId, tokenId, owner, {Substrate: bob.address});291      await expect(transferTokenFromTx).to.be.rejectedWith('common.ApprovedValueTooLow');292    });293294    itSub('Fungible', async ({helper}) => {295      const owner = testCase.account(alice);296      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);297      await helper.ft.mintTokens(alice, collectionId, 10n, owner);298      const tokenId = await helper.ft.getLastTokenId(collectionId);299      await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});300      const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, owner);301      expect(amountBefore).to.be.equal(1n);302303      await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);304      const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, owner);305      expect(amountAfter).to.be.equal(0n);306307      const transferTokenFromTx = helper.ft.transferTokenFrom(bob, collectionId, tokenId, owner, {Substrate: charlie.address}, 1n);308      await expect(transferTokenFromTx).to.be.rejectedWith('common.ApprovedValueTooLow');309    });310311    itSub.ifWithPallets('ReFungible', [Pallets.ReFungible], async ({helper}) => {312      const owner = testCase.account(alice);313      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});314      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner, pieces: 100n});315      await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});316      const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, owner);317      expect(amountBefore).to.be.equal(1n);318319      await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);320      const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, owner);321      expect(amountAfter).to.be.equal(0n);322323      const transferTokenFromTx = helper.rft.transferTokenFrom(bob, collectionId, tokenId, owner, {Substrate: charlie.address}, 1n);324      await expect(transferTokenFromTx).to.be.rejectedWith('common.ApprovedValueTooLow');325    });326  });327328  describe(`[${testCase.method}] User cannot approve for the amount greater than they own:`, () => {329    let alice: IKeyringPair;330    let bob: IKeyringPair;331    let charlie: IKeyringPair;332333    before(async () => {334      await usingPlaygrounds(async (helper, privateKey) => {335        const donor = await privateKey({url: import.meta.url});336        [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);337      });338    });339340    itSub('1 for NFT', async ({helper}) => {341      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});342      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});343      const result = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address}, 2n);344      await expect(result).to.be.rejectedWith('nonfungible.NonfungibleItemsHaveNoAmount');345      expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.false;346    });347348    itSub('Fungible', async ({helper}) => {349      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);350      await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));351      const tokenId = await helper.ft.getLastTokenId(collectionId);352      const result = (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 11n);353      await expect(result).to.be.rejectedWith('common.CantApproveMoreThanOwned');354    });355356    itSub.ifWithPallets('ReFungible', [Pallets.ReFungible], async ({helper}) => {357      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});358      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});359      const result = (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 101n);360      await expect(result).to.be.rejectedWith('common.CantApproveMoreThanOwned');361    });362  });363364  describe(`[${testCase.method}] Integration Test approve(spender, collection_id, item_id, amount) with collection admin permissions:`, () => {365    let alice: IKeyringPair;366    let bob: IKeyringPair;367    let charlie: IKeyringPair;368369    before(async () => {370      await usingPlaygrounds(async (helper, privateKey) => {371        const donor = await privateKey({url: import.meta.url});372        [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);373      });374    });375376    itSub('cannot be called by collection admin on non-owned item', async ({helper}) => {377      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});378      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});379      await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});380      const approveTx = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});381      await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');382    });383  });384385  describe(`[${testCase.method}] Negative Integration Test approve(spender, collection_id, item_id, amount):`, () => {386    let alice: IKeyringPair;387    let bob: IKeyringPair;388    let charlie: IKeyringPair;389    const NONEXISTENT_COLLECTION = (2 ** 32) - 1;390391    before(async () => {392      await usingPlaygrounds(async (helper, privateKey) => {393        const donor = await privateKey({url: import.meta.url});394        [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);395      });396    });397398    itSub('[nft] Approve for a collection that does not exist', async ({helper}) => {399      const approveTx = (helper.nft as any)[testCase.method](bob, NONEXISTENT_COLLECTION, 1, {Substrate: charlie.address});400      await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');401    });402403    itSub('[fungible] Approve for a collection that does not exist', async ({helper}) => {404      const approveTx = (helper.ft as any)[testCase.method](bob, NONEXISTENT_COLLECTION, 1, {Substrate: charlie.address});405      await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');406    });407408    itSub.ifWithPallets('[refungible] Approve for a collection that does not exist', [Pallets.ReFungible], async ({helper}) => {409      const approveTx = (helper.rft as any)[testCase.method](bob, NONEXISTENT_COLLECTION, 1, {Substrate: charlie.address});410      await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');411    });412413    itSub('[nft] Approve for a collection that was destroyed', async ({helper}) => {414      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});415      await helper.nft.burn(alice, collectionId);416      const approveTx = (helper.nft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});417      await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');418    });419420    itSub('[fungible] Approve for a collection that was destroyed', async ({helper}) => {421      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});422      await helper.ft.burn(alice, collectionId);423      const approveTx = (helper.ft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});424      await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');425    });426427    itSub.ifWithPallets('[refungible] Approve for a collection that was destroyed', [Pallets.ReFungible], async ({helper}) => {428      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});429      await helper.rft.burn(alice, collectionId);430      const approveTx = (helper.rft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});431      await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');432    });433434    itSub('[nft] Approve transfer of a token that does not exist', async ({helper}) => {435      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});436      const approveTx = (helper.nft as any)[testCase.method](alice, collectionId, 2, {Substrate: bob.address});437      await expect(approveTx).to.be.rejectedWith('common.TokenNotFound');438    });439440    itSub.ifWithPallets('[refungible] Approve transfer of a token that does not exist', [Pallets.ReFungible], async ({helper}) => {441      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});442      const approveTx = (helper.rft as any)[testCase.method](alice, collectionId, 2, {Substrate: bob.address});443      await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned'); // TODO: why the error is not common.TokenNotFound444    });445446    itSub('[nft] Approve using the address that does not own the approved token', async ({helper}) => {447      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});448      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});449      const approveTx = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});450      await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');451    });452453    itSub('[fungible] Approve using the address that does not own the approved token', async ({helper}) => {454      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});455      await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));456      const tokenId = await helper.ft.getLastTokenId(collectionId);457      const approveTx = (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});458      await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');459    });460461    itSub.ifWithPallets('[refungible] Approve using the address that does not own the approved token', [Pallets.ReFungible], async ({helper}) => {462      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});463      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});464      const approveTx = (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});465      await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');466    });467468    itSub.ifWithPallets('should fail if approved more ReFungibles than owned', [Pallets.ReFungible], async ({helper}) => {469      const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});470      const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});471      await helper.rft.transferToken(alice, collectionId, tokenId, testCase.account(bob), 100n);472      await (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 100n);473474      const approveTx = (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 101n);475      await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');476    });477478    itSub('should fail if approved more Fungibles than owned', async ({helper}) => {479      const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});480      await helper.ft.mintTokens(alice, collectionId, 10n, alice.address);481      const tokenId = await helper.ft.getLastTokenId(collectionId);482483      await helper.ft.transferToken(alice, collectionId, tokenId, testCase.account(bob), 10n);484      await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 10n);485      const approveTx = (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 11n);486      await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');487    });488489    itSub('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async ({helper}) => {490      const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});491      const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});492      await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: false});493494      const approveTx = (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: charlie.address});495      await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');496    });497  });498});499500describe('Normal user can approve other users to be wallet operator:', () => {501  let alice: IKeyringPair;502  let bob: IKeyringPair;503504  before(async () => {505    await usingPlaygrounds(async (helper, privateKey) => {506      const donor = await privateKey({url: import.meta.url});507      [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);508    });509  });510511  itSub('[nft] Enable and disable approval', async ({helper}) => {512    const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});513514    const checkBeforeApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});515    expect(checkBeforeApproval).to.be.false;516517    await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true);518    const checkAfterApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});519    expect(checkAfterApproval).to.be.true;520521    await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false);522    const checkAfterDisapproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});523    expect(checkAfterDisapproval).to.be.false;524  });525526  itSub.ifWithPallets('[rft] Enable and disable approval', [Pallets.ReFungible], async ({helper}) => {527    const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});528529    const checkBeforeApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});530    expect(checkBeforeApproval).to.be.false;531532    await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true);533    const checkAfterApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});534    expect(checkAfterApproval).to.be.true;535536    await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false);537    const checkAfterDisapproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});538    expect(checkAfterDisapproval).to.be.false;539  });540});541542describe('Administrator and collection owner do not need approval in order to execute TransferFrom (with owner_can_transfer_flag = true):', () => {543  let alice: IKeyringPair;544  let bob: IKeyringPair;545  let charlie: IKeyringPair;546  let dave: IKeyringPair;547548  before(async () => {549    await usingPlaygrounds(async (helper, privateKey) => {550      const donor = await privateKey({url: import.meta.url});551      [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);552    });553  });554555  itSub('NFT', async ({helper}) => {556    const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});557    await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});558    const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: charlie.address});559560    await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address});561    const owner1 = await helper.nft.getTokenOwner(collectionId, tokenId);562    expect(owner1.Substrate).to.be.equal(dave.address);563564    await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});565    await helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address});566    const owner2 = await helper.nft.getTokenOwner(collectionId, tokenId);567    expect(owner2.Substrate).to.be.equal(alice.address);568  });569570  itSub('Fungible up to an approved amount', async ({helper}) => {571    const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);572    await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});573    await helper.ft.mintTokens(alice, collectionId, 10n, charlie.address);574    const tokenId = await helper.ft.getLastTokenId(collectionId);575576    const daveBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address});577    await helper.ft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);578    const daveBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address});579    expect(daveBalanceAfter - daveBalanceBefore).to.be.equal(1n);580581    await helper.collection.addAdmin(alice ,collectionId, {Substrate: bob.address});582583    const aliceBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: alice.address});584    await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);585    const aliceBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: alice.address});586    expect(aliceBalanceAfter - aliceBalanceBefore).to.be.equal(1n);587  });588589  itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {590    const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});591    await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});592    const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: charlie.address, pieces: 100n});593594    const daveBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});595    await helper.rft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);596    const daveAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});597    expect(daveAfter - daveBefore).to.be.equal(1n);598599    await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});600601    const aliceBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});602    await helper.rft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);603    const aliceAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});604    expect(aliceAfter - aliceBefore).to.be.equal(1n);605  });606});607608describe('Repeated approvals add up', () => {609  let alice: IKeyringPair;610  let bob: IKeyringPair;611  let charlie: IKeyringPair;612  let dave: IKeyringPair;613614  before(async () => {615    await usingPlaygrounds(async (helper, privateKey) => {616      const donor = await privateKey({url: import.meta.url});617      [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);618    });619  });620621  itSub.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. Fungible', async ({helper}) => {622    const collection = await helper.ft.mintCollection(alice, {});623    await collection.mint(alice, 10n);624    await collection.approveTokens(alice, {Substrate: bob.address}, 1n);625    await collection.approveTokens(alice, {Substrate: charlie.address}, 1n);626    // const allowances1 = await getAllowance(collectionId, 0, Alice.address, Bob.address);627    // const allowances2 = await getAllowance(collectionId, 0, Alice.address, Charlie.address);628    // expect(allowances1 + allowances2).to.be.eq(2n);629  });630631  itSub.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. ReFungible', async ({helper}) => {632    const collection = await helper.rft.mintCollection(alice, {});633    const token = await collection.mintToken(alice, 10n);634    await token.approve(alice, {Substrate: bob.address}, 1n);635    await token.approve(alice, {Substrate: charlie.address}, 1n);636    // const allowances1 = await getAllowance(collectionId, itemId, Alice.address, Bob.address);637    // const allowances2 = await getAllowance(collectionId, itemId, Alice.address, Charlie.address);638    // expect(allowances1 + allowances2).to.be.eq(2n);639  });640641  // Canceled by changing approve logic642  itSub.skip('Cannot approve for more than total user\'s amount (owned: 10, approval 1: 5 - should succeed, approval 2: 6 - should fail). Fungible', async ({helper}) => {643    const collection = await helper.ft.mintCollection(alice, {});644    await collection.mint(alice, 10n, {Substrate: dave.address});645    await collection.approveTokens(dave, {Substrate: bob.address}, 5n);646    await expect(collection.approveTokens(dave, {Substrate: charlie.address}, 6n))647      .to.be.rejectedWith('this test would fail (since it is skipped), replace this expecting message with what would have been received');648  });649650  // Canceled by changing approve logic651  itSub.skip('Cannot approve for more than total user\'s amount (owned: 100, approval 1: 50 - should succeed, approval 2: 51 - should fail). ReFungible', async ({helper}) => {652    const collection = await helper.rft.mintCollection(alice, {});653    const token = await collection.mintToken(alice, 100n, {Substrate: dave.address});654    await token.approve(dave, {Substrate: bob.address}, 50n);655    await expect(token.approve(dave, {Substrate: charlie.address}, 51n))656      .to.be.rejectedWith('this test would fail (since it is skipped), replace this expecting message with what would have been received');657  });658});