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

difftreelog

Move old tests to playgrounds-helpers

Max Andreev2022-08-29parent: #f9edb50.patch.diff
in: master

1 file changed

modifiedtests/src/app-promotion.test.tsdiffbeforeafterboth
36let palletAdmin: IKeyringPair;36let palletAdmin: IKeyringPair;
37let nominal: bigint;37let nominal: bigint;
38let promotionStartBlock: number | null = null;38let promotionStartBlock: number | null = null;
39const palletAddress = calculatePalleteAddress('appstake');
3940
40before(async function () {41before(async function () {
41 await usingPlaygrounds(async (helper, privateKeyWrapper) => {42 await usingPlaygrounds(async (helper, privateKeyWrapper) => {
42 if (!getModuleNames(helper.api!).includes(Pallets.AppPromotion)) this.skip();43 if (!getModuleNames(helper.api!).includes(Pallets.AppPromotion)) this.skip();
43 alice = privateKeyWrapper('//Alice');44 alice = privateKeyWrapper('//Alice');
44 bob = privateKeyWrapper('//Bob');45 bob = privateKeyWrapper('//Bob');
45 palletAdmin = privateKeyWrapper('//palletAdmin');46 palletAdmin = privateKeyWrapper('//palletAdmin');
46 await helper.balance.transferToSubstrate(alice, palletAdmin.address, 10n * helper.balance.getOneTokenNominal());
47 nominal = helper.balance.getOneTokenNominal();47 nominal = helper.balance.getOneTokenNominal();
48 await helper.balance.transferToSubstrate(alice, palletAdmin.address, 100n * nominal);
49 await helper.balance.transferToSubstrate(alice, palletAddress, 100n * nominal);
50 if (!promotionStartBlock) {
51 promotionStartBlock = (await helper.api!.query.parachainSystem.lastRelayChainBlockNumber()).toNumber();
52 }
53 await helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.startAppPromotion(promotionStartBlock!)));
48 });54 });
49});55});
5056
57after(async function () {
58 await usingPlaygrounds(async (helper) => {
59 await helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.stopAppPromotion()));
60 });
61});
62
51describe('app-promotions.stake extrinsic', () => {63describe('app-promotions.stake extrinsic', () => {
52 it('will change balance state to "locked", add it to "staked" map, and increase "totalStaked" amount', async () => {64 it('should change balance state to "locked", add it to "staked" map, and increase "totalStaked" amount', async () => {
53 await usingPlaygrounds(async (helper) => {65 await usingPlaygrounds(async (helper) => {
54 const totalStakedBefore = await helper.staking.getTotalStaked();66 const totalStakedBefore = await helper.staking.getTotalStaked();
55 const [staker] = await helper.arrange.creteAccounts([10n], alice);67 const [staker] = await helper.arrange.creteAccounts([10n], alice);
73 });85 });
74 });86 });
75 87
76 it('will throws if stake amount is more than total free balance', async () => {88 it('should reject transaction if stake amount is more than total free balance', async () => {
77 await usingPlaygrounds(async helper => { 89 await usingPlaygrounds(async helper => {
78 const [staker] = await helper.arrange.creteAccounts([10n], alice);90 const [staker] = await helper.arrange.creteAccounts([10n], alice);
7991
101 // TODO it('Staker stakes 5 times in one block with nonce');113 // TODO it('Staker stakes 5 times in one block with nonce');
102 // TODO it('Staked balance appears as locked in the balance pallet');114 // TODO it('Staked balance appears as locked in the balance pallet');
103 // TODO it('Alice stakes huge amount of tokens');115 // TODO it('Alice stakes huge amount of tokens');
104 // TODO it('Can stake from ethereum account')
105});116});
106117
107describe('unstake balance extrinsic', () => { 118describe('unstake balance extrinsic', () => {
108 it('will change balance state to "reserved", add it to "pendingUnstake" map, and subtract it from totalStaked', async () => {119 it('should change balance state to "reserved", add it to "pendingUnstake" map, and subtract it from totalStaked', async () => {
109 await usingPlaygrounds(async helper => {120 await usingPlaygrounds(async helper => {
110 const totalStakedBefore = await helper.staking.getTotalStaked();121 const totalStakedBefore = await helper.staking.getTotalStaked();
111 const [staker] = await helper.arrange.creteAccounts([10n], alice);122 const [staker] = await helper.arrange.creteAccounts([10n], alice);
118 });129 });
119 });130 });
120131
121 it('will remove from the "staked" map starting from the oldest entry', async () => {132 it('should remove from the "staked" map starting from the oldest entry', async () => {
122 await usingPlaygrounds(async helper => {133 await usingPlaygrounds(async helper => {
123 const [staker] = await helper.arrange.creteAccounts([100n], alice);134 const [staker] = await helper.arrange.creteAccounts([100n], alice);
124 await helper.staking.stake(staker, 10n * nominal);135 await helper.staking.stake(staker, 10n * nominal);
239 await expect(helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.eventually.fulfilled;250 await expect(helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.setAdminAddress({Substrate: palletAdmin.address})))).to.be.eventually.fulfilled;
240 251
241 // ...It doesn't break anything;252 // ...It doesn't break anything;
242 console.log(await helper.balance.getSubstrate(charlie.address));
243 console.log(await helper.balance.getSubstrate(palletAdmin.address));
244 const collection = await helper.nft.mintCollection(charlie, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});253 const collection = await helper.nft.mintCollection(charlie, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
245 await expect(helper.signTransaction(charlie, helper.api!.tx.promotion.sponsorCollection(collection.collectionId))).to.be.eventually.rejected;254 await expect(helper.signTransaction(charlie, helper.api!.tx.promotion.sponsorCollection(collection.collectionId))).to.be.eventually.rejected;
246 });255 });
262271
263describe('App-promotion collection sponsoring', () => {272describe('App-promotion collection sponsoring', () => {
264 before(async function () {273 before(async function () {
265 await usingPlaygrounds(async (helper, privateKeyWrapper) => {274 await usingPlaygrounds(async (helper) => {
266 if (!getModuleNames(helper.api!).includes(Pallets.AppPromotion)) this.skip();275 const tx = helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.setAdminAddress({Substrate: palletAdmin.address}));
267 alice = privateKeyWrapper('//Alice');
268 bob = privateKeyWrapper('//Bob');
269 palletAdmin = privateKeyWrapper('//palletAdmin');
270 await helper.balance.transferToSubstrate(alice, palletAdmin.address, 10n * helper.balance.getOneTokenNominal());
271 await helper.balance.transferToSubstrate(alice, calculatePalleteAddress('appstake'), 10n * helper.balance.getOneTokenNominal());
272
273
274 const tx = helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.setAdminAddress(normalizeAccountId(palletAdmin)));
275 await helper.signTransaction(alice, tx);276 await helper.signTransaction(alice, tx);
276
277 // const txStart = helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.startAppPromotion(promotionStartBlock));
278 // await helper.signTransaction(alice, txStart);
279
280 nominal = helper.balance.getOneTokenNominal();
281 });277 });
282 });278 });
283 279
284 it('can not be set by non admin', async () => {280 it('can not be set by non admin', async () => {
285
286
287 // arrange: Charlie creates Punks
288 // arrange: Sudo calls appPromotion.setAdminAddress(Alice)
289
290 // assert: Random calls appPromotion.sponsorCollection(Punks.id) throws /// Random account can not set sponsoring
291 // assert: Alice calls appPromotion.sponsorCollection(Punks.id) success /// Admin account can set sponsoring
292
293 await usingPlaygrounds(async (helper) => {281 await usingPlaygrounds(async (helper) => {
294 const colletcion = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});282 const [collectionOwner, nonAdmin] = await helper.arrange.creteAccounts([10n, 10n], alice);
283
284 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
295 285
296 const collectionId = colletcion.collectionId;286 await expect(helper.signTransaction(nonAdmin, helper.api!.tx.promotion.sponsorCollection(collection.collectionId))).to.be.eventually.rejected;
297
298 await expect(helper.signTransaction(bob, helper.api!.tx.promotion.sponsorCollection(collectionId))).to.be.eventually.rejected;
299 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionId))).to.be.eventually.fulfilled;287 expect((await collection.getData())?.raw.sponsorship).to.equal('Disabled');
300 });288 });
301
302 });289 });
303290
304 it('will set pallet address as confirmed admin for collection without sponsor', async () => {291 it('should set pallet address as confirmed admin', async () => {
305 // arrange: Charlie creates Punks
306
307 // act: Admin calls appPromotion.sponsorCollection(Punks.id)
308
309 // assert: query collectionById: Punks sponsoring is confirmed by PalleteAddress
310
311 await usingPlaygrounds(async (helper) => {292 await usingPlaygrounds(async (helper) => {
312 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});293 const [collectionOwner, oldSponsor] = await helper.arrange.creteAccounts([20n, 20n], alice);
313 const collectionId = collection.collectionId;
314
315 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionId))).to.be.eventually.fulfilled;
316 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: calculatePalleteAddress('appstake')});
317 });
318
319 });
320
321 it('will set pallet address as confirmed admin for collection with unconfirmed sponsor', async () => {
322 // arrange: Charlie creates Punks
323 // arrange: Charlie calls setCollectionSponsor(Punks.Id, Dave) /// Dave is unconfirmed sponsor
324
325 // act: Admin calls appPromotion.sponsorCollection(Punks.id)
326
327 // assert: query collectionById: Punks sponsoring is confirmed by PalleteAddress
328
329 await usingPlaygrounds(async (helper) => {
330 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
331 await collection.setSponsor(alice, bob.address);
332 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: bob.address});
333 294
334 const collectionId = collection.collectionId;295 // Can set sponsoring for collection without sponsor
335 296 const collectionWithoutSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'No-sponsor', description: 'New Collection', tokenPrefix: 'Promotion'});
336 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionId))).to.be.eventually.fulfilled;297 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionWithoutSponsor.collectionId))).to.be.eventually.fulfilled;
337 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: calculatePalleteAddress('appstake')});298 expect((await collectionWithoutSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
338 });
339
340 });
341299
342 it('will set pallet address as confirmed admin for collection with confirmed sponsor', async () => {300 // Can set sponsoring for collection with unconfirmed sponsor
343 // arrange: Charlie creates Punks301 const collectionWithUnconfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Unconfirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: oldSponsor.address});
344 // arrange: setCollectionSponsor(Punks.Id, Dave)302 expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: oldSponsor.address});
345 // arrange: confirmSponsorship(Punks.Id, Dave) /// Dave is confirmed sponsor303 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionWithUnconfirmedSponsor.collectionId))).to.be.eventually.fulfilled;
304 expect((await collectionWithUnconfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
346305
347 // act: Admin calls appPromotion.sponsorCollection(Punks.id)306 // Can set sponsoring for collection with confirmed sponsor
348
349 // assert: query collectionById: Punks sponsoring is confirmed by PalleteAddress
350 307 const collectionWithConfirmedSponsor = await helper.nft.mintCollection(collectionOwner, {name: 'Confirmed', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: oldSponsor.address});
351 await usingPlaygrounds(async (helper) => {
352 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
353 await collection.setSponsor(alice, bob.address);
354
355 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: bob.address});
356 expect(await collection.confirmSponsorship(bob)).to.be.true;308 await collectionWithConfirmedSponsor.confirmSponsorship(oldSponsor);
357 309 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionWithConfirmedSponsor.collectionId))).to.be.eventually.fulfilled;
358 const collectionId = collection.collectionId;
359
360 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionId))).to.be.eventually.fulfilled;
361 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: calculatePalleteAddress('appstake')});310 expect((await collectionWithConfirmedSponsor.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
362 });311 });
363 });312 });
364313
365 it('can be overwritten by collection owner', async () => {314 it('can be overwritten by collection owner', async () => {
366 // arrange: Charlie creates Punks
367 // arrange: appPromotion.sponsorCollection(Punks.Id) /// Sponsor of Punks is pallete
368
369 // act: Charlie calls unique.setCollectionLimits(limits) /// Charlie as owner can successfully change limits
370 // assert: query collectionById(Punks.id) 1. sponsored by pallete, 2. limits has been changed
371
372 // act: Charlie calls setCollectionSponsor(Dave) /// Collection owner reasignes sponsoring
373 // assert: query collectionById: Punks sponsoring is unconfirmed by Dave
374
375 await usingPlaygrounds(async (helper) => {315 await usingPlaygrounds(async (helper) => {
376 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});316 const [collectionOwner, newSponsor] = await helper.arrange.creteAccounts([20n, 0n], alice);
317 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
377 const collectionId = collection.collectionId;318 const collectionId = collection.collectionId;
378 319
379 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionId))).to.be.eventually.fulfilled;320 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionId))).to.be.eventually.fulfilled;
380 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: calculatePalleteAddress('appstake')});
381 321
382 expect(await collection.setLimits(alice, {sponsorTransferTimeout: 0})).to.be.true;322 // Collection limits still can be changed by the owner
323 expect(await collection.setLimits(collectionOwner, {sponsorTransferTimeout: 0})).to.be.true;
383 expect((await collection.getData())?.raw.limits.sponsorTransferTimeout).to.be.equal(0);324 expect((await collection.getData())?.raw.limits.sponsorTransferTimeout).to.be.equal(0);
384 325 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
326
327 // Collection sponsor can be changed too
385 expect((await collection.setSponsor(alice, bob.address))).to.be.true;328 expect((await collection.setSponsor(collectionOwner, newSponsor.address))).to.be.true;
386 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: bob.address});329 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Unconfirmed: newSponsor.address});
387 });330 });
388
389 });331 });
390 332
391 it('will keep collection limits set by the owner earlier', async () => {333 it('should not overwrite collection limits set by the owner earlier', async () => {
392 // arrange: const limits = {...all possible collection limits}
393 // arrange: Charlie creates Punks
394 // arrange: Charlie calls unique.setCollectionLimits(limits) /// Owner sets all possible limits
395
396 // act: Admin calls appPromotion.sponsorCollection(Punks.id)
397 // assert: query collectionById(Punks.id) returns limits
398
399 await usingPlaygrounds(async (helper) => {334 await usingPlaygrounds(async (helper) => {
400 335 const limits = {ownerCanDestroy: true, ownerCanTransfer: true, sponsorTransferTimeout: 0};
401 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});336 const collectionWithLimits = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', limits});
402 expect(await collection.setLimits(alice, {sponsorTransferTimeout: 0})).to.be.true;337
403 const limits = (await collection.getData())?.raw.limits;
404 338 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionWithLimits.collectionId))).to.be.eventually.fulfilled;
405 const collectionId = collection.collectionId;
406 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionId))).to.be.eventually.fulfilled;
407 expect((await collection.getData())?.raw.limits).to.be.deep.equal(limits);339 expect((await collectionWithLimits.getData())?.raw.limits).to.be.deep.contain(limits);
408 });340 });
409
410 });341 });
411 342
412 it('will throw if collection doesn\'t exist', async () => {343 it('should reject transaction if collection doesn\'t exist', async () => {
413 // assert: Admin calls appPromotion.sponsorCollection(999999999999999) throw
414 await usingPlaygrounds(async (helper) => {344 await usingPlaygrounds(async (helper) => {
415 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(999999999))).to.be.eventually.rejected;345 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(999999999))).to.be.eventually.rejected;
416 });346 });
417 });347 });
418348
419 it('will throw if collection was burnt', async () => {349 it('should reject transaction if collection was burnt', async () => {
420 // arrange: Charlie creates Punks
421 // arrange: Charlie burns Punks
422
423 // assert: Admin calls appPromotion.sponsorCollection(Punks.id) throw
424
425 await usingPlaygrounds(async (helper) => {350 await usingPlaygrounds(async (helper) => {
426 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});351 const [collectionOwner] = await helper.arrange.creteAccounts([10n], alice);
352 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
427 const collectionId = collection.collectionId;353 await collection.burn(collectionOwner);
428 354
429 expect((await collection.burn(alice))).to.be.true;
430 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionId))).to.be.eventually.rejected;355 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collection.collectionId))).to.be.eventually.rejected;
431 });356 });
432
433 });357 });
434});358});
435359
436
437describe('app-promotion stopSponsoringCollection', () => {360describe('app-promotion stopSponsoringCollection', () => {
438 before(async function () {361 it('can not be called by non-admin', async () => {
439 await usingPlaygrounds(async (helper, privateKeyWrapper) => {
440 if (!getModuleNames(helper.api!).includes(Pallets.AppPromotion)) this.skip();
441 alice = privateKeyWrapper('//Alice');
442 bob = privateKeyWrapper('//Bob');
443 palletAdmin = privateKeyWrapper('//palletAdmin');
444 await helper.balance.transferToSubstrate(alice, palletAdmin.address, 10n * helper.balance.getOneTokenNominal());
445 await helper.balance.transferToSubstrate(alice, calculatePalleteAddress('appstake'), 10n * helper.balance.getOneTokenNominal());
446
447 const tx = helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.setAdminAddress(normalizeAccountId(palletAdmin)));
448 await helper.signTransaction(alice, tx);
449
450 nominal = helper.balance.getOneTokenNominal();
451 });
452 });
453
454 it('can not be called by non-admin', async () => {
455 // arrange: Alice creates Punks
456 // arrange: appPromotion.sponsorCollection(Punks.Id)
457
458 // assert: Random calls appPromotion.stopSponsoringCollection(Punks) throws
459 // assert: query collectionById(Punks.id): sponsoring confirmed by PalleteAddress
460
461 await usingPlaygrounds(async (helper) => {362 await usingPlaygrounds(async (helper) => {
462 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});363 const [collectionOwner, nonAdmin] = await helper.arrange.creteAccounts([10n, 10n], alice);
463 const collectionId = collection.collectionId;364 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
464 365
465 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionId))).to.be.eventually.fulfilled;366 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collection.collectionId))).to.be.eventually.fulfilled;
466 367
467 await expect(helper.signTransaction(bob, helper.api!.tx.promotion.stopSponsorignCollection(collectionId))).to.be.eventually.rejected;368 await expect(helper.signTransaction(nonAdmin, helper.api!.tx.promotion.stopSponsorignCollection(collection.collectionId))).to.be.eventually.rejected;
468 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: calculatePalleteAddress('appstake')});369 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: palletAddress});
469 });370 });
470 });371 });
471372
472 it('will set sponsoring as disabled', async () => {373 it('should set sponsoring as disabled', async () => {
473 // arrange: Alice creates Punks
474 // arrange: appPromotion.sponsorCollection(Punks.Id)
475
476 // act: Admin calls appPromotion.stopSponsoringCollection(Punks)
477
478 // assert: query collectionById(Punks.id): sponsoring unconfirmed
479
480 await usingPlaygrounds(async (helper) => {374 await usingPlaygrounds(async (helper) => {
481 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});375 const [collectionOwner] = await helper.arrange.creteAccounts([10n, 10n], alice);
482 const collectionId = collection.collectionId;376 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
483 377
484 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collectionId))).to.be.eventually.fulfilled;378 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.sponsorCollection(collection.collectionId))).to.be.eventually.fulfilled;
485 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.stopSponsorignCollection(collectionId))).to.be.eventually.fulfilled;379 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.stopSponsorignCollection(collection.collectionId))).to.be.eventually.fulfilled;
486 380
487 expect((await collection.getData())?.raw.sponsorship).to.be.equal('Disabled');381 expect((await collection.getData())?.raw.sponsorship).to.be.equal('Disabled');
488 });382 });
489 });383 });
490384
491 it('will not affect collection which is not sponsored by pallete', async () => {385 it('should not affect collection which is not sponsored by pallete', async () => {
492 // arrange: Alice creates Punks
493 // arrange: Alice calls setCollectionSponsoring(Punks)
494 // arrange: Alice calls confirmSponsorship(Punks)
495
496 // act: Admin calls appPromotion.stopSponsoringCollection(A)
497 // assert: query collectionById(Punks): Sponsoring: {Confirmed: Alice} /// Alice still collection owner
498
499 await usingPlaygrounds(async (helper) => {386 await usingPlaygrounds(async (helper) => {
500 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});387 const [collectionOwner] = await helper.arrange.creteAccounts([10n, 10n], alice);
501 const collectionId = collection.collectionId;388 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion', pendingSponsor: collectionOwner.address});
502 expect(await collection.setSponsor(alice, alice.address)).to.be.true;
503 expect(await collection.confirmSponsorship(alice)).to.be.true;389 await collection.confirmSponsorship(collectionOwner);
504 390
505 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.stopSponsorignCollection(collectionId))).to.be.eventually.rejected;391 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.stopSponsorignCollection(collection.collectionId))).to.be.eventually.rejected;
506 392
507 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: alice.address});393 expect((await collection.getData())?.raw.sponsorship).to.be.deep.equal({Confirmed: collectionOwner.address});
508 });394 });
509
510 });395 });
511396
512 it('will throw if collection does not exist', async () => {397 it('should reject transaction if collection does not exist', async () => {
513 // arrange: Alice creates Punks
514 // arrange: Alice burns Punks
515
516 // assert: Admin calls appPromotion.stopSponsoringCollection(Punks.id) throws
517 // assert: Admin calls appPromotion.stopSponsoringCollection(999999999999999) throw
518
519 await usingPlaygrounds(async (helper) => {398 await usingPlaygrounds(async (helper) => {
520 const collection = await helper.nft.mintCollection(alice, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});399 const [collectionOwner] = await helper.arrange.creteAccounts([10n], alice);
521 const collectionId = collection.collectionId;400 const collection = await helper.nft.mintCollection(collectionOwner, {name: 'New', description: 'New Collection', tokenPrefix: 'Promotion'});
522 401
523 expect((await collection.burn(alice))).to.be.true;402 await collection.burn(collectionOwner);
403 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.stopSponsorignCollection(collection.collectionId))).to.be.eventually.rejected;
524 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.stopSponsorignCollection(collectionId))).to.be.eventually.rejected;404 await expect(helper.signTransaction(palletAdmin, helper.api!.tx.promotion.stopSponsorignCollection(999999999))).to.be.eventually.rejected;
525 });405 });
526 });406 });
527});407});
593 bob = privateKeyWrapper('//Bob');473 bob = privateKeyWrapper('//Bob');
594 palletAdmin = privateKeyWrapper('//palletAdmin');474 palletAdmin = privateKeyWrapper('//palletAdmin');
595 await helper.balance.transferToSubstrate(alice, palletAdmin.address, 10n * helper.balance.getOneTokenNominal());475 await helper.balance.transferToSubstrate(alice, palletAdmin.address, 10n * helper.balance.getOneTokenNominal());
596 await helper.balance.transferToSubstrate(alice, calculatePalleteAddress('appstake'), 10n * helper.balance.getOneTokenNominal());476 await helper.balance.transferToSubstrate(alice, palletAddress, 10n * helper.balance.getOneTokenNominal());
597 477
598 const tx = helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.setAdminAddress(normalizeAccountId(palletAdmin)));478 const tx = helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.setAdminAddress(normalizeAccountId(palletAdmin)));
599 await helper.signTransaction(alice, tx);479 await helper.signTransaction(alice, tx);
641});521});
642522
643describe('app-promotion rewards', () => {523describe('app-promotion rewards', () => {
644 const DAY = 7200n;524 it('should credit 0.05% for staking period', async () => {
645
646 // TODO (load test. Can pay reward for 10000 addresses)
647
648
649 before(async function () {
650 await usingPlaygrounds(async (helper, privateKeyWrapper) => {
651 if (!getModuleNames(helper.api!).includes(Pallets.AppPromotion)) this.skip();
652 alice = privateKeyWrapper('//Alice');
653 bob = privateKeyWrapper('//Bob');
654 palletAdmin = privateKeyWrapper('//palletAdmin');
655 if (promotionStartBlock == null) {
656 promotionStartBlock = (await helper.api!.query.parachainSystem.lastRelayChainBlockNumber()).toNumber();
657 }
658 const tx = helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.setAdminAddress(normalizeAccountId(palletAdmin)));
659 await helper.signTransaction(alice, tx);
660
661 const txStart = helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.startAppPromotion(promotionStartBlock!));
662 await helper.signTransaction(alice, txStart);
663
664 nominal = helper.balance.getOneTokenNominal();
665 });
666 });
667
668 after(async function () {
669 await usingPlaygrounds(async (helper) => {
670 await helper.signTransaction(alice, helper.api!.tx.sudo.sudo(helper.api!.tx.promotion.stopAppPromotion()));
671 });
672 });
673
674 it('will credit 0.05% for staking period', async () => {
675 // arrange: bob.stake(10000);
676 // arrange: bob.stake(20000);
677 // arrange: waitForRewards();
678
679 // assert: bob.staked to equal [10005, 20010]
680
681 await usingPlaygrounds(async helper => {525 await usingPlaygrounds(async helper => {
682 const staker = await createUser(50n * nominal);526 const [staker] = await helper.arrange.creteAccounts([50n], alice);
683 await waitForRecalculationBlock(helper.api!);527 await waitForRecalculationBlock(helper.api!);
684 528
685 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.stake(1n * nominal))).to.be.eventually.fulfilled;529 await helper.staking.stake(staker, 1n * nominal);
686 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.stake(2n * nominal))).to.be.eventually.fulfilled;530 await helper.staking.stake(staker, 2n * nominal);
687 await waitForRelayBlock(helper.api!, 36);531 await waitForRelayBlock(helper.api!, 36);
688 532
689 533 const totalStakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(s => s[1]);
690 expect((await helper.api!.rpc.unique.totalStakedPerBlock(normalizeAccountId(staker)))
691 .map(([_, amount]) => amount.toBigInt()))
692 .to.be.deep.equal([calculateIncome(nominal, 10n), calculateIncome(2n * nominal, 10n)]);534 expect(totalStakedPerBlock).to.be.deep.equal([calculateIncome(nominal, 10n), calculateIncome(2n * nominal, 10n)]);
693 });535 });
694
695 });536 });
696 537
697 it('will not be credited for unstaked (reserved) balance', async () => {538 it('should not be credited for unstaked (reserved) balance', async () => {
698 // arrange: bob.stake(10000);
699 // arrange: bob.unstake(5000);
700 // arrange: waitForRewards();
701
702 // assert: bob.staked to equal [5002.5]
703 await usingPlaygrounds(async helper => {539 await usingPlaygrounds(async helper => {
704 const staker = await createUser(20n * nominal);540 expect.fail('Implement me after unstake method will be fixed');
705 await waitForRecalculationBlock(helper.api!);
706 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.stake(10n * nominal))).to.be.eventually.fulfilled;
707 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.unstake(5n * nominal))).to.be.eventually.fulfilled;
708 await waitForRelayBlock(helper.api!, 38);
709
710 expect((await helper.api!.rpc.unique.totalStakedPerBlock(normalizeAccountId(staker)))
711 .map(([_, amount]) => amount.toBigInt()))
712 .to.be.deep.equal([calculateIncome(5n * nominal, 10n)]);
713
714 });541 });
715
716 });542 });
717 543
718 it('will bring compound interest', async () => {544 it('should bring compound interest', async () => {
719 // arrange: bob balance = 30000
720 // arrange: bob.stake(10000);
721 // arrange: bob.stake(10000);
722 // arrange: waitForRewards();
723
724 // assert: bob.staked() equal [10005, 10005, 10005] /// 10_000 * 1.0005
725 // act: waitForRewards();
726
727 // assert: bob.staked() equal [10010.0025, 10010.0025, 10010.0025] /// 10_005 * 1.0005
728 // act: bob.unstake(10.0025)
729 // assert: bob.staked() equal [10000, 10010.0025, 10010.0025] /// 10_005 * 1.0005
730
731 // act: waitForRewards();
732 // assert: bob.staked() equal [10005, 10015,00750125, 10015,00750125] ///
733 await usingPlaygrounds(async helper => {545 await usingPlaygrounds(async helper => {
734 const staker = await createUser(40n * nominal);546 const [staker] = await helper.arrange.creteAccounts([80n], alice);
735 547
736 await waitForRecalculationBlock(helper.api!);548 await waitForRecalculationBlock(helper.api!);
737 549
738
739 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.stake(10n * nominal))).to.be.eventually.fulfilled;550 await helper.staking.stake(staker, 10n * nominal);
551 await helper.staking.stake(staker, 20n * nominal);
552 await helper.staking.stake(staker, 30n * nominal);
740 553
741 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.stake(10n * nominal))).to.be.eventually.fulfilled;
742
743 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.stake(10n * nominal))).to.be.eventually.fulfilled;
744
745 await waitForRelayBlock(helper.api!, 34);554 await waitForRelayBlock(helper.api!, 34);
746 expect((await helper.api!.rpc.unique.totalStakedPerBlock(normalizeAccountId(staker)))555 let totalStakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(s => s[1]);
747 .map(([_, amount]) => amount.toBigInt()))
748 .to.be.deep.equal([calculateIncome(10n * nominal, 10n), calculateIncome(10n * nominal, 10n), calculateIncome(10n * nominal, 10n)]);556 expect(totalStakedPerBlock).to.deep.equal([calculateIncome(10n * nominal, 10n), calculateIncome(20n * nominal, 10n), calculateIncome(30n * nominal, 10n)]);
749 557
750 await waitForRelayBlock(helper.api!, 20);558 await waitForRelayBlock(helper.api!, 20);
751 await expect(helper.signTransaction(staker, helper.api!.tx.promotion.unstake(calculateIncome(10n * nominal, 10n, 2) - 10n * nominal))).to.be.eventually.fulfilled;559 totalStakedPerBlock = (await helper.staking.getTotalStakedPerBlock({Substrate: staker.address})).map(s => s[1]);
752 expect((await helper.api!.rpc.unique.totalStakedPerBlock(normalizeAccountId(staker)))
753 .map(([_, amount]) => amount.toBigInt()))
754 .to.be.deep.equal([10n * nominal, calculateIncome(10n * nominal, 10n, 2), calculateIncome(10n * nominal, 10n, 2)]);560 expect(totalStakedPerBlock).to.deep.equal([calculateIncome(10n * nominal, 10n, 2), calculateIncome(20n * nominal, 10n, 2), calculateIncome(30n * nominal, 10n, 2)]);
755 });561 });
756
757 });562 });
563
564 // TODO (load test. Can pay reward for 10000 addresses)
758});565});
759566
760567
789 });596 });
790}597}
791598
792
793function calculatePalleteAddress(palletId: any) {599function calculatePalleteAddress(palletId: any) {
794 const address = stringToU8a(('modl' + palletId).padEnd(32, '\0'));600 const address = stringToU8a(('modl' + palletId).padEnd(32, '\0'));
795 return encodeAddress(address);601 return encodeAddress(address);
796}602}
603
797function calculateIncome(base: bigint, calcPeriod: bigint, iter = 0): bigint {604function calculateIncome(base: bigint, calcPeriod: bigint, iter = 0): bigint {
798 const DAY = 7200n;605 const DAY = 7200n;
799 const ACCURACY = 1_000_000_000n;606 const ACCURACY = 1_000_000_000n;
802 if (iter > 1) {609 if (iter > 1) {
803 return calculateIncome(income, calcPeriod, iter - 1);610 return calculateIncome(income, calcPeriod, iter - 1);
804 } else return income;611 } else return income;
805}
806
807async function createUser(amount?: bigint) {
808 return await usingPlaygrounds(async helper => {
809 const user: IKeyringPair = helper.util.fromSeed(mnemonicGenerate());
810 await helper.balance.transferToSubstrate(alice, user.address, amount ? amount : 10n * helper.balance.getOneTokenNominal());
811 return user;
812 });
813}612}
814613