1234567891011121314151617import {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({filename: __filename});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({filename: __filename});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({filename: __filename});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({filename: __filename});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({filename: __filename});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({filename: __filename});275 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);276 });277 });278279 itSub('NFT', async ({helper}) => {280 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});281 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});282 await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});283 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.true;284 await (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);285 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: bob.address})).to.be.false;286 const transferTokenFromTx = () => helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: bob.address}, {Substrate: bob.address});287 await expect(transferTokenFromTx()).to.be.rejected;288 });289290 itSub('Fungible', async ({helper}) => {291 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);292 await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));293 const tokenId = await helper.ft.getLastTokenId(collectionId);294 await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});295 const amountBefore = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));296 expect(amountBefore).to.be.equal(BigInt(1));297298 await (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);299 const amountAfter = await helper.ft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));300 expect(amountAfter).to.be.equal(BigInt(0));301302 const transferTokenFromTx = () => helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: bob.address}, {Substrate: charlie.address}, 1n);303 await expect(transferTokenFromTx()).to.be.rejected;304 });305306 itSub.ifWithPallets('ReFungible', [Pallets.ReFungible], async ({helper}) => {307 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});308 const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});309 await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address});310 const amountBefore = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));311 expect(amountBefore).to.be.equal(BigInt(1));312313 await (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 0n);314 const amountAfter = await helper.rft.getTokenApprovedPieces(collectionId, tokenId, {Substrate: bob.address}, testCase.account(alice));315 expect(amountAfter).to.be.equal(BigInt(0));316317 const transferTokenFromTx = () => helper.rft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: bob.address}, {Substrate: charlie.address}, 100n);318 await expect(transferTokenFromTx()).to.be.rejected;319 });320 });321322 describe(`[${testCase.method}] User cannot approve for the amount greater than they own:`, () => {323 let alice: IKeyringPair;324 let bob: IKeyringPair;325 let charlie: IKeyringPair;326327 before(async () => {328 await usingPlaygrounds(async (helper, privateKey) => {329 const donor = await privateKey({filename: __filename});330 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);331 });332 });333334 itSub('1 for NFT', async ({helper}) => {335 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});336 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});337 const result = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address}, 2n);338 await expect(result).to.be.rejected;339 expect(await helper.nft.isTokenApproved(collectionId, tokenId, {Substrate: charlie.address})).to.be.false;340 });341342 itSub('Fungible', async ({helper}) => {343 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);344 await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));345 const tokenId = await helper.ft.getLastTokenId(collectionId);346 const result = (helper.ft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 11n);347 await expect(result).to.be.rejected;348 });349350 itSub.ifWithPallets('ReFungible', [Pallets.ReFungible], async ({helper}) => {351 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});352 const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});353 const result = (helper.rft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: bob.address}, 101n);354 await expect(result).to.be.rejected;355 });356 });357358 describe(`[${testCase.method}] Integration Test approve(spender, collection_id, item_id, amount) with collection admin permissions:`, () => {359 let alice: IKeyringPair;360 let bob: IKeyringPair;361 let charlie: IKeyringPair;362363 before(async () => {364 await usingPlaygrounds(async (helper, privateKey) => {365 const donor = await privateKey({filename: __filename});366 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);367 });368 });369370 itSub('can be called by collection admin on non-owned item', async ({helper}) => {371 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});372 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});373 await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});374 const result = (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: charlie.address});375 await expect(result).to.be.rejected;376 });377 });378379 describe(`[${testCase.method}] Negative Integration Test approve(spender, collection_id, item_id, amount):`, () => {380 let alice: IKeyringPair;381 let bob: IKeyringPair;382 let charlie: IKeyringPair;383384 before(async () => {385 await usingPlaygrounds(async (helper, privateKey) => {386 const donor = await privateKey({filename: __filename});387 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);388 });389 });390391 itSub('[nft] Approve for a collection that does not exist', async ({helper}) => {392 const collectionId = 1 << 32 - 1;393 await expect((helper.nft as any)[testCase.method](bob, collectionId, 1, {Substrate: charlie.address})).to.be.rejected;394 });395396 itSub('[fungible] Approve for a collection that does not exist', async ({helper}) => {397 const collectionId = 1 << 32 - 1;398 const approveTx = () => (helper.ft as any)[testCase.method](bob, collectionId, 1, {Substrate: charlie.address});399 await expect(approveTx()).to.be.rejected;400 });401402 itSub.ifWithPallets('[refungible] Approve for a collection that does not exist', [Pallets.ReFungible], async ({helper}) => {403 const collectionId = 1 << 32 - 1;404 const approveTx = () => (helper.rft as any)[testCase.method](bob, collectionId, 1, {Substrate: charlie.address});405 await expect(approveTx()).to.be.rejected;406 });407408 itSub('[nft] Approve for a collection that was destroyed', async ({helper}) => {409 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});410 await helper.nft.burn(alice, collectionId);411 const approveTx = () => (helper.nft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});412 await expect(approveTx()).to.be.rejected;413 });414415 itSub('[fungible] Approve for a collection that was destroyed', async ({helper}) => {416 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});417 await helper.ft.burn(alice, collectionId);418 const approveTx = () => (helper.ft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});419 await expect(approveTx()).to.be.rejected;420 });421422 itSub.ifWithPallets('[refungible] Approve for a collection that was destroyed', [Pallets.ReFungible], async ({helper}) => {423 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});424 await helper.rft.burn(alice, collectionId);425 const approveTx = () => (helper.rft as any)[testCase.method](alice, collectionId, 1, {Substrate: bob.address});426 await expect(approveTx()).to.be.rejected;427 });428429 itSub('[nft] Approve transfer of a token that does not exist', async ({helper}) => {430 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});431 const approveTx = () => (helper.nft as any)[testCase.method](alice, collectionId, 2, {Substrate: bob.address});432 await expect(approveTx()).to.be.rejected;433 });434435 itSub.ifWithPallets('[refungible] Approve transfer of a token that does not exist', [Pallets.ReFungible], async ({helper}) => {436 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});437 const approveTx = () => (helper.rft as any)[testCase.method](alice, collectionId, 2, {Substrate: bob.address});438 await expect(approveTx()).to.be.rejected;439 });440441 itSub('[nft] Approve using the address that does not own the approved token', async ({helper}) => {442 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});443 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice)});444 const approveTx = () => (helper.nft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});445 await expect(approveTx()).to.be.rejected;446 });447448 itSub('[fungible] Approve using the address that does not own the approved token', async ({helper}) => {449 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});450 await helper.ft.mintTokens(alice, collectionId, 10n, testCase.account(alice));451 const tokenId = await helper.ft.getLastTokenId(collectionId);452 const approveTx = () => (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});453 await expect(approveTx()).to.be.rejected;454 });455456 itSub.ifWithPallets('[refungible] Approve using the address that does not own the approved token', [Pallets.ReFungible], async ({helper}) => {457 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});458 const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(alice), pieces: 100n});459 const approveTx = () => (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address});460 await expect(approveTx()).to.be.rejected;461 });462463 itSub.ifWithPallets('should fail if approved more ReFungibles than owned', [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: alice.address, pieces: 100n});466 await helper.rft.transferToken(alice, collectionId, tokenId, testCase.account(bob), 100n);467 await (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 100n);468469 const approveTx = () => (helper.rft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 101n);470 await expect(approveTx()).to.be.rejected;471 });472473 itSub('should fail if approved more Fungibles than owned', async ({helper}) => {474 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});475 await helper.ft.mintTokens(alice, collectionId, 10n, alice.address);476 const tokenId = await helper.ft.getLastTokenId(collectionId);477478 await helper.ft.transferToken(alice, collectionId, tokenId, testCase.account(bob), 10n);479 await (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 10n);480 const approveTx = () => (helper.ft as any)[testCase.method](bob, collectionId, tokenId, {Substrate: alice.address}, 11n);481 await expect(approveTx()).to.be.rejected;482 });483484 itSub('fails when called by collection owner on non-owned item when OwnerCanTransfer == false', async ({helper}) => {485 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});486 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: testCase.account(bob)});487 await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: false});488489 const approveTx = () => (helper.nft as any)[testCase.method](alice, collectionId, tokenId, {Substrate: charlie.address});490 await expect(approveTx()).to.be.rejected;491 });492 });493});494495describe('Normal user can approve other users to be wallet operator:', () => {496 let alice: IKeyringPair;497 let bob: IKeyringPair;498499 before(async () => {500 await usingPlaygrounds(async (helper, privateKey) => {501 const donor = await privateKey({filename: __filename});502 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);503 });504 });505506 itSub('[nft] Enable and disable approval', async ({helper}) => {507 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});508509 const checkBeforeApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});510 expect(checkBeforeApproval).to.be.false;511512 await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true);513 const checkAfterApproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});514 expect(checkAfterApproval).to.be.true;515516 await helper.nft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false);517 const checkAfterDisapproval = await helper.nft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});518 expect(checkAfterDisapproval).to.be.false;519 });520521 itSub.ifWithPallets('[rft] Enable and disable approval', [Pallets.ReFungible], async ({helper}) => {522 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});523524 const checkBeforeApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});525 expect(checkBeforeApproval).to.be.false;526527 await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, true);528 const checkAfterApproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});529 expect(checkAfterApproval).to.be.true;530531 await helper.rft.setAllowanceForAll(alice, collectionId, {Substrate: bob.address}, false);532 const checkAfterDisapproval = await helper.rft.allowanceForAll(collectionId, {Substrate: alice.address}, {Substrate: bob.address});533 expect(checkAfterDisapproval).to.be.false;534 });535});536537describe('Administrator and collection owner do not need approval in order to execute TransferFrom (with owner_can_transfer_flag = true):', () => {538 let alice: IKeyringPair;539 let bob: IKeyringPair;540 let charlie: IKeyringPair;541 let dave: IKeyringPair;542543 before(async () => {544 await usingPlaygrounds(async (helper, privateKey) => {545 const donor = await privateKey({filename: __filename});546 [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);547 });548 });549550 itSub('NFT', async ({helper}) => {551 const {collectionId} = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});552 await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});553 const {tokenId} = await helper.nft.mintToken(alice, {collectionId: collectionId, owner: charlie.address});554555 await helper.nft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address});556 const owner1 = await helper.nft.getTokenOwner(collectionId, tokenId);557 expect(owner1.Substrate).to.be.equal(dave.address);558559 await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});560 await helper.nft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address});561 const owner2 = await helper.nft.getTokenOwner(collectionId, tokenId);562 expect(owner2.Substrate).to.be.equal(alice.address);563 });564565 itSub('Fungible up to an approved amount', async ({helper}) => {566 const {collectionId} = await helper.ft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'}, 0);567 await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});568 await helper.ft.mintTokens(alice, collectionId, 10n, charlie.address);569 const tokenId = await helper.ft.getLastTokenId(collectionId);570571 const daveBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: dave.address});572 await helper.ft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);573 const daveBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: dave.address});574 expect(daveBalanceAfter - daveBalanceBefore).to.be.equal(BigInt(1));575576 await helper.collection.addAdmin(alice ,collectionId, {Substrate: bob.address});577578 const aliceBalanceBefore = await helper.ft.getBalance(collectionId, {Substrate: alice.address});579 await helper.ft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);580 const aliceBalanceAfter = await helper.ft.getBalance(collectionId, {Substrate: alice.address});581 expect(aliceBalanceAfter - aliceBalanceBefore).to.be.equal(BigInt(1));582 });583584 itSub.ifWithPallets('ReFungible up to an approved amount', [Pallets.ReFungible], async ({helper}) => {585 const {collectionId} = await helper.rft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});586 await helper.collection.setLimits(alice, collectionId, {ownerCanTransfer: true});587 const {tokenId} = await helper.rft.mintToken(alice, {collectionId: collectionId, owner: charlie.address, pieces: 100n});588589 const daveBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});590 await helper.rft.transferTokenFrom(alice, collectionId, tokenId, {Substrate: charlie.address}, {Substrate: dave.address}, 1n);591 const daveAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: dave.address});592 expect(daveAfter - daveBefore).to.be.equal(BigInt(1));593594 await helper.collection.addAdmin(alice, collectionId, {Substrate: bob.address});595596 const aliceBefore = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});597 await helper.rft.transferTokenFrom(bob, collectionId, tokenId, {Substrate: dave.address}, {Substrate: alice.address}, 1n);598 const aliceAfter = await helper.rft.getTokenBalance(collectionId, tokenId, {Substrate: alice.address});599 expect(aliceAfter - aliceBefore).to.be.equal(BigInt(1));600 });601});602603describe('Repeated approvals add up', () => {604 let alice: IKeyringPair;605 let bob: IKeyringPair;606 let charlie: IKeyringPair;607 let dave: IKeyringPair;608609 before(async () => {610 await usingPlaygrounds(async (helper, privateKey) => {611 const donor = await privateKey({filename: __filename});612 [alice, bob, charlie, dave] = await helper.arrange.createAccounts([100n, 100n, 100n, 100n], donor);613 });614 });615616 itSub.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. Fungible', async ({helper}) => {617 const collection = await helper.ft.mintCollection(alice, {});618 await collection.mint(alice, 10n);619 await collection.approveTokens(alice, {Substrate: bob.address}, 1n);620 await collection.approveTokens(alice, {Substrate: charlie.address}, 1n);621 622 623 624 });625626 itSub.skip('Owned 10, approval 1: 1, approval 2: 1, resulting approved value: 2. ReFungible', async ({helper}) => {627 const collection = await helper.rft.mintCollection(alice, {});628 const token = await collection.mintToken(alice, 10n);629 await token.approve(alice, {Substrate: bob.address}, 1n);630 await token.approve(alice, {Substrate: charlie.address}, 1n);631 632 633 634 });635636 637 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}) => {638 const collection = await helper.ft.mintCollection(alice, {});639 await collection.mint(alice, 10n, {Substrate: dave.address});640 await collection.approveTokens(dave, {Substrate: bob.address}, 5n);641 await expect(collection.approveTokens(dave, {Substrate: charlie.address}, 6n))642 .to.be.rejectedWith('this test would fail (since it is skipped), replace this expecting message with what would have been received');643 });644645 646 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}) => {647 const collection = await helper.rft.mintCollection(alice, {});648 const token = await collection.mintToken(alice, 100n, {Substrate: dave.address});649 await token.approve(dave, {Substrate: bob.address}, 50n);650 await expect(token.approve(dave, {Substrate: charlie.address}, 51n))651 .to.be.rejectedWith('this test would fail (since it is skipped), replace this expecting message with what would have been received');652 });653});