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

difftreelog

test owner/admin unnest

Daniel Shiposha2023-01-16parent: #0170864.patch.diff
in: master

2 files changed

modifiedtests/src/nesting/nest.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {expect, itSub, Pallets, usingPlaygrounds} from '../util';18import {expect, itSub, Pallets, usingPlaygrounds} from '../util';
19import {UniqueNFToken, UniqueRFToken} from '../util/playgrounds/unique';
2019
21describe('Integration Test: Composite nesting tests', () => {20describe('Integration Test: Composite nesting tests', () => {
22 let alice: IKeyringPair;21 let alice: IKeyringPair;
139 before(async () => {138 before(async () => {
140 await usingPlaygrounds(async (helper, privateKey) => {139 await usingPlaygrounds(async (helper, privateKey) => {
141 const donor = await privateKey({filename: __filename});140 const donor = await privateKey({filename: __filename});
142 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 20n, 20n], donor);141 [alice, bob, charlie] = await helper.arrange.createAccounts([50n, 10n, 10n], donor);
143 });142 });
144 });143 });
145144
337 expect(await newToken.getBalance(targetToken.nestingAccount())).to.be.equal(2n);336 expect(await newToken.getBalance(targetToken.nestingAccount())).to.be.equal(2n);
338 });337 });
339
340 async function checkNestedRft({
341 expectedBalance,
342 childrenShouldPresent,
343 nestedRft,
344 targetNft,
345 }: {
346 expectedBalance: bigint,
347 childrenShouldPresent: boolean,
348 nestedRft: UniqueRFToken,
349 targetNft: UniqueNFToken,
350 }) {
351 const balance = await nestedRft.getBalance(targetNft.nestingAccount());
352 expect(balance).to.be.equal(expectedBalance);
353
354 const children = await targetNft.getChildren();
355
356 if (childrenShouldPresent) {
357 expect(children[0]).to.be.deep.equal({
358 collectionId: nestedRft.collectionId,
359 tokenId: nestedRft.tokenId,
360 });
361 } else {
362 expect(children.length).to.be.equal(0);
363 }
364 }
365
366 itSub.ifWithPallets('ReFungible: allows a collection owner to transfer nested token', [Pallets.ReFungible], async ({helper}) => {
367 const collectionNFT = await helper.nft.mintCollection(alice);
368 const collectionRFT = await helper.rft.mintCollection(alice, {
369 limits: {
370 ownerCanTransfer: true,
371 },
372 });
373
374 await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});
375
376 const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
377 const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});
378
379 await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);
380 await checkNestedRft({
381 expectedBalance: 5n,
382 childrenShouldPresent: true,
383 nestedRft,
384 targetNft,
385 });
386
387 await nestedRft.transferFrom(alice, targetNft.nestingAccount(), {Substrate: bob.address}, 2n);
388 await checkNestedRft({
389 expectedBalance: 3n,
390 childrenShouldPresent: true,
391 nestedRft,
392 targetNft,
393 });
394 expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(2n);
395
396 await nestedRft.transferFrom(alice, targetNft.nestingAccount(), {Substrate: bob.address}, 3n);
397 await checkNestedRft({
398 expectedBalance: 0n,
399 childrenShouldPresent: false,
400 nestedRft,
401 targetNft,
402 });
403 expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(5n);
404 });
405
406 itSub.ifWithPallets('ReFungible: allows a collection admin to transfer nested token', [Pallets.ReFungible], async ({helper}) => {
407 const collectionNFT = await helper.nft.mintCollection(alice);
408 const collectionRFT = await helper.rft.mintCollection(alice, {
409 limits: {
410 ownerCanTransfer: true,
411 },
412 });
413 await collectionRFT.addAdmin(alice, {Substrate: bob.address});
414
415 await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});
416
417 const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
418 const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});
419
420 await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);
421 await checkNestedRft({
422 expectedBalance: 5n,
423 childrenShouldPresent: true,
424 nestedRft,
425 targetNft,
426 });
427
428 await nestedRft.transferFrom(bob, targetNft.nestingAccount(), {Substrate: bob.address}, 2n);
429 await checkNestedRft({
430 expectedBalance: 3n,
431 childrenShouldPresent: true,
432 nestedRft,
433 targetNft,
434 });
435 expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(2n);
436
437 await nestedRft.transferFrom(bob, targetNft.nestingAccount(), {Substrate: bob.address}, 3n);
438 await checkNestedRft({
439 expectedBalance: 0n,
440 childrenShouldPresent: false,
441 nestedRft,
442 targetNft,
443 });
444 expect(await nestedRft.getBalance({Substrate: bob.address})).to.be.equal(5n);
445 });
446
447 itSub.ifWithPallets('ReFungible: allows a collection owner to burn nested token', [Pallets.ReFungible], async ({helper}) => {
448 const collectionNFT = await helper.nft.mintCollection(alice, {
449 limits: {
450 ownerCanTransfer: true,
451 },
452 });
453 const collectionRFT = await helper.rft.mintCollection(alice, {
454 limits: {
455 ownerCanTransfer: true,
456 },
457 });
458
459 await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});
460
461 const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
462 const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});
463
464 await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);
465 await checkNestedRft({
466 expectedBalance: 5n,
467 childrenShouldPresent: true,
468 nestedRft,
469 targetNft,
470 });
471
472 await nestedRft.burnFrom(alice, targetNft.nestingAccount(), 2n);
473 await checkNestedRft({
474 expectedBalance: 3n,
475 childrenShouldPresent: true,
476 nestedRft,
477 targetNft,
478 });
479
480 await nestedRft.burnFrom(alice, targetNft.nestingAccount(), 3n);
481 await checkNestedRft({
482 expectedBalance: 0n,
483 childrenShouldPresent: false,
484 nestedRft,
485 targetNft,
486 });
487
488 // Check if we can burn target NFT when all nested RFTs are gone
489 await targetNft.burnFrom(alice, {Substrate: charlie.address});
490 });
491
492 itSub.ifWithPallets('ReFungible: allows a collection admin to burn nested token', [Pallets.ReFungible], async ({helper}) => {
493 const collectionNFT = await helper.nft.mintCollection(alice, {
494 limits: {
495 ownerCanTransfer: true,
496 },
497 });
498 const collectionRFT = await helper.rft.mintCollection(alice, {
499 limits: {
500 ownerCanTransfer: true,
501 },
502 });
503 await collectionNFT.addAdmin(alice, {Substrate: bob.address});
504 await collectionRFT.addAdmin(alice, {Substrate: bob.address});
505
506 await collectionNFT.setPermissions(alice, {nesting: {tokenOwner: true}});
507
508 const targetNft = await collectionNFT.mintToken(alice, {Substrate: charlie.address});
509 const nestedRft = await collectionRFT.mintToken(alice, 5n, {Substrate: charlie.address});
510
511 await nestedRft.transfer(charlie, targetNft.nestingAccount(), 5n);
512 await checkNestedRft({
513 expectedBalance: 5n,
514 childrenShouldPresent: true,
515 nestedRft,
516 targetNft,
517 });
518
519 await nestedRft.burnFrom(bob, targetNft.nestingAccount(), 2n);
520 await checkNestedRft({
521 expectedBalance: 3n,
522 childrenShouldPresent: true,
523 nestedRft,
524 targetNft,
525 });
526
527 await nestedRft.burnFrom(bob, targetNft.nestingAccount(), 3n);
528 await checkNestedRft({
529 expectedBalance: 0n,
530 childrenShouldPresent: false,
531 nestedRft,
532 targetNft,
533 });
534
535 // Check if we can burn target NFT when all nested RFTs are gone
536 await targetNft.burnFrom(bob, {Substrate: charlie.address});
537 });
538});338});
539339
540describe('Negative Test: Nesting', () => {340describe('Negative Test: Nesting', () => {
modifiedtests/src/nesting/unnest.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {expect, itSub, Pallets, usingPlaygrounds} from '../util';18import {expect, itSub, Pallets, usingPlaygrounds} from '../util';
19import {UniqueFTCollection, UniqueNFToken, UniqueRFToken} from '../util/playgrounds/unique';
1920
20describe('Integration Test: Unnesting', () => {21describe('Integration Test: Unnesting', () => {
21 let alice: IKeyringPair;22 let alice: IKeyringPair;
23 let bob: IKeyringPair;
24 let charlie: IKeyringPair;
2225
23 before(async () => {26 before(async () => {
24 await usingPlaygrounds(async (helper, privateKey) => {27 await usingPlaygrounds(async (helper, privateKey) => {
25 const donor = await privateKey({filename: __filename});28 const donor = await privateKey({filename: __filename});
26 [alice] = await helper.arrange.createAccounts([50n], donor);29 [alice, bob, charlie] = await helper.arrange.createAccounts([200n, 50n, 50n], donor);
27 });30 });
28 });31 });
2932
84 expect(await targetToken.getChildren()).to.be.length(0);87 expect(await targetToken.getChildren()).to.be.length(0);
85 });88 });
89
90 async function checkNestedAmountState({
91 expectedBalance,
92 childrenShouldPresent,
93 nested,
94 targetNft,
95 }: {
96 expectedBalance: bigint,
97 childrenShouldPresent: boolean,
98 nested: UniqueFTCollection | UniqueRFToken,
99 targetNft: UniqueNFToken,
100 }) {
101 const balance = await nested.getBalance(targetNft.nestingAccount());
102 expect(balance).to.be.equal(expectedBalance);
103
104 const children = await targetNft.getChildren();
105
106 if (childrenShouldPresent) {
107 expect(children[0]).to.be.deep.equal({
108 collectionId: nested.collectionId,
109 tokenId: (nested instanceof UniqueFTCollection) ? 0 : nested.tokenId,
110 });
111 } else {
112 expect(children.length).to.be.equal(0);
113 }
114 }
115
116 function ownerOrAdminUnnestCases(modes: ('ft' | 'nft' | 'rft')[]): {
117 mode: 'ft' | 'nft' | 'rft',
118 sender: string,
119 op: 'transfer' | 'burn',
120 requiredPallets: Pallets[],
121 }[] {
122 const senders = ['owner', 'admin'];
123 const ops = ['transfer', 'burn'];
124
125 const cases = [];
126 for (const mode of modes) {
127 const requiredPallets = (mode === 'rft')
128 ? [Pallets.ReFungible]
129 : [];
130
131 for (const sender of senders) {
132 for (const op of ops) {
133 cases.push({
134 mode: mode as 'ft' | 'nft' | 'rft',
135 sender,
136 op: op as 'transfer' | 'burn',
137 requiredPallets,
138 });
139 }
140 }
141 }
142
143 return cases;
144 }
145
146 ownerOrAdminUnnestCases(['ft', 'rft']).map(testCase =>
147 itSub.ifWithPallets(`[${testCase.mode}]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, testCase.requiredPallets, async({helper}) => {
148 const owner = alice;
149 const admin = bob;
150
151 const unnester = (testCase.sender === 'owner')
152 ? owner
153 : admin;
154
155 const collectionNFT = await helper.nft.mintCollection(owner);
156 await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});
157
158 const collectionNested = await helper[testCase.mode as 'ft' | 'rft'].mintCollection(owner, {
159 limits: {
160 ownerCanTransfer: true,
161 },
162 });
163 await collectionNested.addAdmin(owner, {Substrate: admin.address});
164
165 const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});
166
167 let nested: UniqueFTCollection | UniqueRFToken;
168 const totalAmount = 5n;
169 const firstUnnestAmount = 2n;
170 const restUnnestAmount = totalAmount - firstUnnestAmount;
171
172 if (collectionNested instanceof UniqueFTCollection) {
173 await collectionNested.mint(owner, totalAmount, {Substrate: charlie.address});
174 nested = collectionNested;
175 } else {
176 nested = await collectionNested.mintToken(owner, totalAmount, {Substrate: charlie.address});
177 }
178
179 // transfer/burn `amount` of nested assets by `unnester`.
180 const doOperationAndCheck = async ({
181 amount,
182 shouldBeNestedAfterOp,
183 }: {
184 amount: bigint,
185 shouldBeNestedAfterOp: boolean,
186 }) => {
187 const nestedBalanceBeforeOp = await nested.getBalance(targetNft.nestingAccount());
188
189 if (testCase.op === 'transfer') {
190 const bobBalanceBeforeOp = await nested.getBalance({Substrate: bob.address});
191
192 await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address}, amount);
193 expect(await nested.getBalance({Substrate: bob.address})).to.be.equal(bobBalanceBeforeOp + amount);
194 } else {
195 if (nested instanceof UniqueFTCollection) {
196 await nested.burnTokensFrom(unnester, targetNft.nestingAccount(), amount);
197 } else {
198 await nested.burnFrom(unnester, targetNft.nestingAccount(), amount);
199 }
200 }
201
202 await checkNestedAmountState({
203 expectedBalance: nestedBalanceBeforeOp - amount,
204 childrenShouldPresent: shouldBeNestedAfterOp,
205 nested,
206 targetNft,
207 });
208 };
209
210 // Initial setup: nest (fungibles/rft parts).
211 // Check NFT's balance of nested assets and NFT's children.
212 await nested.transfer(charlie, targetNft.nestingAccount(), totalAmount);
213 await checkNestedAmountState({
214 expectedBalance: totalAmount,
215 childrenShouldPresent: true,
216 nested,
217 targetNft,
218 });
219
220 // Transfer/burn only a part of nested assets.
221 // Check that NFT's balance of the nested assets correctly decreased and NFT's children are not changed.
222 await doOperationAndCheck({
223 amount: firstUnnestAmount,
224 shouldBeNestedAfterOp: true,
225 });
226
227 // Transfer/burn all remaining nested assets.
228 // Check that NFT's balance of the nested assets is 0 and NFT has no more children.
229 await doOperationAndCheck({
230 amount: restUnnestAmount,
231 shouldBeNestedAfterOp: false,
232 });
233 }));
234
235 ownerOrAdminUnnestCases(['nft']).map(testCase =>
236 itSub(`[nft]: allows a collection ${testCase.sender} to ${testCase.op} nested token`, async ({helper}) => {
237 const owner = alice;
238 const admin = bob;
239
240 const unnester = (testCase.sender === 'owner')
241 ? owner
242 : admin;
243
244 const collectionNFT = await helper.nft.mintCollection(owner);
245 await collectionNFT.setPermissions(owner, {nesting: {tokenOwner: true}});
246
247 const collectionNested = await helper.nft.mintCollection(owner, {
248 limits: {
249 ownerCanTransfer: true,
250 },
251 });
252 await collectionNested.addAdmin(owner, {Substrate: admin.address});
253
254 const targetNft = await collectionNFT.mintToken(owner, {Substrate: charlie.address});
255 const nested = await collectionNested.mintToken(owner, {Substrate: charlie.address});
256
257 await nested.transfer(charlie, targetNft.nestingAccount());
258 expect(await targetNft.getChildren()).to.be.deep.equal([{
259 collectionId: nested.collectionId,
260 tokenId: nested.tokenId,
261 }]);
262
263 if (testCase.op === 'transfer') {
264 await nested.transferFrom(unnester, targetNft.nestingAccount(), {Substrate: bob.address});
265 } else {
266 await nested.burnFrom(unnester, targetNft.nestingAccount());
267 }
268
269 expect((await targetNft.getChildren()).length).to.be.equal(0);
270 }));
86});271});
87272
88describe('Negative Test: Unnesting', () => {273describe('Negative Test: Unnesting', () => {