1234567891011121314151617import {expect, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from './util';18import {IKeyringPair} from '@polkadot/types/types';19import {DevUniqueHelper} from './util/playgrounds/unique.dev';2021describe('Scheduling token and balance transfers', () => {22 let superuser: IKeyringPair;23 let alice: IKeyringPair;24 let bob: IKeyringPair;25 let charlie: IKeyringPair;2627 before(async function() {28 await usingPlaygrounds(async (helper, privateKey) => {29 requirePalletsOrSkip(this, helper, [Pallets.Scheduler]);3031 superuser = await privateKey('//Alice');32 const donor = await privateKey({filename: __filename});33 [alice, bob, charlie] = await helper.arrange.createAccounts([100n, 100n, 100n], donor);3435 await helper.testUtils.enable();36 });37 });3839 itSub('Can delay a transfer of an owned token', async ({helper}) => {40 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});41 const token = await collection.mintToken(alice);42 const schedulerId = await helper.arrange.makeScheduledId();43 const blocksBeforeExecution = 4;44 45 await token.scheduleAfter(schedulerId, blocksBeforeExecution)46 .transfer(alice, {Substrate: bob.address});47 const executionBlock = await helper.chain.getLatestBlockNumber() + blocksBeforeExecution + 1;4849 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});5051 await helper.wait.forParachainBlockNumber(executionBlock);5253 expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});54 });5556 itSub('Can transfer funds periodically', async ({helper}) => {57 const scheduledId = await helper.arrange.makeScheduledId();58 const waitForBlocks = 1;5960 const amount = 1n * helper.balance.getOneTokenNominal();61 const periodic = {62 period: 2,63 repetitions: 2,64 };6566 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);6768 await helper.scheduler.scheduleAfter(scheduledId, waitForBlocks, {periodic})69 .balance.transferToSubstrate(alice, bob.address, amount);70 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;7172 await helper.wait.forParachainBlockNumber(executionBlock);7374 const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address);75 expect(bobsBalanceAfterFirst)76 .to.be.equal(77 bobsBalanceBefore + 1n * amount,78 '#1 Balance of the recipient should be increased by 1 * amount',79 );8081 await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);8283 const bobsBalanceAfterSecond = await helper.balance.getSubstrate(bob.address);84 expect(bobsBalanceAfterSecond)85 .to.be.equal(86 bobsBalanceBefore + 2n * amount,87 '#2 Balance of the recipient should be increased by 2 * amount',88 );89 });9091 itSub('Can cancel a scheduled operation which has not yet taken effect', async ({helper}) => {92 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});93 const token = await collection.mintToken(alice);9495 const scheduledId = await helper.arrange.makeScheduledId();96 const waitForBlocks = 4;9798 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});99100 await token.scheduleAfter(scheduledId, waitForBlocks)101 .transfer(alice, {Substrate: bob.address});102 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;103104 await helper.scheduler.cancelScheduled(alice, scheduledId);105106 await helper.wait.forParachainBlockNumber(executionBlock);107108 expect(await token.getOwner()).to.be.deep.equal({Substrate: alice.address});109 });110111 itSub('Can cancel a periodic operation (transfer of funds)', async ({helper}) => {112 const waitForBlocks = 1;113 const periodic = {114 period: 3,115 repetitions: 2,116 };117118 const scheduledId = await helper.arrange.makeScheduledId();119120 const amount = 1n * helper.balance.getOneTokenNominal();121122 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);123124 await helper.scheduler.scheduleAfter(scheduledId, waitForBlocks, {periodic})125 .balance.transferToSubstrate(alice, bob.address, amount);126 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;127128 await helper.wait.forParachainBlockNumber(executionBlock);129130 const bobsBalanceAfterFirst = await helper.balance.getSubstrate(bob.address);131132 expect(bobsBalanceAfterFirst)133 .to.be.equal(134 bobsBalanceBefore + 1n * amount,135 '#1 Balance of the recipient should be increased by 1 * amount',136 );137138 await helper.scheduler.cancelScheduled(alice, scheduledId);139 await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);140141 const bobsBalanceAfterSecond = await helper.balance.getSubstrate(bob.address);142 expect(bobsBalanceAfterSecond)143 .to.be.equal(144 bobsBalanceAfterFirst,145 '#2 Balance of the recipient should not be changed',146 );147 });148149 itSub('scheduler will not insert more tasks than allowed', async ({helper}) => {150 const maxScheduledPerBlock = 50;151 const scheduledIds = await helper.arrange.makeScheduledIds(maxScheduledPerBlock + 1);152 const fillScheduledIds = scheduledIds.slice(0, maxScheduledPerBlock);153 const extraScheduledId = scheduledIds[maxScheduledPerBlock];154155 156 157 158 159 160 161 const waitForBlocks = await helper.arrange.isDevNode() ? maxScheduledPerBlock + 5 : 5;162163 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks;164165 const amount = 1n * helper.balance.getOneTokenNominal();166167 const balanceBefore = await helper.balance.getSubstrate(bob.address);168169 170 for (let i = 0; i < maxScheduledPerBlock; i++) {171 await helper.scheduler.scheduleAt(fillScheduledIds[i], executionBlock)172 .balance.transferToSubstrate(superuser, bob.address, amount);173 }174175 176 await expect(helper.scheduler.scheduleAt(extraScheduledId, executionBlock)177 .balance.transferToSubstrate(superuser, bob.address, amount))178 .to.be.rejectedWith(/scheduler\.AgendaIsExhausted/);179180 await helper.wait.forParachainBlockNumber(executionBlock);181182 const balanceAfter = await helper.balance.getSubstrate(bob.address);183184 expect(balanceAfter > balanceBefore).to.be.true;185186 const diff = balanceAfter - balanceBefore;187 expect(diff).to.be.equal(amount * BigInt(maxScheduledPerBlock));188 });189190 itSub.ifWithPallets('Scheduled tasks are transactional', [Pallets.TestUtils], async ({helper}) => {191 const scheduledId = await helper.arrange.makeScheduledId();192 const waitForBlocks = 4;193194 const initTestVal = 42;195 const changedTestVal = 111;196197 await helper.testUtils.setTestValue(alice, initTestVal);198199 await helper.scheduler.scheduleAfter<DevUniqueHelper>(scheduledId, waitForBlocks)200 .testUtils.setTestValueAndRollback(alice, changedTestVal);201 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;202203 await helper.wait.forParachainBlockNumber(executionBlock);204205 const testVal = await helper.testUtils.testValue();206 expect(testVal, 'The test value should NOT be commited')207 .to.be.equal(initTestVal);208 });209210 itSub.ifWithPallets('Scheduled tasks should take correct fees', [Pallets.TestUtils], async function({helper}) {211 const scheduledId = await helper.arrange.makeScheduledId();212 const waitForBlocks = 4;213 const periodic = {214 period: 2,215 repetitions: 2,216 };217218 const dummyTx = helper.constructApiCall('api.tx.testUtils.justTakeFee', []);219 const scheduledLen = dummyTx.callIndex.length;220221 const expectedScheduledFee = (await helper.getPaymentInfo(alice, dummyTx, scheduledLen))222 .partialFee.toBigInt();223224 await helper.scheduler.scheduleAfter<DevUniqueHelper>(scheduledId, waitForBlocks, {periodic})225 .testUtils.justTakeFee(alice);226 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;227228 const aliceInitBalance = await helper.balance.getSubstrate(alice.address);229 let diff;230231 await helper.wait.forParachainBlockNumber(executionBlock);232233 const aliceBalanceAfterFirst = await helper.balance.getSubstrate(alice.address);234 expect(235 aliceBalanceAfterFirst < aliceInitBalance,236 '[after execution #1] Scheduled task should take a fee',237 ).to.be.true;238239 diff = aliceInitBalance - aliceBalanceAfterFirst;240 expect(diff).to.be.equal(241 expectedScheduledFee,242 'Scheduled task should take the right amount of fees',243 );244245 await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);246247 const aliceBalanceAfterSecond = await helper.balance.getSubstrate(alice.address);248 expect(249 aliceBalanceAfterSecond < aliceBalanceAfterFirst,250 '[after execution #2] Scheduled task should take a fee',251 ).to.be.true;252253 diff = aliceBalanceAfterFirst - aliceBalanceAfterSecond;254 expect(diff).to.be.equal(255 expectedScheduledFee,256 'Scheduled task should take the right amount of fees',257 );258 });259260 261 262 itSub.ifWithPallets('Can cancel the periodic sheduled tx when the tx is running', [Pallets.TestUtils], async ({helper}) => {263 const currentBlockNumber = await helper.chain.getLatestBlockNumber();264 const blocksBeforeExecution = 10;265 const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;266267 const [268 scheduledId,269 scheduledCancelId,270 ] = await helper.arrange.makeScheduledIds(2);271272 const periodic = {273 period: 5,274 repetitions: 5,275 };276277 const initTestVal = 0;278 const incTestVal = initTestVal + 1;279 const finalTestVal = initTestVal + 2;280281 await helper.testUtils.setTestValue(alice, initTestVal);282283 await helper.scheduler.scheduleAt<DevUniqueHelper>(scheduledId, firstExecutionBlockNumber, {periodic})284 .testUtils.incTestValue(alice);285286 287 288 await helper.scheduler.scheduleAt(289 scheduledCancelId,290 firstExecutionBlockNumber + periodic.period,291 ).scheduler.cancelScheduled(alice, scheduledId);292293 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);294295 296 expect(await helper.testUtils.testValue())297 .to.be.equal(incTestVal);298299 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period);300301 302 expect(await helper.testUtils.testValue())303 .to.be.equal(finalTestVal);304305 for (let i = 1; i < periodic.repetitions; i++) {306 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period * (i + 1));307 expect(await helper.testUtils.testValue())308 .to.be.equal(finalTestVal);309 }310 });311312 itSub.ifWithPallets('A scheduled operation can cancel itself', [Pallets.TestUtils], async ({helper}) => {313 const scheduledId = await helper.arrange.makeScheduledId();314 const waitForBlocks = 4;315 const periodic = {316 period: 2,317 repetitions: 5,318 };319320 const initTestVal = 0;321 const maxTestVal = 2;322323 await helper.testUtils.setTestValue(alice, initTestVal);324325 await helper.scheduler.scheduleAfter<DevUniqueHelper>(scheduledId, waitForBlocks, {periodic})326 .testUtils.selfCancelingInc(alice, scheduledId, maxTestVal);327 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;328329 await helper.wait.forParachainBlockNumber(executionBlock);330331 332 expect(await helper.testUtils.testValue())333 .to.be.equal(initTestVal + 1);334335 await helper.wait.forParachainBlockNumber(executionBlock + periodic.period);336337 338 expect(await helper.testUtils.testValue())339 .to.be.equal(initTestVal + 2);340341 await helper.wait.forParachainBlockNumber(executionBlock + 2 * periodic.period);342343 344 expect(await helper.testUtils.testValue())345 .to.be.equal(initTestVal + 2);346 });347348 itSub('Root can cancel any scheduled operation', async ({helper}) => {349 const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});350 const token = await collection.mintToken(bob);351352 const scheduledId = await helper.arrange.makeScheduledId();353 const waitForBlocks = 4;354355 await token.scheduleAfter(scheduledId, waitForBlocks)356 .transfer(bob, {Substrate: alice.address});357 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;358359 await helper.getSudo().scheduler.cancelScheduled(superuser, scheduledId);360361 await helper.wait.forParachainBlockNumber(executionBlock);362363 expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});364 });365366 itSub('Root can set prioritized scheduled operation', async ({helper}) => {367 const scheduledId = await helper.arrange.makeScheduledId();368 const waitForBlocks = 4;369370 const amount = 42n * helper.balance.getOneTokenNominal();371372 const balanceBefore = await helper.balance.getSubstrate(charlie.address);373374 await helper.getSudo()375 .scheduler.scheduleAfter(scheduledId, waitForBlocks, {priority: 42})376 .balance.forceTransferToSubstrate(superuser, bob.address, charlie.address, amount);377 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;378379 await helper.wait.forParachainBlockNumber(executionBlock);380381 const balanceAfter = await helper.balance.getSubstrate(charlie.address);382383 expect(balanceAfter > balanceBefore).to.be.true;384385 const diff = balanceAfter - balanceBefore;386 expect(diff).to.be.equal(amount);387 });388389 itSub("Root can change scheduled operation's priority", async ({helper}) => {390 const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});391 const token = await collection.mintToken(bob);392393 const scheduledId = await helper.arrange.makeScheduledId();394 const waitForBlocks = 6;395396 await token.scheduleAfter(scheduledId, waitForBlocks)397 .transfer(bob, {Substrate: alice.address});398 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;399400 const priority = 112;401 await helper.getSudo().scheduler.changePriority(superuser, scheduledId, priority);402403 const priorityChanged = await helper.wait.event(404 waitForBlocks,405 'scheduler',406 'PriorityChanged',407 );408409 expect(priorityChanged !== null).to.be.true;410411 const [blockNumber, index] = priorityChanged!.event.data[0].toJSON() as any[];412 expect(blockNumber).to.be.equal(executionBlock);413 expect(index).to.be.equal(0);414415 expect(priorityChanged!.event.data[1].toString()).to.be.equal(priority.toString());416 });417418 itSub('Prioritized operations execute in valid order', async ({helper}) => {419 const [420 scheduledFirstId,421 scheduledSecondId,422 ] = await helper.arrange.makeScheduledIds(2);423424 const currentBlockNumber = await helper.chain.getLatestBlockNumber();425 const blocksBeforeExecution = 6;426 const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;427428 const prioHigh = 0;429 const prioLow = 255;430431 const periodic = {432 period: 6,433 repetitions: 2,434 };435436 const amount = 1n * helper.balance.getOneTokenNominal();437438 439 await helper.getSudo().scheduler.scheduleAt(scheduledFirstId, firstExecutionBlockNumber, {priority: prioLow, periodic})440 .balance.forceTransferToSubstrate(superuser, alice.address, bob.address, amount);441442 await helper.getSudo().scheduler.scheduleAt(scheduledSecondId, firstExecutionBlockNumber, {priority: prioHigh, periodic})443 .balance.forceTransferToSubstrate(superuser, alice.address, bob.address, amount);444445 const capture = await helper.arrange.captureEvents('scheduler', 'Dispatched');446447 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);448449 450 await helper.getSudo().scheduler.changePriority(superuser, scheduledFirstId, prioHigh);451 await helper.getSudo().scheduler.changePriority(superuser, scheduledSecondId, prioLow);452453 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + periodic.period);454455 const dispatchEvents = capture.extractCapturedEvents();456 expect(dispatchEvents.length).to.be.equal(4);457458 const dispatchedIds = dispatchEvents.map(r => r.event.data[1].toString());459460 const firstExecuctionIds = [dispatchedIds[0], dispatchedIds[1]];461 const secondExecuctionIds = [dispatchedIds[2], dispatchedIds[3]];462463 expect(firstExecuctionIds[0]).to.be.equal(scheduledSecondId);464 expect(firstExecuctionIds[1]).to.be.equal(scheduledFirstId);465466 expect(secondExecuctionIds[0]).to.be.equal(scheduledFirstId);467 expect(secondExecuctionIds[1]).to.be.equal(scheduledSecondId);468 });469470 itSub('Periodic operations always can be rescheduled', async ({helper}) => {471 const maxScheduledPerBlock = 50;472 const numFilledBlocks = 3;473 const ids = await helper.arrange.makeScheduledIds(numFilledBlocks * maxScheduledPerBlock + 1);474 const periodicId = ids[0];475 const fillIds = ids.slice(1);476477 const initTestVal = 0;478 const firstExecTestVal = 1;479 const secondExecTestVal = 2;480 await helper.testUtils.setTestValue(alice, initTestVal);481482 const currentBlockNumber = await helper.chain.getLatestBlockNumber();483 const blocksBeforeExecution = 8;484 const firstExecutionBlockNumber = currentBlockNumber + blocksBeforeExecution;485486 const period = 5;487488 const periodic = {489 period,490 repetitions: 2,491 };492493 494 const txs = [];495 for (let offset = 0; offset < numFilledBlocks; offset ++) {496 for (let i = 0; i < maxScheduledPerBlock; i++) {497498 const scheduledTx = helper.constructApiCall('api.tx.balances.transfer', [bob.address, 1n]);499500 const when = firstExecutionBlockNumber + period + offset;501 const tx = helper.constructApiCall('api.tx.scheduler.scheduleNamed', [fillIds[i + offset * maxScheduledPerBlock], when, null, null, scheduledTx]);502503 txs.push(tx);504 }505 }506 await helper.executeExtrinsic(alice, 'api.tx.testUtils.batchAll', [txs], true);507508 await helper.scheduler.scheduleAt<DevUniqueHelper>(periodicId, firstExecutionBlockNumber, {periodic})509 .testUtils.incTestValue(alice);510511 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber);512 expect(await helper.testUtils.testValue()).to.be.equal(firstExecTestVal);513514 await helper.wait.forParachainBlockNumber(firstExecutionBlockNumber + period + numFilledBlocks);515516 517 for (let i = 0; i < numFilledBlocks; i++) {518 expect(await helper.testUtils.testValue(firstExecutionBlockNumber + period + i)).to.be.equal(firstExecTestVal);519 }520521 522 expect(await helper.testUtils.testValue()).to.be.equal(secondExecTestVal);523 });524525 itSub('scheduled operations does not change nonce', async ({helper}) => {526 const scheduledId = await helper.arrange.makeScheduledId();527 const blocksBeforeExecution = 4;528529 await helper.scheduler530 .scheduleAfter<DevUniqueHelper>(scheduledId, blocksBeforeExecution)531 .balance.transferToSubstrate(alice, bob.address, 1n);532 const executionBlock = await helper.chain.getLatestBlockNumber() + blocksBeforeExecution + 1;533534 const initNonce = await helper.chain.getNonce(alice.address);535536 await helper.wait.forParachainBlockNumber(executionBlock);537538 const finalNonce = await helper.chain.getNonce(alice.address);539540 expect(initNonce).to.be.equal(finalNonce);541 });542});543544describe('Negative Test: Scheduling', () => {545 let alice: IKeyringPair;546 let bob: IKeyringPair;547548 before(async function() {549 await usingPlaygrounds(async (helper, privateKey) => {550 requirePalletsOrSkip(this, helper, [Pallets.Scheduler]);551552 const donor = await privateKey({filename: __filename});553 [alice, bob] = await helper.arrange.createAccounts([100n, 100n], donor);554555 await helper.testUtils.enable();556 });557 });558559 itSub("Can't overwrite a scheduled ID", async ({helper}) => {560 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});561 const token = await collection.mintToken(alice);562563 const scheduledId = await helper.arrange.makeScheduledId();564 const waitForBlocks = 4;565566 await token.scheduleAfter(scheduledId, waitForBlocks)567 .transfer(alice, {Substrate: bob.address});568 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;569570 const scheduled = helper.scheduler.scheduleAfter(scheduledId, waitForBlocks);571 await expect(scheduled.balance.transferToSubstrate(alice, bob.address, 1n * helper.balance.getOneTokenNominal()))572 .to.be.rejectedWith(/scheduler\.FailedToSchedule/);573574 const bobsBalanceBefore = await helper.balance.getSubstrate(bob.address);575576 await helper.wait.forParachainBlockNumber(executionBlock);577578 const bobsBalanceAfter = await helper.balance.getSubstrate(bob.address);579580 expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});581 expect(bobsBalanceBefore).to.be.equal(bobsBalanceAfter);582 });583584 itSub("Can't cancel an operation which is not scheduled", async ({helper}) => {585 const scheduledId = await helper.arrange.makeScheduledId();586 await expect(helper.scheduler.cancelScheduled(alice, scheduledId))587 .to.be.rejectedWith(/scheduler\.NotFound/);588 });589590 itSub("Can't cancel a non-owned scheduled operation", async ({helper}) => {591 const collection = await helper.nft.mintCollection(alice, {tokenPrefix: 'schd'});592 const token = await collection.mintToken(alice);593594 const scheduledId = await helper.arrange.makeScheduledId();595 const waitForBlocks = 4;596597 await token.scheduleAfter(scheduledId, waitForBlocks)598 .transfer(alice, {Substrate: bob.address});599 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;600601 await expect(helper.scheduler.cancelScheduled(bob, scheduledId))602 .to.be.rejectedWith(/BadOrigin/);603604 await helper.wait.forParachainBlockNumber(executionBlock);605606 expect(await token.getOwner()).to.be.deep.equal({Substrate: bob.address});607 });608609 itSub("Regular user can't set prioritized scheduled operation", async ({helper}) => {610 const scheduledId = await helper.arrange.makeScheduledId();611 const waitForBlocks = 4;612613 const amount = 42n * helper.balance.getOneTokenNominal();614615 const balanceBefore = await helper.balance.getSubstrate(bob.address);616617 const scheduled = helper.scheduler.scheduleAfter(scheduledId, waitForBlocks, {priority: 42});618 619 await expect(scheduled.balance.transferToSubstrate(alice, bob.address, amount))620 .to.be.rejectedWith(/BadOrigin/);621622 const executionBlock = await helper.chain.getLatestBlockNumber() + waitForBlocks + 1;623624 await helper.wait.forParachainBlockNumber(executionBlock);625626 const balanceAfter = await helper.balance.getSubstrate(bob.address);627628 expect(balanceAfter).to.be.equal(balanceBefore);629 });630631 itSub("Regular user can't change scheduled operation's priority", async ({helper}) => {632 const collection = await helper.nft.mintCollection(bob, {tokenPrefix: 'schd'});633 const token = await collection.mintToken(bob);634635 const scheduledId = await helper.arrange.makeScheduledId();636 const waitForBlocks = 4;637638 await token.scheduleAfter(scheduledId, waitForBlocks)639 .transfer(bob, {Substrate: alice.address});640641 const priority = 112;642 await expect(helper.scheduler.changePriority(alice, scheduledId, priority))643 .to.be.rejectedWith(/BadOrigin/);644645 const priorityChanged = await helper.wait.event(646 waitForBlocks,647 'scheduler',648 'PriorityChanged',649 );650651 expect(priorityChanged === null).to.be.true;652 });653});654655656describe.skip('Sponsoring scheduling', () => {657 658 659660 661 662 663 664 665 666667 it('Can sponsor scheduling a transaction', async () => {668 669 670 671672 673 674 675676 677 678 679 680 681 682 683 684 685 686 });687688 it('Schedules and dispatches a transaction even if the caller has no funds at the time of the dispatch', async () => {689 690 691 692693 694695 696 697 698699 700 701 702703 704 705 706707 708 709 710711 712 713 714 715 716 717 718 719720 721 722723 724 725 });726727 it('Sponsor going bankrupt does not impact a scheduled transaction', async () => {728 729730 731 732 733 734735 736 737738 739 740741 742 743744 745 746 747 748749 750 751752 753 754 });755756 it('Exceeding sponsor rate limit without having enough funds prevents scheduling a periodic transaction', async () => {757 758 759 760761 762 763764 765 766767 768769 770 771 772773 774 775 776 777778 779780 781 782 });783});