difftreelog
Check errors explicitly
in: master
1 file changed
tests/src/approve.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 {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(BigInt(1));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(BigInt(1));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(BigInt(1));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(BigInt(0));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(BigInt(1));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(BigInt(0));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.rejected;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(BigInt(1));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(BigInt(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(BigInt(1));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(BigInt(1));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.rejected;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(BigInt(1));218219 const transferTokenFromTx = () => helper.ft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 1n);220 await expect(transferTokenFromTx()).to.be.rejected;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(BigInt(100));231 const transferTokenFromTx = () => helper.rft.transferTokenFrom(charlie, collectionId, tokenId, testCase.account(bob), {Substrate: alice.address}, 100n);232 await expect(transferTokenFromTx()).to.be.rejected;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(BigInt(2));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(BigInt(8));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(BigInt(0));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.rejected;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.rejected;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.rejected;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('can 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 result = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});381 await expect(result).to.be.rejected;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;389390 before(async () => {391 await usingPlaygrounds(async (helper, privateKey) => {392 const donor = await privateKey({url: import.meta.url});393 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);394 });395 });396397 itSub('[nft] Approve for a collection that does not exist', async ({helper}) => {398 const collectionId = 1 << 32 - 1;399 await expect((helper.nft as any)[testCase.method](bob, collectionId, 1, {Substrate: charlie.address})).to.be.rejected;400 });401402 itSub('[fungible] Approve for a collection that does not exist', async ({helper}) => {403 const collectionId = 1 << 32 - 1;404 const approveTx = () => (helper.ft as any)[testCase.method](bob, collectionId, 1, {Substrate: charlie.address});405 await expect(approveTx()).to.be.rejected;406 });407408 itSub.ifWithPallets('[refungible] Approve for a collection that does not exist', [Pallets.ReFungible], async ({helper}) => {409 const collectionId = 1 << 32 - 1;410 const approveTx = () => (helper.rft as any)[testCase.method](bob, collectionId, 1, {Substrate: charlie.address});411 await expect(approveTx()).to.be.rejected;412 });413414 itSub('[nft] Approve for a collection that was destroyed', async ({helper}) => {415 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});416 await helper.nft.burn(alice, collectionId);417 const approveTx = () => (helper.nft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});418 await expect(approveTx()).to.be.rejected;419 });420421 itSub('[fungible] Approve for a collection that was destroyed', async ({helper}) => {422 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});423 await helper.ft.burn(alice, collectionId);424 const approveTx = () => (helper.ft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});425 await expect(approveTx()).to.be.rejected;426 });427428 itSub.ifWithPallets('[refungible] Approve for a collection that was destroyed', [Pallets.ReFungible], async ({helper}) => {429 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});430 await helper.rft.burn(alice, collectionId);431 const approveTx = () => (helper.rft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});432 await expect(approveTx()).to.be.rejected;433 });434435 itSub('[nft] Approve transfer of a token that does not exist', async ({helper}) => {436 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});437 const approveTx = () => (helper.nft as any)[testCase.method](alice, collectionId, 2, {Substrate: bob.address});438 await expect(approveTx()).to.be.rejected;439 });440441 itSub.ifWithPallets('[refungible] Approve transfer of a token that does not exist', [Pallets.ReFungible], async ({helper}) => {442 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});443 const approveTx = () => (helper.rft as any)[testCase.method](alice, collectionId, 2, {Substrate: bob.address});444 await expect(approveTx()).to.be.rejected;445 });446447 itSub('[nft] Approve using the address that does not own the approved token', async ({helper}) => {448 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});449 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});450 const approveTx = () => (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});451 await expect(approveTx()).to.be.rejected;452 });453454 itSub('[fungible] Approve using the address that does not own the approved token', async ({helper}) => {455 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});456 await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));457 const tokenId = await helper.ft.getLastTokenId(collectionId);458 const approveTx = () => (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});459 await expect(approveTx()).to.be.rejected;460 });461462 itSub.ifWithPallets('[refungible] Approve using the address that does not own the approved token', [Pallets.ReFungible], async ({helper}) => {463 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});464 const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});465 const approveTx = () => (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});466 await expect(approveTx()).to.be.rejected;467 });468469 itSub.ifWithPallets('should fail if approved more ReFungibles than owned', [Pallets.ReFungible], async ({helper}) => {470 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});471 const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});472 await helper.rft.transferToken(alice, collectionId, tokenId, testCase.account(bob), 100n);473 await (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 100n);474475 const approveTx = () => (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 101n);476 await expect(approveTx()).to.be.rejected;477 });478479 itSub('should fail if approved more Fungibles than owned', async ({helper}) => {480 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});481 await helper.ft.mintTokens(alice, collectionId, 10n, alice.address);482 const tokenId = await helper.ft.getLastTokenId(collectionId);483484 await helper.ft.transferToken(alice, collectionId, tokenId, testCase.account(bob), 10n);485 await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 10n);486 const approveTx = () => (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 11n);487 await expect(approveTx()).to.be.rejected;488 });489490 itSub('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async ({helper}) => {491 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});492 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});493 await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: false});494495 const approveTx = () => (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: charlie.address});496 await expect(approveTx()).to.be.rejected;497 });498 });499});500501describe('Normal user can approve other users to be wallet operator:', () => {502 let alice: IKeyringPair;503 let bob: IKeyringPair;504505 before(async () => {506 await usingPlaygrounds(async (helper, privateKey) => {507 const donor = await privateKey({url: import.meta.url});508 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);509 });510 });511512 itSub('[nft] Enable and disable approval', async ({helper}) => {513 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});514515 const checkBeforeApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});516 expect(checkBeforeApproval).to.be.false;517518 await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true);519 const checkAfterApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});520 expect(checkAfterApproval).to.be.true;521522 await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false);523 const checkAfterDisapproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});524 expect(checkAfterDisapproval).to.be.false;525 });526527 itSub.ifWithPallets('[rft] Enable and disable approval', [Pallets.ReFungible], async ({helper}) => {528 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});529530 const checkBeforeApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});531 expect(checkBeforeApproval).to.be.false;532533 await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true);534 const checkAfterApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});535 expect(checkAfterApproval).to.be.true;536537 await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false);538 const checkAfterDisapproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});539 expect(checkAfterDisapproval).to.be.false;540 });541});542543describe('Administrator and collection owner do not need approval in order to execute TransferFrom (with owner_can_transfer_flag = true):', () => {544 let alice: IKeyringPair;545 let bob: IKeyringPair;546 let charlie: IKeyringPair;547 let dave: IKeyringPair;548549 before(async () => {550 await usingPlaygrounds(async (helper, privateKey) => {551 const donor = await privateKey({url: import.meta.url});552 [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);553 });554 });555556 itSub('NFT', async ({helper}) => {557 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});558 await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});559 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: charlie.address});560561 await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address});562 const owner1 = await helper.nft.getTokenOwner(collectionId, tokenId);563 expect(owner1.Substrate).to.be.equal(dave.address);564565 await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});566 await helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address});567 const owner2 = await helper.nft.getTokenOwner(collectionId, tokenId);568 expect(owner2.Substrate).to.be.equal(alice.address);569 });570571 itSub('Fungible up to an approved amount', async ({helper}) => {572 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);573 await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});574 await helper.ft.mintTokens(alice, collectionId, 10n, charlie.address);575 const tokenId = await helper.ft.getLastTokenId(collectionId);576577 const daveBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address});578 await helper.ft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);579 const daveBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address});580 expect(daveBalanceAfter - daveBalanceBefore).to.be.equal(BigInt(1));581582 await helper.collection.addAdmin(alice ,collectionId, {Substrate: bob.address});583584 const aliceBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: alice.address});585 await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);586 const aliceBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: alice.address});587 expect(aliceBalanceAfter - aliceBalanceBefore).to.be.equal(BigInt(1));588 });589590 itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {591 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});592 await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});593 const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: charlie.address, pieces: 100n});594595 const daveBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});596 await helper.rft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);597 const daveAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});598 expect(daveAfter - daveBefore).to.be.equal(BigInt(1));599600 await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});601602 const aliceBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});603 await helper.rft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);604 const aliceAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});605 expect(aliceAfter - aliceBefore).to.be.equal(BigInt(1));606 });607});608609describe('Repeated approvals add up', () => {610 let alice: IKeyringPair;611 let bob: IKeyringPair;612 let charlie: IKeyringPair;613 let dave: IKeyringPair;614615 before(async () => {616 await usingPlaygrounds(async (helper, privateKey) => {617 const donor = await privateKey({url: import.meta.url});618 [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);619 });620 });621622 itSub.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. Fungible', async ({helper}) => {623 const collection = await helper.ft.mintCollection(alice, {});624 await collection.mint(alice, 10n);625 await collection.approveTokens(alice, {Substrate: bob.address}, 1n);626 await collection.approveTokens(alice, {Substrate: charlie.address}, 1n);627 // const allowances1 = await getAllowance(collectionId, 0, Alice.address, Bob.address);628 // const allowances2 = await getAllowance(collectionId, 0, Alice.address, Charlie.address);629 // expect(allowances1 + allowances2).to.be.eq(BigInt(2));630 });631632 itSub.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. ReFungible', async ({helper}) => {633 const collection = await helper.rft.mintCollection(alice, {});634 const token = await collection.mintToken(alice, 10n);635 await token.approve(alice, {Substrate: bob.address}, 1n);636 await token.approve(alice, {Substrate: charlie.address}, 1n);637 // const allowances1 = await getAllowance(collectionId, itemId, Alice.address, Bob.address);638 // const allowances2 = await getAllowance(collectionId, itemId, Alice.address, Charlie.address);639 // expect(allowances1 + allowances2).to.be.eq(BigInt(2));640 });641642 // Canceled by changing approve logic643 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}) => {644 const collection = await helper.ft.mintCollection(alice, {});645 await collection.mint(alice, 10n, {Substrate: dave.address});646 await collection.approveTokens(dave, {Substrate: bob.address}, 5n);647 await expect(collection.approveTokens(dave, {Substrate: charlie.address}, 6n))648 .to.be.rejectedWith('this test would fail (since it is skipped), replace this expecting message with what would have been received');649 });650651 // Canceled by changing approve logic652 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}) => {653 const collection = await helper.rft.mintCollection(alice, {});654 const token = await collection.mintToken(alice, 100n, {Substrate: dave.address});655 await token.approve(dave, {Substrate: bob.address}, 50n);656 await expect(token.approve(dave, {Substrate: charlie.address}, 51n))657 .to.be.rejectedWith('this test would fail (since it is skipped), replace this expecting message with what would have been received');658 });659});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;389390 before(async () => {391 await usingPlaygrounds(async (helper, privateKey) => {392 const donor = await privateKey({url: import.meta.url});393 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);394 });395 });396397 itSub('[nft] Approve for a collection that does not exist', async ({helper}) => {398 const collectionId = 999999;399 const approveTx = (helper.nft as any)[testCase.method](bob, collectionId, 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 collectionId = 999999;405 const approveTx = (helper.ft as any)[testCase.method](bob, collectionId, 1, {Substrate: charlie.address});406 await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');407 });408409 itSub.ifWithPallets('[refungible] Approve for a collection that does not exist', [Pallets.ReFungible], async ({helper}) => {410 const collectionId = 999999;411 const approveTx = (helper.rft as any)[testCase.method](bob, collectionId, 1, {Substrate: charlie.address});412 await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');413 });414415 itSub('[nft] Approve for a collection that was destroyed', async ({helper}) => {416 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});417 await helper.nft.burn(alice, collectionId);418 const approveTx = (helper.nft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});419 await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');420 });421422 itSub('[fungible] Approve for a collection that was destroyed', async ({helper}) => {423 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});424 await helper.ft.burn(alice, collectionId);425 const approveTx = (helper.ft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});426 await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');427 });428429 itSub.ifWithPallets('[refungible] Approve for a collection that was destroyed', [Pallets.ReFungible], async ({helper}) => {430 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});431 await helper.rft.burn(alice, collectionId);432 const approveTx = (helper.rft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});433 await expect(approveTx).to.be.rejectedWith('common.CollectionNotFound');434 });435436 itSub('[nft] Approve transfer of a token that does not exist', async ({helper}) => {437 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});438 const approveTx = (helper.nft as any)[testCase.method](alice, collectionId, 2, {Substrate: bob.address});439 await expect(approveTx).to.be.rejectedWith('common.TokenNotFound');440 });441442 itSub.ifWithPallets('[refungible] Approve transfer of a token that does not exist', [Pallets.ReFungible], async ({helper}) => {443 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});444 const approveTx = (helper.rft as any)[testCase.method](alice, collectionId, 2, {Substrate: bob.address});445 await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned'); // TODO: why the error is not common.TokenNotFound446 });447448 itSub('[nft] Approve using the address that does not own the approved token', async ({helper}) => {449 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});450 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});451 const approveTx = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});452 await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');453 });454455 itSub('[fungible] Approve using the address that does not own the approved token', async ({helper}) => {456 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});457 await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));458 const tokenId = await helper.ft.getLastTokenId(collectionId);459 const approveTx = (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});460 await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');461 });462463 itSub.ifWithPallets('[refungible] Approve using the address that does not own the approved token', [Pallets.ReFungible], async ({helper}) => {464 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});465 const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});466 const approveTx = (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});467 await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');468 });469470 itSub.ifWithPallets('should fail if approved more ReFungibles than owned', [Pallets.ReFungible], async ({helper}) => {471 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});472 const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: alice.address, pieces: 100n});473 await helper.rft.transferToken(alice, collectionId, tokenId, testCase.account(bob), 100n);474 await (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 100n);475476 const approveTx = (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 101n);477 await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');478 });479480 itSub('should fail if approved more Fungibles than owned', async ({helper}) => {481 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});482 await helper.ft.mintTokens(alice, collectionId, 10n, alice.address);483 const tokenId = await helper.ft.getLastTokenId(collectionId);484485 await helper.ft.transferToken(alice, collectionId, tokenId, testCase.account(bob), 10n);486 await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 10n);487 const approveTx = (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 11n);488 await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');489 });490491 itSub('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async ({helper}) => {492 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});493 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});494 await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: false});495496 const approveTx = (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: charlie.address});497 await expect(approveTx).to.be.rejectedWith('common.CantApproveMoreThanOwned');498 });499 });500});501502describe('Normal user can approve other users to be wallet operator:', () => {503 let alice: IKeyringPair;504 let bob: IKeyringPair;505506 before(async () => {507 await usingPlaygrounds(async (helper, privateKey) => {508 const donor = await privateKey({url: import.meta.url});509 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);510 });511 });512513 itSub('[nft] Enable and disable approval', async ({helper}) => {514 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});515516 const checkBeforeApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});517 expect(checkBeforeApproval).to.be.false;518519 await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true);520 const checkAfterApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});521 expect(checkAfterApproval).to.be.true;522523 await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false);524 const checkAfterDisapproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});525 expect(checkAfterDisapproval).to.be.false;526 });527528 itSub.ifWithPallets('[rft] Enable and disable approval', [Pallets.ReFungible], async ({helper}) => {529 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});530531 const checkBeforeApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});532 expect(checkBeforeApproval).to.be.false;533534 await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true);535 const checkAfterApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});536 expect(checkAfterApproval).to.be.true;537538 await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false);539 const checkAfterDisapproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});540 expect(checkAfterDisapproval).to.be.false;541 });542});543544describe('Administrator and collection owner do not need approval in order to execute TransferFrom (with owner_can_transfer_flag = true):', () => {545 let alice: IKeyringPair;546 let bob: IKeyringPair;547 let charlie: IKeyringPair;548 let dave: IKeyringPair;549550 before(async () => {551 await usingPlaygrounds(async (helper, privateKey) => {552 const donor = await privateKey({url: import.meta.url});553 [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);554 });555 });556557 itSub('NFT', async ({helper}) => {558 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});559 await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});560 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: charlie.address});561562 await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address});563 const owner1 = await helper.nft.getTokenOwner(collectionId, tokenId);564 expect(owner1.Substrate).to.be.equal(dave.address);565566 await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});567 await helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address});568 const owner2 = await helper.nft.getTokenOwner(collectionId, tokenId);569 expect(owner2.Substrate).to.be.equal(alice.address);570 });571572 itSub('Fungible up to an approved amount', async ({helper}) => {573 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);574 await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});575 await helper.ft.mintTokens(alice, collectionId, 10n, charlie.address);576 const tokenId = await helper.ft.getLastTokenId(collectionId);577578 const daveBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address});579 await helper.ft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);580 const daveBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address});581 expect(daveBalanceAfter - daveBalanceBefore).to.be.equal(1n);582583 await helper.collection.addAdmin(alice ,collectionId, {Substrate: bob.address});584585 const aliceBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: alice.address});586 await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);587 const aliceBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: alice.address});588 expect(aliceBalanceAfter - aliceBalanceBefore).to.be.equal(1n);589 });590591 itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {592 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});593 await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});594 const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: charlie.address, pieces: 100n});595596 const daveBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});597 await helper.rft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);598 const daveAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});599 expect(daveAfter - daveBefore).to.be.equal(1n);600601 await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});602603 const aliceBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});604 await helper.rft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);605 const aliceAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});606 expect(aliceAfter - aliceBefore).to.be.equal(1n);607 });608});609610describe('Repeated approvals add up', () => {611 let alice: IKeyringPair;612 let bob: IKeyringPair;613 let charlie: IKeyringPair;614 let dave: IKeyringPair;615616 before(async () => {617 await usingPlaygrounds(async (helper, privateKey) => {618 const donor = await privateKey({url: import.meta.url});619 [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);620 });621 });622623 itSub.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. Fungible', async ({helper}) => {624 const collection = await helper.ft.mintCollection(alice, {});625 await collection.mint(alice, 10n);626 await collection.approveTokens(alice, {Substrate: bob.address}, 1n);627 await collection.approveTokens(alice, {Substrate: charlie.address}, 1n);628 // const allowances1 = await getAllowance(collectionId, 0, Alice.address, Bob.address);629 // const allowances2 = await getAllowance(collectionId, 0, Alice.address, Charlie.address);630 // expect(allowances1 + allowances2).to.be.eq(2n);631 });632633 itSub.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. ReFungible', async ({helper}) => {634 const collection = await helper.rft.mintCollection(alice, {});635 const token = await collection.mintToken(alice, 10n);636 await token.approve(alice, {Substrate: bob.address}, 1n);637 await token.approve(alice, {Substrate: charlie.address}, 1n);638 // const allowances1 = await getAllowance(collectionId, itemId, Alice.address, Bob.address);639 // const allowances2 = await getAllowance(collectionId, itemId, Alice.address, Charlie.address);640 // expect(allowances1 + allowances2).to.be.eq(2n);641 });642643 // Canceled by changing approve logic644 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}) => {645 const collection = await helper.ft.mintCollection(alice, {});646 await collection.mint(alice, 10n, {Substrate: dave.address});647 await collection.approveTokens(dave, {Substrate: bob.address}, 5n);648 await expect(collection.approveTokens(dave, {Substrate: charlie.address}, 6n))649 .to.be.rejectedWith('this test would fail (since it is skipped), replace this expecting message with what would have been received');650 });651652 // Canceled by changing approve logic653 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}) => {654 const collection = await helper.rft.mintCollection(alice, {});655 const token = await collection.mintToken(alice, 100n, {Substrate: dave.address});656 await token.approve(dave, {Substrate: bob.address}, 50n);657 await expect(token.approve(dave, {Substrate: charlie.address}, 51n))658 .to.be.rejectedWith('this test would fail (since it is skipped), replace this expecting message with what would have been received');659 });660});