TimelockController.test.js 32 KB

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