TimelockController.test.js 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997
  1. const { accounts, contract, web3, config } = require('@openzeppelin/test-environment');
  2. const { constants, expectEvent, expectRevert, time } = require('@openzeppelin/test-helpers');
  3. const { ZERO_BYTES32 } = constants;
  4. const { expect } = require('chai');
  5. const TimelockController = contract.fromArtifact('TimelockController');
  6. const CallReceiverMock = contract.fromArtifact('CallReceiverMock');
  7. const Implementation2 = contract.fromArtifact('Implementation2');
  8. const MINDELAY = time.duration.days(1);
  9. function genOperation (target, value, data, predecessor, salt) {
  10. const id = web3.utils.keccak256(web3.eth.abi.encodeParameters([
  11. 'address',
  12. 'uint256',
  13. 'bytes',
  14. 'uint256',
  15. 'bytes32',
  16. ], [
  17. target,
  18. value,
  19. data,
  20. predecessor,
  21. salt,
  22. ]));
  23. return { id, target, value, data, predecessor, salt };
  24. }
  25. function genOperationBatch (targets, values, datas, predecessor, salt) {
  26. const id = web3.utils.keccak256(web3.eth.abi.encodeParameters([
  27. 'address[]',
  28. 'uint256[]',
  29. 'bytes[]',
  30. 'uint256',
  31. 'bytes32',
  32. ], [
  33. targets,
  34. values,
  35. datas,
  36. predecessor,
  37. salt,
  38. ]));
  39. return { id, targets, values, datas, predecessor, salt };
  40. }
  41. describe('TimelockController', function () {
  42. const [ admin, proposer, executor, other ] = accounts;
  43. beforeEach(async function () {
  44. // Deploy new timelock
  45. this.timelock = await TimelockController.new(
  46. MINDELAY,
  47. [ proposer ],
  48. [ executor ],
  49. { from: admin },
  50. );
  51. // Mocks
  52. this.callreceivermock = await CallReceiverMock.new({ from: admin });
  53. this.implementation2 = await Implementation2.new({ from: admin });
  54. });
  55. it('initial state', async function () {
  56. expect(await this.timelock.getMinDelay()).to.be.bignumber.equal(MINDELAY);
  57. });
  58. describe('methods', function () {
  59. describe('operation hashing', function () {
  60. it('hashOperation', async function () {
  61. this.operation = genOperation(
  62. '0x29cebefe301c6ce1bb36b58654fea275e1cacc83',
  63. '0xf94fdd6e21da21d2',
  64. '0xa3bc5104',
  65. '0xba41db3be0a9929145cfe480bd0f1f003689104d275ae912099f925df424ef94',
  66. '0x60d9109846ab510ed75c15f979ae366a8a2ace11d34ba9788c13ac296db50e6e',
  67. );
  68. expect(await this.timelock.hashOperation(
  69. this.operation.target,
  70. this.operation.value,
  71. this.operation.data,
  72. this.operation.predecessor,
  73. this.operation.salt,
  74. )).to.be.equal(this.operation.id);
  75. });
  76. it('hashOperationBatch', async function () {
  77. this.operation = genOperationBatch(
  78. Array(8).fill('0x2d5f21620e56531c1d59c2df9b8e95d129571f71'),
  79. Array(8).fill('0x2b993cfce932ccee'),
  80. Array(8).fill('0xcf51966b'),
  81. '0xce8f45069cc71d25f71ba05062de1a3974f9849b004de64a70998bca9d29c2e7',
  82. '0x8952d74c110f72bfe5accdf828c74d53a7dfb71235dfa8a1e8c75d8576b372ff',
  83. );
  84. expect(await this.timelock.hashOperationBatch(
  85. this.operation.targets,
  86. this.operation.values,
  87. this.operation.datas,
  88. this.operation.predecessor,
  89. this.operation.salt,
  90. )).to.be.equal(this.operation.id);
  91. });
  92. });
  93. describe('simple', function () {
  94. describe('schedule', function () {
  95. beforeEach(async function () {
  96. this.operation = genOperation(
  97. '0x31754f590B97fD975Eb86938f18Cc304E264D2F2',
  98. 0,
  99. '0x3bf92ccc',
  100. ZERO_BYTES32,
  101. '0x025e7b0be353a74631ad648c667493c0e1cd31caa4cc2d3520fdc171ea0cc726',
  102. );
  103. });
  104. it('proposer can schedule', async function () {
  105. const receipt = await this.timelock.schedule(
  106. this.operation.target,
  107. this.operation.value,
  108. this.operation.data,
  109. this.operation.predecessor,
  110. this.operation.salt,
  111. MINDELAY,
  112. { from: proposer },
  113. );
  114. expectEvent(receipt, 'CallScheduled', {
  115. id: this.operation.id,
  116. index: web3.utils.toBN(0),
  117. target: this.operation.target,
  118. value: web3.utils.toBN(this.operation.value),
  119. data: this.operation.data,
  120. predecessor: this.operation.predecessor,
  121. delay: MINDELAY,
  122. });
  123. const block = await web3.eth.getBlock(receipt.receipt.blockHash);
  124. expect(await this.timelock.getTimestamp(this.operation.id))
  125. .to.be.bignumber.equal(web3.utils.toBN(block.timestamp).add(MINDELAY));
  126. });
  127. it('prevent overwritting active operation', async function () {
  128. await this.timelock.schedule(
  129. this.operation.target,
  130. this.operation.value,
  131. this.operation.data,
  132. this.operation.predecessor,
  133. this.operation.salt,
  134. MINDELAY,
  135. { from: proposer },
  136. );
  137. await expectRevert(
  138. this.timelock.schedule(
  139. this.operation.target,
  140. this.operation.value,
  141. this.operation.data,
  142. this.operation.predecessor,
  143. this.operation.salt,
  144. MINDELAY,
  145. { from: proposer },
  146. ),
  147. 'TimelockController: operation already scheduled',
  148. );
  149. });
  150. it('prevent non-proposer from commiting', async function () {
  151. await expectRevert(
  152. this.timelock.schedule(
  153. this.operation.target,
  154. this.operation.value,
  155. this.operation.data,
  156. this.operation.predecessor,
  157. this.operation.salt,
  158. MINDELAY,
  159. { from: other },
  160. ),
  161. 'TimelockController: sender requires permission',
  162. );
  163. });
  164. it('enforce minimum delay', async function () {
  165. await expectRevert(
  166. this.timelock.schedule(
  167. this.operation.target,
  168. this.operation.value,
  169. this.operation.data,
  170. this.operation.predecessor,
  171. this.operation.salt,
  172. MINDELAY - 1,
  173. { from: proposer },
  174. ),
  175. 'TimelockController: insufficient delay',
  176. );
  177. });
  178. });
  179. describe('execute', function () {
  180. beforeEach(async function () {
  181. this.operation = genOperation(
  182. '0xAe22104DCD970750610E6FE15E623468A98b15f7',
  183. 0,
  184. '0x13e414de',
  185. ZERO_BYTES32,
  186. '0xc1059ed2dc130227aa1d1d539ac94c641306905c020436c636e19e3fab56fc7f',
  187. );
  188. });
  189. it('revert if operation is not scheduled', async function () {
  190. await expectRevert(
  191. this.timelock.execute(
  192. this.operation.target,
  193. this.operation.value,
  194. this.operation.data,
  195. this.operation.predecessor,
  196. this.operation.salt,
  197. { from: executor },
  198. ),
  199. 'TimelockController: operation is not ready',
  200. );
  201. });
  202. describe('with scheduled operation', function () {
  203. beforeEach(async function () {
  204. ({ receipt: this.receipt, logs: this.logs } = await this.timelock.schedule(
  205. this.operation.target,
  206. this.operation.value,
  207. this.operation.data,
  208. this.operation.predecessor,
  209. this.operation.salt,
  210. MINDELAY,
  211. { from: proposer },
  212. ));
  213. });
  214. it('revert if execution comes too early 1/2', async function () {
  215. await expectRevert(
  216. this.timelock.execute(
  217. this.operation.target,
  218. this.operation.value,
  219. this.operation.data,
  220. this.operation.predecessor,
  221. this.operation.salt,
  222. { from: executor },
  223. ),
  224. 'TimelockController: operation is not ready',
  225. );
  226. });
  227. it('revert if execution comes too early 2/2', async function () {
  228. const timestamp = await this.timelock.getTimestamp(this.operation.id);
  229. await time.increaseTo(timestamp - 2); // -1 is too tight, test sometime fails
  230. await expectRevert(
  231. this.timelock.execute(
  232. this.operation.target,
  233. this.operation.value,
  234. this.operation.data,
  235. this.operation.predecessor,
  236. this.operation.salt,
  237. { from: executor },
  238. ),
  239. 'TimelockController: operation is not ready',
  240. );
  241. });
  242. describe('on time', function () {
  243. beforeEach(async function () {
  244. const timestamp = await this.timelock.getTimestamp(this.operation.id);
  245. await time.increaseTo(timestamp);
  246. });
  247. it('executor can reveal', async function () {
  248. const receipt = await this.timelock.execute(
  249. this.operation.target,
  250. this.operation.value,
  251. this.operation.data,
  252. this.operation.predecessor,
  253. this.operation.salt,
  254. { from: executor },
  255. );
  256. expectEvent(receipt, 'CallExecuted', {
  257. id: this.operation.id,
  258. index: web3.utils.toBN(0),
  259. target: this.operation.target,
  260. value: web3.utils.toBN(this.operation.value),
  261. data: this.operation.data,
  262. });
  263. });
  264. it('prevent non-executor from revealing', async function () {
  265. await expectRevert(
  266. this.timelock.execute(
  267. this.operation.target,
  268. this.operation.value,
  269. this.operation.data,
  270. this.operation.predecessor,
  271. this.operation.salt,
  272. { from: other },
  273. ),
  274. 'TimelockController: sender requires permission',
  275. );
  276. });
  277. });
  278. });
  279. });
  280. });
  281. describe('batch', function () {
  282. describe('schedule', function () {
  283. beforeEach(async function () {
  284. this.operation = genOperationBatch(
  285. Array(8).fill('0xEd912250835c812D4516BBD80BdaEA1bB63a293C'),
  286. Array(8).fill(0),
  287. Array(8).fill('0x2fcb7a88'),
  288. ZERO_BYTES32,
  289. '0x6cf9d042ade5de78bed9ffd075eb4b2a4f6b1736932c2dc8af517d6e066f51f5',
  290. );
  291. });
  292. it('proposer can schedule', async function () {
  293. const receipt = await this.timelock.scheduleBatch(
  294. this.operation.targets,
  295. this.operation.values,
  296. this.operation.datas,
  297. this.operation.predecessor,
  298. this.operation.salt,
  299. MINDELAY,
  300. { from: proposer },
  301. );
  302. for (const i in this.operation.targets) {
  303. expectEvent(receipt, 'CallScheduled', {
  304. id: this.operation.id,
  305. index: web3.utils.toBN(i),
  306. target: this.operation.targets[i],
  307. value: web3.utils.toBN(this.operation.values[i]),
  308. data: this.operation.datas[i],
  309. predecessor: this.operation.predecessor,
  310. delay: MINDELAY,
  311. });
  312. }
  313. const block = await web3.eth.getBlock(receipt.receipt.blockHash);
  314. expect(await this.timelock.getTimestamp(this.operation.id))
  315. .to.be.bignumber.equal(web3.utils.toBN(block.timestamp).add(MINDELAY));
  316. });
  317. it('prevent overwritting active operation', async function () {
  318. await this.timelock.scheduleBatch(
  319. this.operation.targets,
  320. this.operation.values,
  321. this.operation.datas,
  322. this.operation.predecessor,
  323. this.operation.salt,
  324. MINDELAY,
  325. { from: proposer },
  326. );
  327. await expectRevert(
  328. this.timelock.scheduleBatch(
  329. this.operation.targets,
  330. this.operation.values,
  331. this.operation.datas,
  332. this.operation.predecessor,
  333. this.operation.salt,
  334. MINDELAY,
  335. { from: proposer },
  336. ),
  337. 'TimelockController: operation already scheduled',
  338. );
  339. });
  340. it('prevent non-proposer from commiting', async function () {
  341. await expectRevert(
  342. this.timelock.scheduleBatch(
  343. this.operation.targets,
  344. this.operation.values,
  345. this.operation.datas,
  346. this.operation.predecessor,
  347. this.operation.salt,
  348. MINDELAY,
  349. { from: other },
  350. ),
  351. 'TimelockController: sender requires permission',
  352. );
  353. });
  354. it('enforce minimum delay', async function () {
  355. await expectRevert(
  356. this.timelock.scheduleBatch(
  357. this.operation.targets,
  358. this.operation.values,
  359. this.operation.datas,
  360. this.operation.predecessor,
  361. this.operation.salt,
  362. MINDELAY - 1,
  363. { from: proposer },
  364. ),
  365. 'TimelockController: insufficient delay',
  366. );
  367. });
  368. });
  369. describe('execute', function () {
  370. beforeEach(async function () {
  371. this.operation = genOperationBatch(
  372. Array(8).fill('0x76E53CcEb05131Ef5248553bEBDb8F70536830b1'),
  373. Array(8).fill(0),
  374. Array(8).fill('0x58a60f63'),
  375. ZERO_BYTES32,
  376. '0x9545eeabc7a7586689191f78a5532443698538e54211b5bd4d7dc0fc0102b5c7',
  377. );
  378. });
  379. it('revert if operation is not scheduled', async function () {
  380. await expectRevert(
  381. this.timelock.executeBatch(
  382. this.operation.targets,
  383. this.operation.values,
  384. this.operation.datas,
  385. this.operation.predecessor,
  386. this.operation.salt,
  387. { from: executor },
  388. ),
  389. 'TimelockController: operation is not ready',
  390. );
  391. });
  392. describe('with scheduled operation', function () {
  393. beforeEach(async function () {
  394. ({ receipt: this.receipt, logs: this.logs } = await this.timelock.scheduleBatch(
  395. this.operation.targets,
  396. this.operation.values,
  397. this.operation.datas,
  398. this.operation.predecessor,
  399. this.operation.salt,
  400. MINDELAY,
  401. { from: proposer },
  402. ));
  403. });
  404. it('revert if execution comes too early 1/2', async function () {
  405. await expectRevert(
  406. this.timelock.executeBatch(
  407. this.operation.targets,
  408. this.operation.values,
  409. this.operation.datas,
  410. this.operation.predecessor,
  411. this.operation.salt,
  412. { from: executor },
  413. ),
  414. 'TimelockController: operation is not ready',
  415. );
  416. });
  417. it('revert if execution comes too early 2/2', async function () {
  418. const timestamp = await this.timelock.getTimestamp(this.operation.id);
  419. await time.increaseTo(timestamp - 2); // -1 is to tight, test sometime fails
  420. await expectRevert(
  421. this.timelock.executeBatch(
  422. this.operation.targets,
  423. this.operation.values,
  424. this.operation.datas,
  425. this.operation.predecessor,
  426. this.operation.salt,
  427. { from: executor },
  428. ),
  429. 'TimelockController: operation is not ready',
  430. );
  431. });
  432. describe('on time', function () {
  433. beforeEach(async function () {
  434. const timestamp = await this.timelock.getTimestamp(this.operation.id);
  435. await time.increaseTo(timestamp);
  436. });
  437. it('executor can reveal', async function () {
  438. const receipt = await this.timelock.executeBatch(
  439. this.operation.targets,
  440. this.operation.values,
  441. this.operation.datas,
  442. this.operation.predecessor,
  443. this.operation.salt,
  444. { from: executor },
  445. );
  446. for (const i in this.operation.targets) {
  447. expectEvent(receipt, 'CallExecuted', {
  448. id: this.operation.id,
  449. index: web3.utils.toBN(i),
  450. target: this.operation.targets[i],
  451. value: web3.utils.toBN(this.operation.values[i]),
  452. data: this.operation.datas[i],
  453. });
  454. }
  455. });
  456. it('prevent non-executor from revealing', async function () {
  457. await expectRevert(
  458. this.timelock.executeBatch(
  459. this.operation.targets,
  460. this.operation.values,
  461. this.operation.datas,
  462. this.operation.predecessor,
  463. this.operation.salt,
  464. { from: other },
  465. ),
  466. 'TimelockController: sender requires permission',
  467. );
  468. });
  469. it('length mismatch #1', async function () {
  470. await expectRevert(
  471. this.timelock.executeBatch(
  472. [],
  473. this.operation.values,
  474. this.operation.datas,
  475. this.operation.predecessor,
  476. this.operation.salt,
  477. { from: executor },
  478. ),
  479. 'TimelockController: length mismatch',
  480. );
  481. });
  482. it('length mismatch #2', async function () {
  483. await expectRevert(
  484. this.timelock.executeBatch(
  485. this.operation.targets,
  486. [],
  487. this.operation.datas,
  488. this.operation.predecessor,
  489. this.operation.salt,
  490. { from: executor },
  491. ),
  492. 'TimelockController: length mismatch',
  493. );
  494. });
  495. it('length mismatch #3', async function () {
  496. await expectRevert(
  497. this.timelock.executeBatch(
  498. this.operation.targets,
  499. this.operation.values,
  500. [],
  501. this.operation.predecessor,
  502. this.operation.salt,
  503. { from: executor },
  504. ),
  505. 'TimelockController: length mismatch',
  506. );
  507. });
  508. });
  509. });
  510. it('partial execution', async function () {
  511. const operation = genOperationBatch(
  512. [
  513. this.callreceivermock.address,
  514. this.callreceivermock.address,
  515. this.callreceivermock.address,
  516. ],
  517. [
  518. 0,
  519. 0,
  520. 0,
  521. ],
  522. [
  523. this.callreceivermock.contract.methods.mockFunction().encodeABI(),
  524. this.callreceivermock.contract.methods.mockFunctionThrows().encodeABI(),
  525. this.callreceivermock.contract.methods.mockFunction().encodeABI(),
  526. ],
  527. ZERO_BYTES32,
  528. '0x8ac04aa0d6d66b8812fb41d39638d37af0a9ab11da507afd65c509f8ed079d3e',
  529. );
  530. await this.timelock.scheduleBatch(
  531. operation.targets,
  532. operation.values,
  533. operation.datas,
  534. operation.predecessor,
  535. operation.salt,
  536. MINDELAY,
  537. { from: proposer },
  538. );
  539. await time.increase(MINDELAY);
  540. await expectRevert(
  541. this.timelock.executeBatch(
  542. operation.targets,
  543. operation.values,
  544. operation.datas,
  545. operation.predecessor,
  546. operation.salt,
  547. { from: executor },
  548. ),
  549. 'TimelockController: underlying transaction reverted',
  550. );
  551. });
  552. });
  553. });
  554. describe('cancel', function () {
  555. beforeEach(async function () {
  556. this.operation = genOperation(
  557. '0xC6837c44AA376dbe1d2709F13879E040CAb653ca',
  558. 0,
  559. '0x296e58dd',
  560. ZERO_BYTES32,
  561. '0xa2485763600634800df9fc9646fb2c112cf98649c55f63dd1d9c7d13a64399d9',
  562. );
  563. ({ receipt: this.receipt, logs: this.logs } = await this.timelock.schedule(
  564. this.operation.target,
  565. this.operation.value,
  566. this.operation.data,
  567. this.operation.predecessor,
  568. this.operation.salt,
  569. MINDELAY,
  570. { from: proposer },
  571. ));
  572. });
  573. it('proposer can cancel', async function () {
  574. const receipt = await this.timelock.cancel(this.operation.id, { from: proposer });
  575. expectEvent(receipt, 'Cancelled', { id: this.operation.id });
  576. });
  577. it('prevent non-proposer from canceling', async function () {
  578. await expectRevert(
  579. this.timelock.cancel(this.operation.id, { from: other }),
  580. 'TimelockController: sender requires permission',
  581. );
  582. });
  583. });
  584. });
  585. describe('maintenance', function () {
  586. it('prevent unauthorized maintenance', async function () {
  587. await expectRevert(
  588. this.timelock.updateDelay(0, { from: other }),
  589. 'TimelockController: caller must be timelock',
  590. );
  591. });
  592. it('timelock scheduled maintenance', async function () {
  593. const newDelay = time.duration.hours(6);
  594. const operation = genOperation(
  595. this.timelock.address,
  596. 0,
  597. this.timelock.contract.methods.updateDelay(newDelay.toString()).encodeABI(),
  598. ZERO_BYTES32,
  599. '0xf8e775b2c5f4d66fb5c7fa800f35ef518c262b6014b3c0aee6ea21bff157f108',
  600. );
  601. await this.timelock.schedule(
  602. operation.target,
  603. operation.value,
  604. operation.data,
  605. operation.predecessor,
  606. operation.salt,
  607. MINDELAY,
  608. { from: proposer },
  609. );
  610. await time.increase(MINDELAY);
  611. const receipt = await this.timelock.execute(
  612. operation.target,
  613. operation.value,
  614. operation.data,
  615. operation.predecessor,
  616. operation.salt,
  617. { from: executor },
  618. );
  619. expectEvent(receipt, 'MinDelayChange', { newDuration: newDelay.toString(), oldDuration: MINDELAY });
  620. expect(await this.timelock.getMinDelay()).to.be.bignumber.equal(newDelay);
  621. });
  622. });
  623. describe('dependency', function () {
  624. beforeEach(async function () {
  625. this.operation1 = genOperation(
  626. '0xdE66bD4c97304200A95aE0AadA32d6d01A867E39',
  627. 0,
  628. '0x01dc731a',
  629. ZERO_BYTES32,
  630. '0x64e932133c7677402ead2926f86205e2ca4686aebecf5a8077627092b9bb2feb',
  631. );
  632. this.operation2 = genOperation(
  633. '0x3c7944a3F1ee7fc8c5A5134ba7c79D11c3A1FCa3',
  634. 0,
  635. '0x8f531849',
  636. this.operation1.id,
  637. '0x036e1311cac523f9548e6461e29fb1f8f9196b91910a41711ea22f5de48df07d',
  638. );
  639. await this.timelock.schedule(
  640. this.operation1.target,
  641. this.operation1.value,
  642. this.operation1.data,
  643. this.operation1.predecessor,
  644. this.operation1.salt,
  645. MINDELAY,
  646. { from: proposer },
  647. );
  648. await this.timelock.schedule(
  649. this.operation2.target,
  650. this.operation2.value,
  651. this.operation2.data,
  652. this.operation2.predecessor,
  653. this.operation2.salt,
  654. MINDELAY,
  655. { from: proposer },
  656. );
  657. await time.increase(MINDELAY);
  658. });
  659. it('cannot execute before dependency', async function () {
  660. await expectRevert(
  661. this.timelock.execute(
  662. this.operation2.target,
  663. this.operation2.value,
  664. this.operation2.data,
  665. this.operation2.predecessor,
  666. this.operation2.salt,
  667. { from: executor },
  668. ),
  669. 'TimelockController: missing dependency',
  670. );
  671. });
  672. it('can execute after dependency', async function () {
  673. await this.timelock.execute(
  674. this.operation1.target,
  675. this.operation1.value,
  676. this.operation1.data,
  677. this.operation1.predecessor,
  678. this.operation1.salt,
  679. { from: executor },
  680. );
  681. await this.timelock.execute(
  682. this.operation2.target,
  683. this.operation2.value,
  684. this.operation2.data,
  685. this.operation2.predecessor,
  686. this.operation2.salt,
  687. { from: executor },
  688. );
  689. });
  690. });
  691. describe('usage scenario', function () {
  692. this.timeout(10000);
  693. it('call', async function () {
  694. const operation = genOperation(
  695. this.implementation2.address,
  696. 0,
  697. this.implementation2.contract.methods.setValue(42).encodeABI(),
  698. ZERO_BYTES32,
  699. '0x8043596363daefc89977b25f9d9b4d06c3910959ef0c4d213557a903e1b555e2',
  700. );
  701. await this.timelock.schedule(
  702. operation.target,
  703. operation.value,
  704. operation.data,
  705. operation.predecessor,
  706. operation.salt,
  707. MINDELAY,
  708. { from: proposer },
  709. );
  710. await time.increase(MINDELAY);
  711. await this.timelock.execute(
  712. operation.target,
  713. operation.value,
  714. operation.data,
  715. operation.predecessor,
  716. operation.salt,
  717. { from: executor },
  718. );
  719. expect(await this.implementation2.getValue()).to.be.bignumber.equal(web3.utils.toBN(42));
  720. });
  721. it('call reverting', async function () {
  722. const operation = genOperation(
  723. this.callreceivermock.address,
  724. 0,
  725. this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(),
  726. ZERO_BYTES32,
  727. '0xb1b1b276fdf1a28d1e00537ea73b04d56639128b08063c1a2f70a52e38cba693',
  728. );
  729. await this.timelock.schedule(
  730. operation.target,
  731. operation.value,
  732. operation.data,
  733. operation.predecessor,
  734. operation.salt,
  735. MINDELAY,
  736. { from: proposer },
  737. );
  738. await time.increase(MINDELAY);
  739. await expectRevert(
  740. this.timelock.execute(
  741. operation.target,
  742. operation.value,
  743. operation.data,
  744. operation.predecessor,
  745. operation.salt,
  746. { from: executor },
  747. ),
  748. 'TimelockController: underlying transaction reverted',
  749. );
  750. });
  751. it('call throw', async function () {
  752. const operation = genOperation(
  753. this.callreceivermock.address,
  754. 0,
  755. this.callreceivermock.contract.methods.mockFunctionThrows().encodeABI(),
  756. ZERO_BYTES32,
  757. '0xe5ca79f295fc8327ee8a765fe19afb58f4a0cbc5053642bfdd7e73bc68e0fc67',
  758. );
  759. await this.timelock.schedule(
  760. operation.target,
  761. operation.value,
  762. operation.data,
  763. operation.predecessor,
  764. operation.salt,
  765. MINDELAY,
  766. { from: proposer },
  767. );
  768. await time.increase(MINDELAY);
  769. await expectRevert(
  770. this.timelock.execute(
  771. operation.target,
  772. operation.value,
  773. operation.data,
  774. operation.predecessor,
  775. operation.salt,
  776. { from: executor },
  777. ),
  778. 'TimelockController: underlying transaction reverted',
  779. );
  780. });
  781. // Skipped in a coverage mode due to coverage mode setting a block gas limit to 0xffffffffff
  782. // which cause a mockFunctionOutOfGas function to crash Ganache and the
  783. // subsequent tests before running out of gas.
  784. it('call out of gas', async function () {
  785. if (config.coverage) { return this.skip(); }
  786. const operation = genOperation(
  787. this.callreceivermock.address,
  788. 0,
  789. this.callreceivermock.contract.methods.mockFunctionOutOfGas().encodeABI(),
  790. ZERO_BYTES32,
  791. '0xf3274ce7c394c5b629d5215723563a744b817e1730cca5587c567099a14578fd',
  792. );
  793. await this.timelock.schedule(
  794. operation.target,
  795. operation.value,
  796. operation.data,
  797. operation.predecessor,
  798. operation.salt,
  799. MINDELAY,
  800. { from: proposer },
  801. );
  802. await time.increase(MINDELAY);
  803. await expectRevert(
  804. this.timelock.execute(
  805. operation.target,
  806. operation.value,
  807. operation.data,
  808. operation.predecessor,
  809. operation.salt,
  810. { from: executor },
  811. ),
  812. 'TimelockController: underlying transaction reverted',
  813. );
  814. });
  815. it('call payable with eth', async function () {
  816. const operation = genOperation(
  817. this.callreceivermock.address,
  818. 1,
  819. this.callreceivermock.contract.methods.mockFunction().encodeABI(),
  820. ZERO_BYTES32,
  821. '0x5ab73cd33477dcd36c1e05e28362719d0ed59a7b9ff14939de63a43073dc1f44',
  822. );
  823. await this.timelock.schedule(
  824. operation.target,
  825. operation.value,
  826. operation.data,
  827. operation.predecessor,
  828. operation.salt,
  829. MINDELAY,
  830. { from: proposer },
  831. );
  832. await time.increase(MINDELAY);
  833. expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  834. expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  835. await this.timelock.execute(
  836. operation.target,
  837. operation.value,
  838. operation.data,
  839. operation.predecessor,
  840. operation.salt,
  841. { from: executor, value: 1 },
  842. );
  843. expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  844. expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(1));
  845. });
  846. it('call nonpayable with eth', async function () {
  847. const operation = genOperation(
  848. this.callreceivermock.address,
  849. 1,
  850. this.callreceivermock.contract.methods.mockFunctionNonPayable().encodeABI(),
  851. ZERO_BYTES32,
  852. '0xb78edbd920c7867f187e5aa6294ae5a656cfbf0dea1ccdca3751b740d0f2bdf8',
  853. );
  854. await this.timelock.schedule(
  855. operation.target,
  856. operation.value,
  857. operation.data,
  858. operation.predecessor,
  859. operation.salt,
  860. MINDELAY,
  861. { from: proposer },
  862. );
  863. await time.increase(MINDELAY);
  864. expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  865. expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  866. await expectRevert(
  867. this.timelock.execute(
  868. operation.target,
  869. operation.value,
  870. operation.data,
  871. operation.predecessor,
  872. operation.salt,
  873. { from: executor },
  874. ),
  875. 'TimelockController: underlying transaction reverted',
  876. );
  877. expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  878. expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  879. });
  880. it('call reverting with eth', async function () {
  881. const operation = genOperation(
  882. this.callreceivermock.address,
  883. 1,
  884. this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(),
  885. ZERO_BYTES32,
  886. '0xdedb4563ef0095db01d81d3f2decf57cf83e4a72aa792af14c43a792b56f4de6',
  887. );
  888. await this.timelock.schedule(
  889. operation.target,
  890. operation.value,
  891. operation.data,
  892. operation.predecessor,
  893. operation.salt,
  894. MINDELAY,
  895. { from: proposer },
  896. );
  897. await time.increase(MINDELAY);
  898. expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  899. expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  900. await expectRevert(
  901. this.timelock.execute(
  902. operation.target,
  903. operation.value,
  904. operation.data,
  905. operation.predecessor,
  906. operation.salt,
  907. { from: executor },
  908. ),
  909. 'TimelockController: underlying transaction reverted',
  910. );
  911. expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  912. expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  913. });
  914. });
  915. });