TimelockController.test.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  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('length of batch parameter must match #1', async function () {
  340. await expectRevert(
  341. this.timelock.scheduleBatch(
  342. this.operation.targets,
  343. [],
  344. this.operation.datas,
  345. this.operation.predecessor,
  346. this.operation.salt,
  347. MINDELAY,
  348. { from: proposer },
  349. ),
  350. 'TimelockController: length mismatch',
  351. );
  352. });
  353. it('length of batch parameter must match #1', async function () {
  354. await expectRevert(
  355. this.timelock.scheduleBatch(
  356. this.operation.targets,
  357. this.operation.values,
  358. [],
  359. this.operation.predecessor,
  360. this.operation.salt,
  361. MINDELAY,
  362. { from: proposer },
  363. ),
  364. 'TimelockController: length mismatch',
  365. );
  366. });
  367. it('prevent non-proposer from commiting', async function () {
  368. await expectRevert(
  369. this.timelock.scheduleBatch(
  370. this.operation.targets,
  371. this.operation.values,
  372. this.operation.datas,
  373. this.operation.predecessor,
  374. this.operation.salt,
  375. MINDELAY,
  376. { from: other },
  377. ),
  378. 'TimelockController: sender requires permission',
  379. );
  380. });
  381. it('enforce minimum delay', async function () {
  382. await expectRevert(
  383. this.timelock.scheduleBatch(
  384. this.operation.targets,
  385. this.operation.values,
  386. this.operation.datas,
  387. this.operation.predecessor,
  388. this.operation.salt,
  389. MINDELAY - 1,
  390. { from: proposer },
  391. ),
  392. 'TimelockController: insufficient delay',
  393. );
  394. });
  395. });
  396. describe('execute', function () {
  397. beforeEach(async function () {
  398. this.operation = genOperationBatch(
  399. Array(8).fill('0x76E53CcEb05131Ef5248553bEBDb8F70536830b1'),
  400. Array(8).fill(0),
  401. Array(8).fill('0x58a60f63'),
  402. ZERO_BYTES32,
  403. '0x9545eeabc7a7586689191f78a5532443698538e54211b5bd4d7dc0fc0102b5c7',
  404. );
  405. });
  406. it('revert if operation is not scheduled', async function () {
  407. await expectRevert(
  408. this.timelock.executeBatch(
  409. this.operation.targets,
  410. this.operation.values,
  411. this.operation.datas,
  412. this.operation.predecessor,
  413. this.operation.salt,
  414. { from: executor },
  415. ),
  416. 'TimelockController: operation is not ready',
  417. );
  418. });
  419. describe('with scheduled operation', function () {
  420. beforeEach(async function () {
  421. ({ receipt: this.receipt, logs: this.logs } = await this.timelock.scheduleBatch(
  422. this.operation.targets,
  423. this.operation.values,
  424. this.operation.datas,
  425. this.operation.predecessor,
  426. this.operation.salt,
  427. MINDELAY,
  428. { from: proposer },
  429. ));
  430. });
  431. it('revert if execution comes too early 1/2', async function () {
  432. await expectRevert(
  433. this.timelock.executeBatch(
  434. this.operation.targets,
  435. this.operation.values,
  436. this.operation.datas,
  437. this.operation.predecessor,
  438. this.operation.salt,
  439. { from: executor },
  440. ),
  441. 'TimelockController: operation is not ready',
  442. );
  443. });
  444. it('revert if execution comes too early 2/2', async function () {
  445. const timestamp = await this.timelock.getTimestamp(this.operation.id);
  446. await time.increaseTo(timestamp - 5); // -1 is to tight, test sometime fails
  447. await expectRevert(
  448. this.timelock.executeBatch(
  449. this.operation.targets,
  450. this.operation.values,
  451. this.operation.datas,
  452. this.operation.predecessor,
  453. this.operation.salt,
  454. { from: executor },
  455. ),
  456. 'TimelockController: operation is not ready',
  457. );
  458. });
  459. describe('on time', function () {
  460. beforeEach(async function () {
  461. const timestamp = await this.timelock.getTimestamp(this.operation.id);
  462. await time.increaseTo(timestamp);
  463. });
  464. it('executor can reveal', async function () {
  465. const receipt = await this.timelock.executeBatch(
  466. this.operation.targets,
  467. this.operation.values,
  468. this.operation.datas,
  469. this.operation.predecessor,
  470. this.operation.salt,
  471. { from: executor },
  472. );
  473. for (const i in this.operation.targets) {
  474. expectEvent(receipt, 'CallExecuted', {
  475. id: this.operation.id,
  476. index: web3.utils.toBN(i),
  477. target: this.operation.targets[i],
  478. value: web3.utils.toBN(this.operation.values[i]),
  479. data: this.operation.datas[i],
  480. });
  481. }
  482. });
  483. it('prevent non-executor from revealing', async function () {
  484. await expectRevert(
  485. this.timelock.executeBatch(
  486. this.operation.targets,
  487. this.operation.values,
  488. this.operation.datas,
  489. this.operation.predecessor,
  490. this.operation.salt,
  491. { from: other },
  492. ),
  493. 'TimelockController: sender requires permission',
  494. );
  495. });
  496. it('length mismatch #1', async function () {
  497. await expectRevert(
  498. this.timelock.executeBatch(
  499. [],
  500. this.operation.values,
  501. this.operation.datas,
  502. this.operation.predecessor,
  503. this.operation.salt,
  504. { from: executor },
  505. ),
  506. 'TimelockController: length mismatch',
  507. );
  508. });
  509. it('length mismatch #2', async function () {
  510. await expectRevert(
  511. this.timelock.executeBatch(
  512. this.operation.targets,
  513. [],
  514. this.operation.datas,
  515. this.operation.predecessor,
  516. this.operation.salt,
  517. { from: executor },
  518. ),
  519. 'TimelockController: length mismatch',
  520. );
  521. });
  522. it('length mismatch #3', async function () {
  523. await expectRevert(
  524. this.timelock.executeBatch(
  525. this.operation.targets,
  526. this.operation.values,
  527. [],
  528. this.operation.predecessor,
  529. this.operation.salt,
  530. { from: executor },
  531. ),
  532. 'TimelockController: length mismatch',
  533. );
  534. });
  535. });
  536. });
  537. it('partial execution', async function () {
  538. const operation = genOperationBatch(
  539. [
  540. this.callreceivermock.address,
  541. this.callreceivermock.address,
  542. this.callreceivermock.address,
  543. ],
  544. [
  545. 0,
  546. 0,
  547. 0,
  548. ],
  549. [
  550. this.callreceivermock.contract.methods.mockFunction().encodeABI(),
  551. this.callreceivermock.contract.methods.mockFunctionThrows().encodeABI(),
  552. this.callreceivermock.contract.methods.mockFunction().encodeABI(),
  553. ],
  554. ZERO_BYTES32,
  555. '0x8ac04aa0d6d66b8812fb41d39638d37af0a9ab11da507afd65c509f8ed079d3e',
  556. );
  557. await this.timelock.scheduleBatch(
  558. operation.targets,
  559. operation.values,
  560. operation.datas,
  561. operation.predecessor,
  562. operation.salt,
  563. MINDELAY,
  564. { from: proposer },
  565. );
  566. await time.increase(MINDELAY);
  567. await expectRevert(
  568. this.timelock.executeBatch(
  569. operation.targets,
  570. operation.values,
  571. operation.datas,
  572. operation.predecessor,
  573. operation.salt,
  574. { from: executor },
  575. ),
  576. 'TimelockController: underlying transaction reverted',
  577. );
  578. });
  579. });
  580. });
  581. describe('cancel', function () {
  582. beforeEach(async function () {
  583. this.operation = genOperation(
  584. '0xC6837c44AA376dbe1d2709F13879E040CAb653ca',
  585. 0,
  586. '0x296e58dd',
  587. ZERO_BYTES32,
  588. '0xa2485763600634800df9fc9646fb2c112cf98649c55f63dd1d9c7d13a64399d9',
  589. );
  590. ({ receipt: this.receipt, logs: this.logs } = await this.timelock.schedule(
  591. this.operation.target,
  592. this.operation.value,
  593. this.operation.data,
  594. this.operation.predecessor,
  595. this.operation.salt,
  596. MINDELAY,
  597. { from: proposer },
  598. ));
  599. });
  600. it('proposer can cancel', async function () {
  601. const receipt = await this.timelock.cancel(this.operation.id, { from: proposer });
  602. expectEvent(receipt, 'Cancelled', { id: this.operation.id });
  603. });
  604. it('cannot cancel invalid operation', async function () {
  605. await expectRevert(
  606. this.timelock.cancel(constants.ZERO_BYTES32, { from: proposer }),
  607. 'TimelockController: operation cannot be cancelled',
  608. );
  609. });
  610. it('prevent non-proposer from canceling', async function () {
  611. await expectRevert(
  612. this.timelock.cancel(this.operation.id, { from: other }),
  613. 'TimelockController: sender requires permission',
  614. );
  615. });
  616. });
  617. });
  618. describe('maintenance', function () {
  619. it('prevent unauthorized maintenance', async function () {
  620. await expectRevert(
  621. this.timelock.updateDelay(0, { from: other }),
  622. 'TimelockController: caller must be timelock',
  623. );
  624. });
  625. it('timelock scheduled maintenance', async function () {
  626. const newDelay = time.duration.hours(6);
  627. const operation = genOperation(
  628. this.timelock.address,
  629. 0,
  630. this.timelock.contract.methods.updateDelay(newDelay.toString()).encodeABI(),
  631. ZERO_BYTES32,
  632. '0xf8e775b2c5f4d66fb5c7fa800f35ef518c262b6014b3c0aee6ea21bff157f108',
  633. );
  634. await this.timelock.schedule(
  635. operation.target,
  636. operation.value,
  637. operation.data,
  638. operation.predecessor,
  639. operation.salt,
  640. MINDELAY,
  641. { from: proposer },
  642. );
  643. await time.increase(MINDELAY);
  644. const receipt = await this.timelock.execute(
  645. operation.target,
  646. operation.value,
  647. operation.data,
  648. operation.predecessor,
  649. operation.salt,
  650. { from: executor },
  651. );
  652. expectEvent(receipt, 'MinDelayChange', { newDuration: newDelay.toString(), oldDuration: MINDELAY });
  653. expect(await this.timelock.getMinDelay()).to.be.bignumber.equal(newDelay);
  654. });
  655. });
  656. describe('dependency', function () {
  657. beforeEach(async function () {
  658. this.operation1 = genOperation(
  659. '0xdE66bD4c97304200A95aE0AadA32d6d01A867E39',
  660. 0,
  661. '0x01dc731a',
  662. ZERO_BYTES32,
  663. '0x64e932133c7677402ead2926f86205e2ca4686aebecf5a8077627092b9bb2feb',
  664. );
  665. this.operation2 = genOperation(
  666. '0x3c7944a3F1ee7fc8c5A5134ba7c79D11c3A1FCa3',
  667. 0,
  668. '0x8f531849',
  669. this.operation1.id,
  670. '0x036e1311cac523f9548e6461e29fb1f8f9196b91910a41711ea22f5de48df07d',
  671. );
  672. await this.timelock.schedule(
  673. this.operation1.target,
  674. this.operation1.value,
  675. this.operation1.data,
  676. this.operation1.predecessor,
  677. this.operation1.salt,
  678. MINDELAY,
  679. { from: proposer },
  680. );
  681. await this.timelock.schedule(
  682. this.operation2.target,
  683. this.operation2.value,
  684. this.operation2.data,
  685. this.operation2.predecessor,
  686. this.operation2.salt,
  687. MINDELAY,
  688. { from: proposer },
  689. );
  690. await time.increase(MINDELAY);
  691. });
  692. it('cannot execute before dependency', async function () {
  693. await expectRevert(
  694. this.timelock.execute(
  695. this.operation2.target,
  696. this.operation2.value,
  697. this.operation2.data,
  698. this.operation2.predecessor,
  699. this.operation2.salt,
  700. { from: executor },
  701. ),
  702. 'TimelockController: missing dependency',
  703. );
  704. });
  705. it('can execute after dependency', async function () {
  706. await this.timelock.execute(
  707. this.operation1.target,
  708. this.operation1.value,
  709. this.operation1.data,
  710. this.operation1.predecessor,
  711. this.operation1.salt,
  712. { from: executor },
  713. );
  714. await this.timelock.execute(
  715. this.operation2.target,
  716. this.operation2.value,
  717. this.operation2.data,
  718. this.operation2.predecessor,
  719. this.operation2.salt,
  720. { from: executor },
  721. );
  722. });
  723. });
  724. describe('usage scenario', function () {
  725. this.timeout(10000);
  726. it('call', async function () {
  727. const operation = genOperation(
  728. this.implementation2.address,
  729. 0,
  730. this.implementation2.contract.methods.setValue(42).encodeABI(),
  731. ZERO_BYTES32,
  732. '0x8043596363daefc89977b25f9d9b4d06c3910959ef0c4d213557a903e1b555e2',
  733. );
  734. await this.timelock.schedule(
  735. operation.target,
  736. operation.value,
  737. operation.data,
  738. operation.predecessor,
  739. operation.salt,
  740. MINDELAY,
  741. { from: proposer },
  742. );
  743. await time.increase(MINDELAY);
  744. await this.timelock.execute(
  745. operation.target,
  746. operation.value,
  747. operation.data,
  748. operation.predecessor,
  749. operation.salt,
  750. { from: executor },
  751. );
  752. expect(await this.implementation2.getValue()).to.be.bignumber.equal(web3.utils.toBN(42));
  753. });
  754. it('call reverting', async function () {
  755. const operation = genOperation(
  756. this.callreceivermock.address,
  757. 0,
  758. this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(),
  759. ZERO_BYTES32,
  760. '0xb1b1b276fdf1a28d1e00537ea73b04d56639128b08063c1a2f70a52e38cba693',
  761. );
  762. await this.timelock.schedule(
  763. operation.target,
  764. operation.value,
  765. operation.data,
  766. operation.predecessor,
  767. operation.salt,
  768. MINDELAY,
  769. { from: proposer },
  770. );
  771. await time.increase(MINDELAY);
  772. await expectRevert(
  773. this.timelock.execute(
  774. operation.target,
  775. operation.value,
  776. operation.data,
  777. operation.predecessor,
  778. operation.salt,
  779. { from: executor },
  780. ),
  781. 'TimelockController: underlying transaction reverted',
  782. );
  783. });
  784. it('call throw', async function () {
  785. const operation = genOperation(
  786. this.callreceivermock.address,
  787. 0,
  788. this.callreceivermock.contract.methods.mockFunctionThrows().encodeABI(),
  789. ZERO_BYTES32,
  790. '0xe5ca79f295fc8327ee8a765fe19afb58f4a0cbc5053642bfdd7e73bc68e0fc67',
  791. );
  792. await this.timelock.schedule(
  793. operation.target,
  794. operation.value,
  795. operation.data,
  796. operation.predecessor,
  797. operation.salt,
  798. MINDELAY,
  799. { from: proposer },
  800. );
  801. await time.increase(MINDELAY);
  802. await expectRevert(
  803. this.timelock.execute(
  804. operation.target,
  805. operation.value,
  806. operation.data,
  807. operation.predecessor,
  808. operation.salt,
  809. { from: executor },
  810. ),
  811. 'TimelockController: underlying transaction reverted',
  812. );
  813. });
  814. it('call out of gas', async function () {
  815. const operation = genOperation(
  816. this.callreceivermock.address,
  817. 0,
  818. this.callreceivermock.contract.methods.mockFunctionOutOfGas().encodeABI(),
  819. ZERO_BYTES32,
  820. '0xf3274ce7c394c5b629d5215723563a744b817e1730cca5587c567099a14578fd',
  821. );
  822. await this.timelock.schedule(
  823. operation.target,
  824. operation.value,
  825. operation.data,
  826. operation.predecessor,
  827. operation.salt,
  828. MINDELAY,
  829. { from: proposer },
  830. );
  831. await time.increase(MINDELAY);
  832. await expectRevert(
  833. this.timelock.execute(
  834. operation.target,
  835. operation.value,
  836. operation.data,
  837. operation.predecessor,
  838. operation.salt,
  839. { from: executor, gas: '70000' },
  840. ),
  841. 'TimelockController: underlying transaction reverted',
  842. );
  843. });
  844. it('call payable with eth', async function () {
  845. const operation = genOperation(
  846. this.callreceivermock.address,
  847. 1,
  848. this.callreceivermock.contract.methods.mockFunction().encodeABI(),
  849. ZERO_BYTES32,
  850. '0x5ab73cd33477dcd36c1e05e28362719d0ed59a7b9ff14939de63a43073dc1f44',
  851. );
  852. await this.timelock.schedule(
  853. operation.target,
  854. operation.value,
  855. operation.data,
  856. operation.predecessor,
  857. operation.salt,
  858. MINDELAY,
  859. { from: proposer },
  860. );
  861. await time.increase(MINDELAY);
  862. expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  863. expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  864. await this.timelock.execute(
  865. operation.target,
  866. operation.value,
  867. operation.data,
  868. operation.predecessor,
  869. operation.salt,
  870. { from: executor, value: 1 },
  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(1));
  874. });
  875. it('call nonpayable with eth', async function () {
  876. const operation = genOperation(
  877. this.callreceivermock.address,
  878. 1,
  879. this.callreceivermock.contract.methods.mockFunctionNonPayable().encodeABI(),
  880. ZERO_BYTES32,
  881. '0xb78edbd920c7867f187e5aa6294ae5a656cfbf0dea1ccdca3751b740d0f2bdf8',
  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. it('call reverting with eth', async function () {
  910. const operation = genOperation(
  911. this.callreceivermock.address,
  912. 1,
  913. this.callreceivermock.contract.methods.mockFunctionRevertsNoReason().encodeABI(),
  914. ZERO_BYTES32,
  915. '0xdedb4563ef0095db01d81d3f2decf57cf83e4a72aa792af14c43a792b56f4de6',
  916. );
  917. await this.timelock.schedule(
  918. operation.target,
  919. operation.value,
  920. operation.data,
  921. operation.predecessor,
  922. operation.salt,
  923. MINDELAY,
  924. { from: proposer },
  925. );
  926. await time.increase(MINDELAY);
  927. expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  928. expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  929. await expectRevert(
  930. this.timelock.execute(
  931. operation.target,
  932. operation.value,
  933. operation.data,
  934. operation.predecessor,
  935. operation.salt,
  936. { from: executor },
  937. ),
  938. 'TimelockController: underlying transaction reverted',
  939. );
  940. expect(await web3.eth.getBalance(this.timelock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  941. expect(await web3.eth.getBalance(this.callreceivermock.address)).to.be.bignumber.equal(web3.utils.toBN(0));
  942. });
  943. });
  944. });