AccessManager.test.js 111 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683
  1. const { web3 } = require('hardhat');
  2. const { constants, expectEvent, time, expectRevert } = require('@openzeppelin/test-helpers');
  3. const { expectRevertCustomError } = require('../../helpers/customError');
  4. const { selector } = require('../../helpers/methods');
  5. const { clockFromReceipt } = require('../../helpers/time');
  6. const {
  7. buildBaseRoles,
  8. formatAccess,
  9. EXPIRATION,
  10. MINSETBACK,
  11. EXECUTION_ID_STORAGE_SLOT,
  12. CONSUMING_SCHEDULE_STORAGE_SLOT,
  13. } = require('../../helpers/access-manager');
  14. const {
  15. // COMMON PATHS
  16. COMMON_SCHEDULABLE_PATH,
  17. COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY,
  18. // MODE HELPERS
  19. shouldBehaveLikeClosable,
  20. // DELAY HELPERS
  21. shouldBehaveLikeDelay,
  22. // OPERATION HELPERS
  23. shouldBehaveLikeSchedulableOperation,
  24. // METHOD HELPERS
  25. shouldBehaveLikeCanCall,
  26. shouldBehaveLikeGetAccess,
  27. shouldBehaveLikeHasRole,
  28. // ADMIN OPERATION HELPERS
  29. shouldBehaveLikeDelayedAdminOperation,
  30. shouldBehaveLikeNotDelayedAdminOperation,
  31. shouldBehaveLikeRoleAdminOperation,
  32. // RESTRICTED OPERATION HELPERS
  33. shouldBehaveLikeAManagedRestrictedOperation,
  34. // HELPERS
  35. scheduleOperation,
  36. } = require('./AccessManager.behavior');
  37. const { default: Wallet } = require('ethereumjs-wallet');
  38. const {
  39. mine,
  40. time: { setNextBlockTimestamp },
  41. getStorageAt,
  42. } = require('@nomicfoundation/hardhat-network-helpers');
  43. const { MAX_UINT48 } = require('../../helpers/constants');
  44. const { impersonate } = require('../../helpers/account');
  45. const AccessManager = artifacts.require('$AccessManager');
  46. const AccessManagedTarget = artifacts.require('$AccessManagedTarget');
  47. const Ownable = artifacts.require('$Ownable');
  48. const someAddress = Wallet.generate().getChecksumAddressString();
  49. contract('AccessManager', function (accounts) {
  50. const [admin, manager, guardian, member, user, other] = accounts;
  51. beforeEach(async function () {
  52. this.roles = buildBaseRoles();
  53. // Add members
  54. this.roles.ADMIN.members = [admin];
  55. this.roles.SOME_ADMIN.members = [manager];
  56. this.roles.SOME_GUARDIAN.members = [guardian];
  57. this.roles.SOME.members = [member];
  58. this.roles.PUBLIC.members = [admin, manager, guardian, member, user, other];
  59. this.manager = await AccessManager.new(admin);
  60. this.target = await AccessManagedTarget.new(this.manager.address);
  61. for (const { id: roleId, admin, guardian, members } of Object.values(this.roles)) {
  62. if (roleId === this.roles.PUBLIC.id) continue; // Every address belong to public and is locked
  63. if (roleId === this.roles.ADMIN.id) continue; // Admin set during construction and is locked
  64. // Set admin role avoiding default
  65. if (admin.id !== this.roles.ADMIN.id) {
  66. await this.manager.$_setRoleAdmin(roleId, admin.id);
  67. }
  68. // Set guardian role avoiding default
  69. if (guardian.id !== this.roles.ADMIN.id) {
  70. await this.manager.$_setRoleGuardian(roleId, guardian.id);
  71. }
  72. // Grant role to members
  73. for (const member of members) {
  74. await this.manager.$_grantRole(roleId, member, 0, 0);
  75. }
  76. }
  77. });
  78. describe('during construction', function () {
  79. it('grants admin role to initialAdmin', async function () {
  80. const manager = await AccessManager.new(other);
  81. expect(await manager.hasRole(this.roles.ADMIN.id, other).then(formatAccess)).to.be.deep.equal([true, '0']);
  82. });
  83. it('rejects zero address for initialAdmin', async function () {
  84. await expectRevertCustomError(AccessManager.new(constants.ZERO_ADDRESS), 'AccessManagerInvalidInitialAdmin', [
  85. constants.ZERO_ADDRESS,
  86. ]);
  87. });
  88. it('initializes setup roles correctly', async function () {
  89. for (const { id: roleId, admin, guardian, members } of Object.values(this.roles)) {
  90. expect(await this.manager.getRoleAdmin(roleId)).to.be.bignumber.equal(admin.id);
  91. expect(await this.manager.getRoleGuardian(roleId)).to.be.bignumber.equal(guardian.id);
  92. for (const user of this.roles.PUBLIC.members) {
  93. expect(await this.manager.hasRole(roleId, user).then(formatAccess)).to.be.deep.equal([
  94. members.includes(user),
  95. '0',
  96. ]);
  97. }
  98. }
  99. });
  100. });
  101. describe('getters', function () {
  102. describe('#canCall', function () {
  103. beforeEach('set calldata', function () {
  104. this.calldata = '0x12345678';
  105. this.role = { id: web3.utils.toBN(379204) };
  106. });
  107. shouldBehaveLikeCanCall({
  108. closed() {
  109. it('should return false and no delay', async function () {
  110. const { immediate, delay } = await this.manager.canCall(
  111. someAddress,
  112. this.target.address,
  113. this.calldata.substring(0, 10),
  114. );
  115. expect(immediate).to.be.equal(false);
  116. expect(delay).to.be.bignumber.equal('0');
  117. });
  118. },
  119. open: {
  120. callerIsTheManager: {
  121. executing() {
  122. it('should return true and no delay', async function () {
  123. const { immediate, delay } = await this.manager.canCall(
  124. this.caller,
  125. this.target.address,
  126. this.calldata.substring(0, 10),
  127. );
  128. expect(immediate).to.be.equal(true);
  129. expect(delay).to.be.bignumber.equal('0');
  130. });
  131. },
  132. notExecuting() {
  133. it('should return false and no delay', async function () {
  134. const { immediate, delay } = await this.manager.canCall(
  135. this.caller,
  136. this.target.address,
  137. this.calldata.substring(0, 10),
  138. );
  139. expect(immediate).to.be.equal(false);
  140. expect(delay).to.be.bignumber.equal('0');
  141. });
  142. },
  143. },
  144. callerIsNotTheManager: {
  145. publicRoleIsRequired() {
  146. it('should return true and no delay', async function () {
  147. const { immediate, delay } = await this.manager.canCall(
  148. this.caller,
  149. this.target.address,
  150. this.calldata.substring(0, 10),
  151. );
  152. expect(immediate).to.be.equal(true);
  153. expect(delay).to.be.bignumber.equal('0');
  154. });
  155. },
  156. specificRoleIsRequired: {
  157. requiredRoleIsGranted: {
  158. roleGrantingIsDelayed: {
  159. callerHasAnExecutionDelay: {
  160. beforeGrantDelay() {
  161. beforeEach('consume previously set grant delay', async function () {
  162. // Consume previously set delay
  163. await mine();
  164. });
  165. it('should return false and no execution delay', async function () {
  166. const { immediate, delay } = await this.manager.canCall(
  167. this.caller,
  168. this.target.address,
  169. this.calldata.substring(0, 10),
  170. );
  171. expect(immediate).to.be.equal(false);
  172. expect(delay).to.be.bignumber.equal('0');
  173. });
  174. },
  175. afterGrantDelay() {
  176. beforeEach('consume previously set grant delay', async function () {
  177. // Consume previously set delay
  178. await mine();
  179. this.scheduleIn = this.executionDelay; // For shouldBehaveLikeSchedulableOperation
  180. });
  181. shouldBehaveLikeSchedulableOperation({
  182. scheduled: {
  183. before() {
  184. beforeEach('consume previously set delay', async function () {
  185. // Consume previously set delay
  186. await mine();
  187. });
  188. it('should return false and execution delay', async function () {
  189. const { immediate, delay } = await this.manager.canCall(
  190. this.caller,
  191. this.target.address,
  192. this.calldata.substring(0, 10),
  193. );
  194. expect(immediate).to.be.equal(false);
  195. expect(delay).to.be.bignumber.equal(this.executionDelay);
  196. });
  197. },
  198. after() {
  199. beforeEach('consume previously set delay', async function () {
  200. // Consume previously set delay
  201. await mine();
  202. });
  203. it('should return false and execution delay', async function () {
  204. const { immediate, delay } = await this.manager.canCall(
  205. this.caller,
  206. this.target.address,
  207. this.calldata.substring(0, 10),
  208. );
  209. expect(immediate).to.be.equal(false);
  210. expect(delay).to.be.bignumber.equal(this.executionDelay);
  211. });
  212. },
  213. expired() {
  214. beforeEach('consume previously set delay', async function () {
  215. // Consume previously set delay
  216. await mine();
  217. });
  218. it('should return false and execution delay', async function () {
  219. const { immediate, delay } = await this.manager.canCall(
  220. this.caller,
  221. this.target.address,
  222. this.calldata.substring(0, 10),
  223. );
  224. expect(immediate).to.be.equal(false);
  225. expect(delay).to.be.bignumber.equal(this.executionDelay);
  226. });
  227. },
  228. },
  229. notScheduled() {
  230. it('should return false and execution delay', async function () {
  231. const { immediate, delay } = await this.manager.canCall(
  232. this.caller,
  233. this.target.address,
  234. this.calldata.substring(0, 10),
  235. );
  236. expect(immediate).to.be.equal(false);
  237. expect(delay).to.be.bignumber.equal(this.executionDelay);
  238. });
  239. },
  240. });
  241. },
  242. },
  243. callerHasNoExecutionDelay: {
  244. beforeGrantDelay() {
  245. beforeEach('consume previously set grant delay', async function () {
  246. // Consume previously set delay
  247. await mine();
  248. });
  249. it('should return false and no execution delay', async function () {
  250. const { immediate, delay } = await this.manager.canCall(
  251. this.caller,
  252. this.target.address,
  253. this.calldata.substring(0, 10),
  254. );
  255. expect(immediate).to.be.equal(false);
  256. expect(delay).to.be.bignumber.equal('0');
  257. });
  258. },
  259. afterGrantDelay() {
  260. beforeEach('consume previously set grant delay', async function () {
  261. // Consume previously set delay
  262. await mine();
  263. });
  264. it('should return true and no execution delay', async function () {
  265. const { immediate, delay } = await this.manager.canCall(
  266. this.caller,
  267. this.target.address,
  268. this.calldata.substring(0, 10),
  269. );
  270. expect(immediate).to.be.equal(true);
  271. expect(delay).to.be.bignumber.equal('0');
  272. });
  273. },
  274. },
  275. },
  276. roleGrantingIsNotDelayed: {
  277. callerHasAnExecutionDelay() {
  278. it('should return false and execution delay', async function () {
  279. const { immediate, delay } = await this.manager.canCall(
  280. this.caller,
  281. this.target.address,
  282. this.calldata.substring(0, 10),
  283. );
  284. expect(immediate).to.be.equal(false);
  285. expect(delay).to.be.bignumber.equal(this.executionDelay);
  286. });
  287. },
  288. callerHasNoExecutionDelay() {
  289. it('should return true and no execution delay', async function () {
  290. const { immediate, delay } = await this.manager.canCall(
  291. this.caller,
  292. this.target.address,
  293. this.calldata.substring(0, 10),
  294. );
  295. expect(immediate).to.be.equal(true);
  296. expect(delay).to.be.bignumber.equal('0');
  297. });
  298. },
  299. },
  300. },
  301. requiredRoleIsNotGranted() {
  302. it('should return false and no execution delay', async function () {
  303. const { immediate, delay } = await this.manager.canCall(
  304. this.caller,
  305. this.target.address,
  306. this.calldata.substring(0, 10),
  307. );
  308. expect(immediate).to.be.equal(false);
  309. expect(delay).to.be.bignumber.equal('0');
  310. });
  311. },
  312. },
  313. },
  314. },
  315. });
  316. });
  317. describe('#expiration', function () {
  318. it('has a 7 days default expiration', async function () {
  319. expect(await this.manager.expiration()).to.be.bignumber.equal(EXPIRATION);
  320. });
  321. });
  322. describe('#minSetback', function () {
  323. it('has a 5 days default minimum setback', async function () {
  324. expect(await this.manager.minSetback()).to.be.bignumber.equal(MINSETBACK);
  325. });
  326. });
  327. describe('#isTargetClosed', function () {
  328. shouldBehaveLikeClosable({
  329. closed() {
  330. it('returns true', async function () {
  331. expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(true);
  332. });
  333. },
  334. open() {
  335. it('returns false', async function () {
  336. expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(false);
  337. });
  338. },
  339. });
  340. });
  341. describe('#getTargetFunctionRole', function () {
  342. const methodSelector = selector('something(address,bytes)');
  343. it('returns the target function role', async function () {
  344. const roleId = web3.utils.toBN(21498);
  345. await this.manager.$_setTargetFunctionRole(this.target.address, methodSelector, roleId);
  346. expect(await this.manager.getTargetFunctionRole(this.target.address, methodSelector)).to.be.bignumber.equal(
  347. roleId,
  348. );
  349. });
  350. it('returns the ADMIN role if not set', async function () {
  351. expect(await this.manager.getTargetFunctionRole(this.target.address, methodSelector)).to.be.bignumber.equal(
  352. this.roles.ADMIN.id,
  353. );
  354. });
  355. });
  356. describe('#getTargetAdminDelay', function () {
  357. describe('when the target admin delay is setup', function () {
  358. beforeEach('set target admin delay', async function () {
  359. this.oldDelay = await this.manager.getTargetAdminDelay(this.target.address);
  360. this.newDelay = time.duration.days(10);
  361. await this.manager.$_setTargetAdminDelay(this.target.address, this.newDelay);
  362. this.delay = MINSETBACK; // For shouldBehaveLikeDelay
  363. });
  364. shouldBehaveLikeDelay('effect', {
  365. before() {
  366. beforeEach('consume previously set grant delay', async function () {
  367. // Consume previously set delay
  368. await mine();
  369. });
  370. it('returns the old target admin delay', async function () {
  371. expect(await this.manager.getTargetAdminDelay(this.target.address)).to.be.bignumber.equal(this.oldDelay);
  372. });
  373. },
  374. after() {
  375. beforeEach('consume previously set grant delay', async function () {
  376. // Consume previously set delay
  377. await mine();
  378. });
  379. it('returns the new target admin delay', async function () {
  380. expect(await this.manager.getTargetAdminDelay(this.target.address)).to.be.bignumber.equal(this.newDelay);
  381. });
  382. },
  383. });
  384. });
  385. it('returns the 0 if not set', async function () {
  386. expect(await this.manager.getTargetAdminDelay(this.target.address)).to.be.bignumber.equal('0');
  387. });
  388. });
  389. describe('#getRoleAdmin', function () {
  390. const roleId = web3.utils.toBN(5234907);
  391. it('returns the role admin', async function () {
  392. const adminId = web3.utils.toBN(789433);
  393. await this.manager.$_setRoleAdmin(roleId, adminId);
  394. expect(await this.manager.getRoleAdmin(roleId)).to.be.bignumber.equal(adminId);
  395. });
  396. it('returns the ADMIN role if not set', async function () {
  397. expect(await this.manager.getRoleAdmin(roleId)).to.be.bignumber.equal(this.roles.ADMIN.id);
  398. });
  399. });
  400. describe('#getRoleGuardian', function () {
  401. const roleId = web3.utils.toBN(5234907);
  402. it('returns the role guardian', async function () {
  403. const guardianId = web3.utils.toBN(789433);
  404. await this.manager.$_setRoleGuardian(roleId, guardianId);
  405. expect(await this.manager.getRoleGuardian(roleId)).to.be.bignumber.equal(guardianId);
  406. });
  407. it('returns the ADMIN role if not set', async function () {
  408. expect(await this.manager.getRoleGuardian(roleId)).to.be.bignumber.equal(this.roles.ADMIN.id);
  409. });
  410. });
  411. describe('#getRoleGrantDelay', function () {
  412. const roleId = web3.utils.toBN(9248439);
  413. describe('when the grant admin delay is setup', function () {
  414. beforeEach('set grant admin delay', async function () {
  415. this.oldDelay = await this.manager.getRoleGrantDelay(roleId);
  416. this.newDelay = time.duration.days(11);
  417. await this.manager.$_setGrantDelay(roleId, this.newDelay);
  418. this.delay = MINSETBACK; // For shouldBehaveLikeDelay
  419. });
  420. shouldBehaveLikeDelay('grant', {
  421. before() {
  422. beforeEach('consume previously set grant delay', async function () {
  423. // Consume previously set delay
  424. await mine();
  425. });
  426. it('returns the old role grant delay', async function () {
  427. expect(await this.manager.getRoleGrantDelay(roleId)).to.be.bignumber.equal(this.oldDelay);
  428. });
  429. },
  430. after() {
  431. beforeEach('consume previously set grant delay', async function () {
  432. // Consume previously set delay
  433. await mine();
  434. });
  435. it('returns the new role grant delay', async function () {
  436. expect(await this.manager.getRoleGrantDelay(roleId)).to.be.bignumber.equal(this.newDelay);
  437. });
  438. },
  439. });
  440. });
  441. it('returns 0 if delay is not set', async function () {
  442. expect(await this.manager.getTargetAdminDelay(this.target.address)).to.be.bignumber.equal('0');
  443. });
  444. });
  445. describe('#getAccess', function () {
  446. beforeEach('set role', function () {
  447. this.role = { id: web3.utils.toBN(9452) };
  448. this.caller = user;
  449. });
  450. shouldBehaveLikeGetAccess({
  451. requiredRoleIsGranted: {
  452. roleGrantingIsDelayed: {
  453. callerHasAnExecutionDelay: {
  454. beforeGrantDelay() {
  455. beforeEach('consume previously set grant delay', async function () {
  456. // Consume previously set delay
  457. await mine();
  458. });
  459. it('role is not in effect and execution delay is set', async function () {
  460. const access = await this.manager.getAccess(this.role.id, this.caller);
  461. expect(access[0]).to.be.bignumber.equal(this.delayEffect); // inEffectSince
  462. expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay
  463. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  464. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  465. // Not in effect yet
  466. expect(await time.latest()).to.be.bignumber.lt(access[0]);
  467. });
  468. },
  469. afterGrantDelay() {
  470. beforeEach('consume previously set grant delay', async function () {
  471. // Consume previously set delay
  472. await mine();
  473. });
  474. it('access has role in effect and execution delay is set', async function () {
  475. const access = await this.manager.getAccess(this.role.id, this.caller);
  476. expect(access[0]).to.be.bignumber.equal(this.delayEffect); // inEffectSince
  477. expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay
  478. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  479. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  480. // Already in effect
  481. expect(await time.latest()).to.be.bignumber.equal(access[0]);
  482. });
  483. },
  484. },
  485. callerHasNoExecutionDelay: {
  486. beforeGrantDelay() {
  487. beforeEach('consume previously set grant delay', async function () {
  488. // Consume previously set delay
  489. await mine();
  490. });
  491. it('access has role not in effect without execution delay', async function () {
  492. const access = await this.manager.getAccess(this.role.id, this.caller);
  493. expect(access[0]).to.be.bignumber.equal(this.delayEffect); // inEffectSince
  494. expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
  495. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  496. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  497. // Not in effect yet
  498. expect(await time.latest()).to.be.bignumber.lt(access[0]);
  499. });
  500. },
  501. afterGrantDelay() {
  502. beforeEach('consume previously set grant delay', async function () {
  503. // Consume previously set delay
  504. await mine();
  505. });
  506. it('role is in effect without execution delay', async function () {
  507. const access = await this.manager.getAccess(this.role.id, this.caller);
  508. expect(access[0]).to.be.bignumber.equal(this.delayEffect); // inEffectSince
  509. expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
  510. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  511. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  512. // Already in effect
  513. expect(await time.latest()).to.be.bignumber.equal(access[0]);
  514. });
  515. },
  516. },
  517. },
  518. roleGrantingIsNotDelayed: {
  519. callerHasAnExecutionDelay() {
  520. it('access has role in effect and execution delay is set', async function () {
  521. const access = await this.manager.getAccess(this.role.id, this.caller);
  522. expect(access[0]).to.be.bignumber.equal(await time.latest()); // inEffectSince
  523. expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay
  524. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  525. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  526. // Already in effect
  527. expect(await time.latest()).to.be.bignumber.equal(access[0]);
  528. });
  529. },
  530. callerHasNoExecutionDelay() {
  531. it('access has role in effect without execution delay', async function () {
  532. const access = await this.manager.getAccess(this.role.id, this.caller);
  533. expect(access[0]).to.be.bignumber.equal(await time.latest()); // inEffectSince
  534. expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
  535. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  536. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  537. // Already in effect
  538. expect(await time.latest()).to.be.bignumber.equal(access[0]);
  539. });
  540. },
  541. },
  542. },
  543. requiredRoleIsNotGranted() {
  544. it('has empty access', async function () {
  545. const access = await this.manager.getAccess(this.role.id, this.caller);
  546. expect(access[0]).to.be.bignumber.equal('0'); // inEffectSince
  547. expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
  548. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  549. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  550. });
  551. },
  552. });
  553. });
  554. describe('#hasRole', function () {
  555. beforeEach('setup shouldBehaveLikeHasRole', function () {
  556. this.role = { id: web3.utils.toBN(49832) };
  557. this.calldata = '0x1234';
  558. this.caller = user;
  559. });
  560. shouldBehaveLikeHasRole({
  561. publicRoleIsRequired() {
  562. it('has PUBLIC role', async function () {
  563. const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller);
  564. expect(isMember).to.be.true;
  565. expect(executionDelay).to.be.bignumber.eq('0');
  566. });
  567. },
  568. specificRoleIsRequired: {
  569. requiredRoleIsGranted: {
  570. roleGrantingIsDelayed: {
  571. callerHasAnExecutionDelay: {
  572. beforeGrantDelay() {
  573. beforeEach('consume previously set grant delay', async function () {
  574. // Consume previously set delay
  575. await mine();
  576. });
  577. it('does not have role but execution delay', async function () {
  578. const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller);
  579. expect(isMember).to.be.false;
  580. expect(executionDelay).to.be.bignumber.eq(this.executionDelay);
  581. });
  582. },
  583. afterGrantDelay() {
  584. beforeEach('consume previously set grant delay', async function () {
  585. // Consume previously set delay
  586. await mine();
  587. });
  588. it('has role and execution delay', async function () {
  589. const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller);
  590. expect(isMember).to.be.true;
  591. expect(executionDelay).to.be.bignumber.eq(this.executionDelay);
  592. });
  593. },
  594. },
  595. callerHasNoExecutionDelay: {
  596. beforeGrantDelay() {
  597. beforeEach('consume previously set grant delay', async function () {
  598. // Consume previously set delay
  599. await mine();
  600. });
  601. it('does not have role nor execution delay', async function () {
  602. const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller);
  603. expect(isMember).to.be.false;
  604. expect(executionDelay).to.be.bignumber.eq('0');
  605. });
  606. },
  607. afterGrantDelay() {
  608. beforeEach('consume previously set grant delay', async function () {
  609. // Consume previously set delay
  610. await mine();
  611. });
  612. it('has role and no execution delay', async function () {
  613. const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller);
  614. expect(isMember).to.be.true;
  615. expect(executionDelay).to.be.bignumber.eq('0');
  616. });
  617. },
  618. },
  619. },
  620. roleGrantingIsNotDelayed: {
  621. callerHasAnExecutionDelay() {
  622. it('has role and execution delay', async function () {
  623. const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller);
  624. expect(isMember).to.be.true;
  625. expect(executionDelay).to.be.bignumber.eq(this.executionDelay);
  626. });
  627. },
  628. callerHasNoExecutionDelay() {
  629. it('has role and no execution delay', async function () {
  630. const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller);
  631. expect(isMember).to.be.true;
  632. expect(executionDelay).to.be.bignumber.eq('0');
  633. });
  634. },
  635. },
  636. },
  637. requiredRoleIsNotGranted() {
  638. it('has no role and no execution delay', async function () {
  639. const { isMember, executionDelay } = await this.manager.hasRole(this.role.id, this.caller);
  640. expect(isMember).to.be.false;
  641. expect(executionDelay).to.be.bignumber.eq('0');
  642. });
  643. },
  644. },
  645. });
  646. });
  647. describe('#getSchedule', function () {
  648. beforeEach('set role and calldata', async function () {
  649. const method = 'fnRestricted()';
  650. this.caller = user;
  651. this.role = { id: web3.utils.toBN(493590) };
  652. await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id);
  653. await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay
  654. this.calldata = await this.target.contract.methods[method]().encodeABI();
  655. this.scheduleIn = time.duration.days(10); // For shouldBehaveLikeSchedulableOperation
  656. });
  657. shouldBehaveLikeSchedulableOperation({
  658. scheduled: {
  659. before() {
  660. beforeEach('consume previously set grant delay', async function () {
  661. // Consume previously set delay
  662. await mine();
  663. });
  664. it('returns schedule in the future', async function () {
  665. const schedule = await this.manager.getSchedule(this.operationId);
  666. expect(schedule).to.be.bignumber.equal(this.scheduledAt.add(this.scheduleIn));
  667. expect(schedule).to.be.bignumber.gt(await time.latest());
  668. });
  669. },
  670. after() {
  671. beforeEach('consume previously set grant delay', async function () {
  672. // Consume previously set delay
  673. await mine();
  674. });
  675. it('returns schedule', async function () {
  676. const schedule = await this.manager.getSchedule(this.operationId);
  677. expect(schedule).to.be.bignumber.equal(this.scheduledAt.add(this.scheduleIn));
  678. expect(schedule).to.be.bignumber.eq(await time.latest());
  679. });
  680. },
  681. expired() {
  682. beforeEach('consume previously set grant delay', async function () {
  683. // Consume previously set delay
  684. await mine();
  685. });
  686. it('returns 0', async function () {
  687. expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal('0');
  688. });
  689. },
  690. },
  691. notScheduled() {
  692. it('defaults to 0', async function () {
  693. expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal('0');
  694. });
  695. },
  696. });
  697. });
  698. describe('#getNonce', function () {
  699. describe('when operation is scheduled', function () {
  700. beforeEach('schedule operation', async function () {
  701. const method = 'fnRestricted()';
  702. this.caller = user;
  703. this.role = { id: web3.utils.toBN(4209043) };
  704. await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id);
  705. await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay
  706. this.calldata = await this.target.contract.methods[method]().encodeABI();
  707. this.delay = time.duration.days(10);
  708. const { operationId } = await scheduleOperation(this.manager, {
  709. caller: this.caller,
  710. target: this.target.address,
  711. calldata: this.calldata,
  712. delay: this.delay,
  713. });
  714. this.operationId = operationId;
  715. });
  716. it('returns nonce', async function () {
  717. expect(await this.manager.getNonce(this.operationId)).to.be.bignumber.equal('1');
  718. });
  719. });
  720. describe('when is not scheduled', function () {
  721. it('returns default 0', async function () {
  722. expect(await this.manager.getNonce(web3.utils.keccak256('operation'))).to.be.bignumber.equal('0');
  723. });
  724. });
  725. });
  726. describe('#hashOperation', function () {
  727. it('returns an operationId', async function () {
  728. const calldata = '0x123543';
  729. const address = someAddress;
  730. const args = [user, address, calldata];
  731. expect(await this.manager.hashOperation(...args)).to.be.bignumber.eq(
  732. await web3.utils.keccak256(web3.eth.abi.encodeParameters(['address', 'address', 'bytes'], args)),
  733. );
  734. });
  735. });
  736. });
  737. describe('admin operations', function () {
  738. beforeEach('set required role', function () {
  739. this.role = this.roles.ADMIN;
  740. });
  741. describe('subject to a delay', function () {
  742. describe('#labelRole', function () {
  743. describe('restrictions', function () {
  744. beforeEach('set method and args', function () {
  745. const method = 'labelRole(uint64,string)';
  746. const args = [123443, 'TEST'];
  747. this.calldata = this.manager.contract.methods[method](...args).encodeABI();
  748. });
  749. shouldBehaveLikeDelayedAdminOperation();
  750. });
  751. it('emits an event with the label', async function () {
  752. expectEvent(await this.manager.labelRole(this.roles.SOME.id, 'Some label', { from: admin }), 'RoleLabel', {
  753. roleId: this.roles.SOME.id,
  754. label: 'Some label',
  755. });
  756. });
  757. it('updates label on a second call', async function () {
  758. await this.manager.labelRole(this.roles.SOME.id, 'Some label', { from: admin });
  759. expectEvent(await this.manager.labelRole(this.roles.SOME.id, 'Updated label', { from: admin }), 'RoleLabel', {
  760. roleId: this.roles.SOME.id,
  761. label: 'Updated label',
  762. });
  763. });
  764. it('reverts labeling PUBLIC_ROLE', async function () {
  765. await expectRevertCustomError(
  766. this.manager.labelRole(this.roles.PUBLIC.id, 'Some label', { from: admin }),
  767. 'AccessManagerLockedRole',
  768. [this.roles.PUBLIC.id],
  769. );
  770. });
  771. it('reverts labeling ADMIN_ROLE', async function () {
  772. await expectRevertCustomError(
  773. this.manager.labelRole(this.roles.ADMIN.id, 'Some label', { from: admin }),
  774. 'AccessManagerLockedRole',
  775. [this.roles.ADMIN.id],
  776. );
  777. });
  778. });
  779. describe('#setRoleAdmin', function () {
  780. describe('restrictions', function () {
  781. beforeEach('set method and args', function () {
  782. const method = 'setRoleAdmin(uint64,uint64)';
  783. const args = [93445, 84532];
  784. this.calldata = this.manager.contract.methods[method](...args).encodeABI();
  785. });
  786. shouldBehaveLikeDelayedAdminOperation();
  787. });
  788. it("sets any role's admin if called by an admin", async function () {
  789. expect(await this.manager.getRoleAdmin(this.roles.SOME.id)).to.be.bignumber.equal(this.roles.SOME_ADMIN.id);
  790. const { receipt } = await this.manager.setRoleAdmin(this.roles.SOME.id, this.roles.ADMIN.id, { from: admin });
  791. expectEvent(receipt, 'RoleAdminChanged', { roleId: this.roles.SOME.id, admin: this.roles.ADMIN.id });
  792. expect(await this.manager.getRoleAdmin(this.roles.SOME.id)).to.be.bignumber.equal(this.roles.ADMIN.id);
  793. });
  794. it('reverts setting PUBLIC_ROLE admin', async function () {
  795. await expectRevertCustomError(
  796. this.manager.setRoleAdmin(this.roles.PUBLIC.id, this.roles.ADMIN.id, { from: admin }),
  797. 'AccessManagerLockedRole',
  798. [this.roles.PUBLIC.id],
  799. );
  800. });
  801. it('reverts setting ADMIN_ROLE admin', async function () {
  802. await expectRevertCustomError(
  803. this.manager.setRoleAdmin(this.roles.ADMIN.id, this.roles.ADMIN.id, { from: admin }),
  804. 'AccessManagerLockedRole',
  805. [this.roles.ADMIN.id],
  806. );
  807. });
  808. });
  809. describe('#setRoleGuardian', function () {
  810. describe('restrictions', function () {
  811. beforeEach('set method and args', function () {
  812. const method = 'setRoleGuardian(uint64,uint64)';
  813. const args = [93445, 84532];
  814. this.calldata = this.manager.contract.methods[method](...args).encodeABI();
  815. });
  816. shouldBehaveLikeDelayedAdminOperation();
  817. });
  818. it("sets any role's guardian if called by an admin", async function () {
  819. expect(await this.manager.getRoleGuardian(this.roles.SOME.id)).to.be.bignumber.equal(
  820. this.roles.SOME_GUARDIAN.id,
  821. );
  822. const { receipt } = await this.manager.setRoleGuardian(this.roles.SOME.id, this.roles.ADMIN.id, {
  823. from: admin,
  824. });
  825. expectEvent(receipt, 'RoleGuardianChanged', { roleId: this.roles.SOME.id, guardian: this.roles.ADMIN.id });
  826. expect(await this.manager.getRoleGuardian(this.roles.SOME.id)).to.be.bignumber.equal(this.roles.ADMIN.id);
  827. });
  828. it('reverts setting PUBLIC_ROLE admin', async function () {
  829. await expectRevertCustomError(
  830. this.manager.setRoleGuardian(this.roles.PUBLIC.id, this.roles.ADMIN.id, { from: admin }),
  831. 'AccessManagerLockedRole',
  832. [this.roles.PUBLIC.id],
  833. );
  834. });
  835. it('reverts setting ADMIN_ROLE admin', async function () {
  836. await expectRevertCustomError(
  837. this.manager.setRoleGuardian(this.roles.ADMIN.id, this.roles.ADMIN.id, { from: admin }),
  838. 'AccessManagerLockedRole',
  839. [this.roles.ADMIN.id],
  840. );
  841. });
  842. });
  843. describe('#setGrantDelay', function () {
  844. describe('restrictions', function () {
  845. beforeEach('set method and args', function () {
  846. const method = 'setGrantDelay(uint64,uint32)';
  847. const args = [984910, time.duration.days(2)];
  848. this.calldata = this.manager.contract.methods[method](...args).encodeABI();
  849. });
  850. shouldBehaveLikeDelayedAdminOperation();
  851. });
  852. it('reverts setting grant delay for the PUBLIC_ROLE', async function () {
  853. await expectRevertCustomError(
  854. this.manager.setGrantDelay(this.roles.PUBLIC.id, web3.utils.toBN(69), { from: admin }),
  855. 'AccessManagerLockedRole',
  856. [this.roles.PUBLIC.id],
  857. );
  858. });
  859. describe('when increasing the delay', function () {
  860. const oldDelay = web3.utils.toBN(10);
  861. const newDelay = web3.utils.toBN(100);
  862. beforeEach('sets old delay', async function () {
  863. this.role = this.roles.SOME;
  864. await this.manager.$_setGrantDelay(this.role.id, oldDelay);
  865. await time.increase(MINSETBACK);
  866. expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay);
  867. });
  868. it('increases the delay after minsetback', async function () {
  869. const { receipt } = await this.manager.setGrantDelay(this.role.id, newDelay, { from: admin });
  870. const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
  871. expectEvent(receipt, 'RoleGrantDelayChanged', {
  872. roleId: this.role.id,
  873. delay: newDelay,
  874. since: timestamp.add(MINSETBACK),
  875. });
  876. expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay);
  877. await time.increase(MINSETBACK);
  878. expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(newDelay);
  879. });
  880. });
  881. describe('when reducing the delay', function () {
  882. const oldDelay = time.duration.days(10);
  883. beforeEach('sets old delay', async function () {
  884. this.role = this.roles.SOME;
  885. await this.manager.$_setGrantDelay(this.role.id, oldDelay);
  886. await time.increase(MINSETBACK);
  887. expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay);
  888. });
  889. describe('when the delay difference is shorter than minimum setback', function () {
  890. const newDelay = oldDelay.subn(1);
  891. it('increases the delay after minsetback', async function () {
  892. const { receipt } = await this.manager.setGrantDelay(this.role.id, newDelay, { from: admin });
  893. const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
  894. expectEvent(receipt, 'RoleGrantDelayChanged', {
  895. roleId: this.role.id,
  896. delay: newDelay,
  897. since: timestamp.add(MINSETBACK),
  898. });
  899. expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay);
  900. await time.increase(MINSETBACK);
  901. expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(newDelay);
  902. });
  903. });
  904. describe('when the delay difference is longer than minimum setback', function () {
  905. const newDelay = web3.utils.toBN(1);
  906. beforeEach('assert delay difference is higher than minsetback', function () {
  907. expect(oldDelay.sub(newDelay)).to.be.bignumber.gt(MINSETBACK);
  908. });
  909. it('increases the delay after delay difference', async function () {
  910. const setback = oldDelay.sub(newDelay);
  911. const { receipt } = await this.manager.setGrantDelay(this.role.id, newDelay, { from: admin });
  912. const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
  913. expectEvent(receipt, 'RoleGrantDelayChanged', {
  914. roleId: this.role.id,
  915. delay: newDelay,
  916. since: timestamp.add(setback),
  917. });
  918. expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(oldDelay);
  919. await time.increase(setback);
  920. expect(await this.manager.getRoleGrantDelay(this.role.id)).to.be.bignumber.equal(newDelay);
  921. });
  922. });
  923. });
  924. });
  925. describe('#setTargetAdminDelay', function () {
  926. describe('restrictions', function () {
  927. beforeEach('set method and args', function () {
  928. const method = 'setTargetAdminDelay(address,uint32)';
  929. const args = [someAddress, time.duration.days(3)];
  930. this.calldata = this.manager.contract.methods[method](...args).encodeABI();
  931. });
  932. shouldBehaveLikeDelayedAdminOperation();
  933. });
  934. describe('when increasing the delay', function () {
  935. const oldDelay = time.duration.days(10);
  936. const newDelay = time.duration.days(11);
  937. const target = someAddress;
  938. beforeEach('sets old delay', async function () {
  939. await this.manager.$_setTargetAdminDelay(target, oldDelay);
  940. await time.increase(MINSETBACK);
  941. expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay);
  942. });
  943. it('increases the delay after minsetback', async function () {
  944. const { receipt } = await this.manager.setTargetAdminDelay(target, newDelay, { from: admin });
  945. const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
  946. expectEvent(receipt, 'TargetAdminDelayUpdated', {
  947. target,
  948. delay: newDelay,
  949. since: timestamp.add(MINSETBACK),
  950. });
  951. expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay);
  952. await time.increase(MINSETBACK);
  953. expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(newDelay);
  954. });
  955. });
  956. describe('when reducing the delay', function () {
  957. const oldDelay = time.duration.days(10);
  958. const target = someAddress;
  959. beforeEach('sets old delay', async function () {
  960. await this.manager.$_setTargetAdminDelay(target, oldDelay);
  961. await time.increase(MINSETBACK);
  962. expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay);
  963. });
  964. describe('when the delay difference is shorter than minimum setback', function () {
  965. const newDelay = oldDelay.subn(1);
  966. it('increases the delay after minsetback', async function () {
  967. const { receipt } = await this.manager.setTargetAdminDelay(target, newDelay, { from: admin });
  968. const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
  969. expectEvent(receipt, 'TargetAdminDelayUpdated', {
  970. target,
  971. delay: newDelay,
  972. since: timestamp.add(MINSETBACK),
  973. });
  974. expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay);
  975. await time.increase(MINSETBACK);
  976. expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(newDelay);
  977. });
  978. });
  979. describe('when the delay difference is longer than minimum setback', function () {
  980. const newDelay = web3.utils.toBN(1);
  981. beforeEach('assert delay difference is higher than minsetback', function () {
  982. expect(oldDelay.sub(newDelay)).to.be.bignumber.gt(MINSETBACK);
  983. });
  984. it('increases the delay after delay difference', async function () {
  985. const setback = oldDelay.sub(newDelay);
  986. const { receipt } = await this.manager.setTargetAdminDelay(target, newDelay, { from: admin });
  987. const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
  988. expectEvent(receipt, 'TargetAdminDelayUpdated', {
  989. target,
  990. delay: newDelay,
  991. since: timestamp.add(setback),
  992. });
  993. expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(oldDelay);
  994. await time.increase(setback);
  995. expect(await this.manager.getTargetAdminDelay(target)).to.be.bignumber.equal(newDelay);
  996. });
  997. });
  998. });
  999. });
  1000. });
  1001. describe('not subject to a delay', function () {
  1002. describe('#updateAuthority', function () {
  1003. beforeEach('create a target and a new authority', async function () {
  1004. this.newAuthority = await AccessManager.new(admin);
  1005. this.newManagedTarget = await AccessManagedTarget.new(this.manager.address);
  1006. });
  1007. describe('restrictions', function () {
  1008. beforeEach('set method and args', function () {
  1009. const method = 'updateAuthority(address,address)';
  1010. const args = [this.newManagedTarget.address, this.newAuthority.address];
  1011. this.calldata = this.manager.contract.methods[method](...args).encodeABI();
  1012. });
  1013. shouldBehaveLikeNotDelayedAdminOperation();
  1014. });
  1015. it('changes the authority', async function () {
  1016. expect(await this.newManagedTarget.authority()).to.be.equal(this.manager.address);
  1017. const { tx } = await this.manager.updateAuthority(this.newManagedTarget.address, this.newAuthority.address, {
  1018. from: admin,
  1019. });
  1020. // Managed contract is responsible of notifying the change through an event
  1021. await expectEvent.inTransaction(tx, this.newManagedTarget, 'AuthorityUpdated', {
  1022. authority: this.newAuthority.address,
  1023. });
  1024. expect(await this.newManagedTarget.authority()).to.be.equal(this.newAuthority.address);
  1025. });
  1026. });
  1027. describe('#setTargetClosed', function () {
  1028. describe('restrictions', function () {
  1029. beforeEach('set method and args', function () {
  1030. const method = 'setTargetClosed(address,bool)';
  1031. const args = [someAddress, true];
  1032. this.calldata = this.manager.contract.methods[method](...args).encodeABI();
  1033. });
  1034. shouldBehaveLikeNotDelayedAdminOperation();
  1035. });
  1036. it('closes and opens a target', async function () {
  1037. const close = await this.manager.setTargetClosed(this.target.address, true, { from: admin });
  1038. expectEvent(close.receipt, 'TargetClosed', { target: this.target.address, closed: true });
  1039. expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(true);
  1040. const open = await this.manager.setTargetClosed(this.target.address, false, { from: admin });
  1041. expectEvent(open.receipt, 'TargetClosed', { target: this.target.address, closed: false });
  1042. expect(await this.manager.isTargetClosed(this.target.address)).to.be.equal(false);
  1043. });
  1044. it('reverts if closing the manager', async function () {
  1045. await expectRevertCustomError(
  1046. this.manager.setTargetClosed(this.manager.address, true, { from: admin }),
  1047. 'AccessManagerLockedAccount',
  1048. [this.manager.address],
  1049. );
  1050. });
  1051. });
  1052. describe('#setTargetFunctionRole', function () {
  1053. describe('restrictions', function () {
  1054. beforeEach('set method and args', function () {
  1055. const method = 'setTargetFunctionRole(address,bytes4[],uint64)';
  1056. const args = [someAddress, ['0x12345678'], 443342];
  1057. this.calldata = this.manager.contract.methods[method](...args).encodeABI();
  1058. });
  1059. shouldBehaveLikeNotDelayedAdminOperation();
  1060. });
  1061. const sigs = ['someFunction()', 'someOtherFunction(uint256)', 'oneMoreFunction(address,uint8)'].map(selector);
  1062. it('sets function roles', async function () {
  1063. for (const sig of sigs) {
  1064. expect(await this.manager.getTargetFunctionRole(this.target.address, sig)).to.be.bignumber.equal(
  1065. this.roles.ADMIN.id,
  1066. );
  1067. }
  1068. const { receipt: receipt1 } = await this.manager.setTargetFunctionRole(
  1069. this.target.address,
  1070. sigs,
  1071. this.roles.SOME.id,
  1072. {
  1073. from: admin,
  1074. },
  1075. );
  1076. for (const sig of sigs) {
  1077. expectEvent(receipt1, 'TargetFunctionRoleUpdated', {
  1078. target: this.target.address,
  1079. selector: sig,
  1080. roleId: this.roles.SOME.id,
  1081. });
  1082. expect(await this.manager.getTargetFunctionRole(this.target.address, sig)).to.be.bignumber.equal(
  1083. this.roles.SOME.id,
  1084. );
  1085. }
  1086. const { receipt: receipt2 } = await this.manager.setTargetFunctionRole(
  1087. this.target.address,
  1088. [sigs[1]],
  1089. this.roles.SOME_ADMIN.id,
  1090. {
  1091. from: admin,
  1092. },
  1093. );
  1094. expectEvent(receipt2, 'TargetFunctionRoleUpdated', {
  1095. target: this.target.address,
  1096. selector: sigs[1],
  1097. roleId: this.roles.SOME_ADMIN.id,
  1098. });
  1099. for (const sig of sigs) {
  1100. expect(await this.manager.getTargetFunctionRole(this.target.address, sig)).to.be.bignumber.equal(
  1101. sig == sigs[1] ? this.roles.SOME_ADMIN.id : this.roles.SOME.id,
  1102. );
  1103. }
  1104. });
  1105. });
  1106. describe('role admin operations', function () {
  1107. const ANOTHER_ADMIN = web3.utils.toBN(0xdeadc0de1);
  1108. const ANOTHER_ROLE = web3.utils.toBN(0xdeadc0de2);
  1109. beforeEach('set required role', async function () {
  1110. // Make admin a member of ANOTHER_ADMIN
  1111. await this.manager.$_grantRole(ANOTHER_ADMIN, admin, 0, 0);
  1112. await this.manager.$_setRoleAdmin(ANOTHER_ROLE, ANOTHER_ADMIN);
  1113. this.role = { id: ANOTHER_ADMIN };
  1114. this.user = user;
  1115. await this.manager.$_grantRole(this.role.id, this.user, 0, 0);
  1116. });
  1117. describe('#grantRole', function () {
  1118. describe('restrictions', function () {
  1119. beforeEach('set method and args', function () {
  1120. const method = 'grantRole(uint64,address,uint32)';
  1121. const args = [ANOTHER_ROLE, someAddress, 0];
  1122. this.calldata = this.manager.contract.methods[method](...args).encodeABI();
  1123. });
  1124. shouldBehaveLikeRoleAdminOperation(ANOTHER_ADMIN);
  1125. });
  1126. it('reverts when granting PUBLIC_ROLE', async function () {
  1127. await expectRevertCustomError(
  1128. this.manager.grantRole(this.roles.PUBLIC.id, user, 0, {
  1129. from: admin,
  1130. }),
  1131. 'AccessManagerLockedRole',
  1132. [this.roles.PUBLIC.id],
  1133. );
  1134. });
  1135. describe('when the user is not a role member', function () {
  1136. describe('with grant delay', function () {
  1137. beforeEach('set grant delay and grant role', async function () {
  1138. // Delay granting
  1139. this.grantDelay = time.duration.weeks(2);
  1140. await this.manager.$_setGrantDelay(ANOTHER_ROLE, this.grantDelay);
  1141. await time.increase(MINSETBACK);
  1142. // Grant role
  1143. this.executionDelay = time.duration.days(3);
  1144. expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([
  1145. false,
  1146. '0',
  1147. ]);
  1148. const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.executionDelay, {
  1149. from: admin,
  1150. });
  1151. this.receipt = receipt;
  1152. this.delay = this.grantDelay; // For shouldBehaveLikeDelay
  1153. });
  1154. shouldBehaveLikeDelay('grant', {
  1155. before() {
  1156. beforeEach('consume previously set grant delay', async function () {
  1157. // Consume previously set delay
  1158. await mine();
  1159. });
  1160. it('does not grant role to the user yet', async function () {
  1161. const timestamp = await clockFromReceipt.timestamp(this.receipt).then(web3.utils.toBN);
  1162. expectEvent(this.receipt, 'RoleGranted', {
  1163. roleId: ANOTHER_ROLE,
  1164. account: this.user,
  1165. since: timestamp.add(this.grantDelay),
  1166. delay: this.executionDelay,
  1167. newMember: true,
  1168. });
  1169. // Access is correctly stored
  1170. const access = await this.manager.getAccess(ANOTHER_ROLE, user);
  1171. expect(access[0]).to.be.bignumber.equal(timestamp.add(this.grantDelay)); // inEffectSince
  1172. expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay
  1173. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  1174. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  1175. // Not in effect yet
  1176. const currentTimestamp = await time.latest();
  1177. expect(currentTimestamp).to.be.a.bignumber.lt(access[0]);
  1178. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1179. false,
  1180. this.executionDelay.toString(),
  1181. ]);
  1182. });
  1183. },
  1184. after() {
  1185. beforeEach('consume previously set grant delay', async function () {
  1186. // Consume previously set delay
  1187. await mine();
  1188. });
  1189. it('grants role to the user', async function () {
  1190. const timestamp = await clockFromReceipt.timestamp(this.receipt).then(web3.utils.toBN);
  1191. expectEvent(this.receipt, 'RoleGranted', {
  1192. roleId: ANOTHER_ROLE,
  1193. account: this.user,
  1194. since: timestamp.add(this.grantDelay),
  1195. delay: this.executionDelay,
  1196. newMember: true,
  1197. });
  1198. // Access is correctly stored
  1199. const access = await this.manager.getAccess(ANOTHER_ROLE, user);
  1200. expect(access[0]).to.be.bignumber.equal(timestamp.add(this.grantDelay)); // inEffectSince
  1201. expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay
  1202. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  1203. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  1204. // Already in effect
  1205. const currentTimestamp = await time.latest();
  1206. expect(currentTimestamp).to.be.a.bignumber.equal(access[0]);
  1207. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1208. true,
  1209. this.executionDelay.toString(),
  1210. ]);
  1211. });
  1212. },
  1213. });
  1214. });
  1215. describe('without grant delay', function () {
  1216. beforeEach('set granting delay', async function () {
  1217. // Delay granting
  1218. this.grantDelay = 0;
  1219. await this.manager.$_setGrantDelay(ANOTHER_ROLE, this.grantDelay);
  1220. await time.increase(MINSETBACK);
  1221. });
  1222. it('immediately grants the role to the user', async function () {
  1223. this.executionDelay = time.duration.days(6);
  1224. expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([
  1225. false,
  1226. '0',
  1227. ]);
  1228. const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.executionDelay, {
  1229. from: admin,
  1230. });
  1231. const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
  1232. expectEvent(receipt, 'RoleGranted', {
  1233. roleId: ANOTHER_ROLE,
  1234. account: this.user,
  1235. since: timestamp,
  1236. delay: this.executionDelay,
  1237. newMember: true,
  1238. });
  1239. // Access is correctly stored
  1240. const access = await this.manager.getAccess(ANOTHER_ROLE, user);
  1241. expect(access[0]).to.be.bignumber.equal(timestamp); // inEffectSince
  1242. expect(access[1]).to.be.bignumber.equal(this.executionDelay); // currentDelay
  1243. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  1244. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  1245. // Already in effect
  1246. const currentTimestamp = await time.latest();
  1247. expect(currentTimestamp).to.be.a.bignumber.equal(access[0]);
  1248. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1249. true,
  1250. this.executionDelay.toString(),
  1251. ]);
  1252. });
  1253. });
  1254. });
  1255. describe('when the user is already a role member', function () {
  1256. beforeEach('make user role member', async function () {
  1257. this.previousExecutionDelay = time.duration.days(6);
  1258. await this.manager.$_grantRole(ANOTHER_ROLE, this.user, 0, this.previousExecutionDelay);
  1259. this.oldAccess = await this.manager.getAccess(ANOTHER_ROLE, user);
  1260. });
  1261. describe('with grant delay', function () {
  1262. beforeEach('set granting delay', async function () {
  1263. // Delay granting
  1264. const grantDelay = time.duration.weeks(2);
  1265. await this.manager.$_setGrantDelay(ANOTHER_ROLE, grantDelay);
  1266. await time.increase(MINSETBACK);
  1267. });
  1268. describe('when increasing the execution delay', function () {
  1269. beforeEach('set increased new execution delay', async function () {
  1270. expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([
  1271. true,
  1272. this.previousExecutionDelay.toString(),
  1273. ]);
  1274. this.newExecutionDelay = this.previousExecutionDelay.add(time.duration.days(4));
  1275. });
  1276. it('emits event and immediately changes the execution delay', async function () {
  1277. expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([
  1278. true,
  1279. this.previousExecutionDelay.toString(),
  1280. ]);
  1281. const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay, {
  1282. from: admin,
  1283. });
  1284. const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
  1285. expectEvent(receipt, 'RoleGranted', {
  1286. roleId: ANOTHER_ROLE,
  1287. account: this.user,
  1288. since: timestamp,
  1289. delay: this.newExecutionDelay,
  1290. newMember: false,
  1291. });
  1292. // Access is correctly stored
  1293. const access = await this.manager.getAccess(ANOTHER_ROLE, user);
  1294. expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince
  1295. expect(access[1]).to.be.bignumber.equal(this.newExecutionDelay); // currentDelay
  1296. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  1297. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  1298. // Already in effect
  1299. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1300. true,
  1301. this.newExecutionDelay.toString(),
  1302. ]);
  1303. });
  1304. });
  1305. describe('when decreasing the execution delay', function () {
  1306. beforeEach('decrease execution delay', async function () {
  1307. expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([
  1308. true,
  1309. this.previousExecutionDelay.toString(),
  1310. ]);
  1311. this.newExecutionDelay = this.previousExecutionDelay.sub(time.duration.days(4));
  1312. const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay, {
  1313. from: admin,
  1314. });
  1315. this.grantTimestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
  1316. this.receipt = receipt;
  1317. this.delay = this.previousExecutionDelay.sub(this.newExecutionDelay); // For shouldBehaveLikeDelay
  1318. });
  1319. it('emits event', function () {
  1320. expectEvent(this.receipt, 'RoleGranted', {
  1321. roleId: ANOTHER_ROLE,
  1322. account: this.user,
  1323. since: this.grantTimestamp.add(this.delay),
  1324. delay: this.newExecutionDelay,
  1325. newMember: false,
  1326. });
  1327. });
  1328. shouldBehaveLikeDelay('execution delay effect', {
  1329. before() {
  1330. beforeEach('consume effect delay', async function () {
  1331. // Consume previously set delay
  1332. await mine();
  1333. });
  1334. it('does not change the execution delay yet', async function () {
  1335. // Access is correctly stored
  1336. const access = await this.manager.getAccess(ANOTHER_ROLE, user);
  1337. expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince
  1338. expect(access[1]).to.be.bignumber.equal(this.previousExecutionDelay); // currentDelay
  1339. expect(access[2]).to.be.bignumber.equal(this.newExecutionDelay); // pendingDelay
  1340. expect(access[3]).to.be.bignumber.equal(this.grantTimestamp.add(this.delay)); // pendingDelayEffect
  1341. // Not in effect yet
  1342. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1343. true,
  1344. this.previousExecutionDelay.toString(),
  1345. ]);
  1346. });
  1347. },
  1348. after() {
  1349. beforeEach('consume effect delay', async function () {
  1350. // Consume previously set delay
  1351. await mine();
  1352. });
  1353. it('changes the execution delay', async function () {
  1354. // Access is correctly stored
  1355. const access = await this.manager.getAccess(ANOTHER_ROLE, user);
  1356. expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince
  1357. expect(access[1]).to.be.bignumber.equal(this.newExecutionDelay); // currentDelay
  1358. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  1359. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  1360. // Already in effect
  1361. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1362. true,
  1363. this.newExecutionDelay.toString(),
  1364. ]);
  1365. });
  1366. },
  1367. });
  1368. });
  1369. });
  1370. describe('without grant delay', function () {
  1371. beforeEach('set granting delay', async function () {
  1372. // Delay granting
  1373. const grantDelay = 0;
  1374. await this.manager.$_setGrantDelay(ANOTHER_ROLE, grantDelay);
  1375. await time.increase(MINSETBACK);
  1376. });
  1377. describe('when increasing the execution delay', function () {
  1378. beforeEach('set increased new execution delay', async function () {
  1379. expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([
  1380. true,
  1381. this.previousExecutionDelay.toString(),
  1382. ]);
  1383. this.newExecutionDelay = this.previousExecutionDelay.add(time.duration.days(4));
  1384. });
  1385. it('emits event and immediately changes the execution delay', async function () {
  1386. expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([
  1387. true,
  1388. this.previousExecutionDelay.toString(),
  1389. ]);
  1390. const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay, {
  1391. from: admin,
  1392. });
  1393. const timestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
  1394. expectEvent(receipt, 'RoleGranted', {
  1395. roleId: ANOTHER_ROLE,
  1396. account: this.user,
  1397. since: timestamp,
  1398. delay: this.newExecutionDelay,
  1399. newMember: false,
  1400. });
  1401. // Access is correctly stored
  1402. const access = await this.manager.getAccess(ANOTHER_ROLE, user);
  1403. expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince
  1404. expect(access[1]).to.be.bignumber.equal(this.newExecutionDelay); // currentDelay
  1405. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  1406. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  1407. // Already in effect
  1408. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1409. true,
  1410. this.newExecutionDelay.toString(),
  1411. ]);
  1412. });
  1413. });
  1414. describe('when decreasing the execution delay', function () {
  1415. beforeEach('decrease execution delay', async function () {
  1416. expect(await this.manager.hasRole(ANOTHER_ROLE, this.user).then(formatAccess)).to.be.deep.equal([
  1417. true,
  1418. this.previousExecutionDelay.toString(),
  1419. ]);
  1420. this.newExecutionDelay = this.previousExecutionDelay.sub(time.duration.days(4));
  1421. const { receipt } = await this.manager.grantRole(ANOTHER_ROLE, this.user, this.newExecutionDelay, {
  1422. from: admin,
  1423. });
  1424. this.grantTimestamp = await clockFromReceipt.timestamp(receipt).then(web3.utils.toBN);
  1425. this.receipt = receipt;
  1426. this.delay = this.previousExecutionDelay.sub(this.newExecutionDelay); // For shouldBehaveLikeDelay
  1427. });
  1428. it('emits event', function () {
  1429. expectEvent(this.receipt, 'RoleGranted', {
  1430. roleId: ANOTHER_ROLE,
  1431. account: this.user,
  1432. since: this.grantTimestamp.add(this.delay),
  1433. delay: this.newExecutionDelay,
  1434. newMember: false,
  1435. });
  1436. });
  1437. shouldBehaveLikeDelay('execution delay effect', {
  1438. before() {
  1439. beforeEach('consume effect delay', async function () {
  1440. // Consume previously set delay
  1441. await mine();
  1442. });
  1443. it('does not change the execution delay yet', async function () {
  1444. // Access is correctly stored
  1445. const access = await this.manager.getAccess(ANOTHER_ROLE, user);
  1446. expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince
  1447. expect(access[1]).to.be.bignumber.equal(this.previousExecutionDelay); // currentDelay
  1448. expect(access[2]).to.be.bignumber.equal(this.newExecutionDelay); // pendingDelay
  1449. expect(access[3]).to.be.bignumber.equal(this.grantTimestamp.add(this.delay)); // pendingDelayEffect
  1450. // Not in effect yet
  1451. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1452. true,
  1453. this.previousExecutionDelay.toString(),
  1454. ]);
  1455. });
  1456. },
  1457. after() {
  1458. beforeEach('consume effect delay', async function () {
  1459. // Consume previously set delay
  1460. await mine();
  1461. });
  1462. it('changes the execution delay', async function () {
  1463. // Access is correctly stored
  1464. const access = await this.manager.getAccess(ANOTHER_ROLE, user);
  1465. expect(access[0]).to.be.bignumber.equal(this.oldAccess[0]); // inEffectSince
  1466. expect(access[1]).to.be.bignumber.equal(this.newExecutionDelay); // currentDelay
  1467. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  1468. expect(access[3]).to.be.bignumber.equal('0'); // pendingDelayEffect
  1469. // Already in effect
  1470. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1471. true,
  1472. this.newExecutionDelay.toString(),
  1473. ]);
  1474. });
  1475. },
  1476. });
  1477. });
  1478. });
  1479. });
  1480. });
  1481. describe('#revokeRole', function () {
  1482. describe('restrictions', function () {
  1483. beforeEach('set method and args', async function () {
  1484. const method = 'revokeRole(uint64,address)';
  1485. const args = [ANOTHER_ROLE, someAddress];
  1486. this.calldata = this.manager.contract.methods[method](...args).encodeABI();
  1487. // Need to be set before revoking
  1488. await this.manager.$_grantRole(...args, 0, 0);
  1489. });
  1490. shouldBehaveLikeRoleAdminOperation(ANOTHER_ADMIN);
  1491. });
  1492. describe('when role has been granted', function () {
  1493. beforeEach('grant role with grant delay', async function () {
  1494. this.grantDelay = time.duration.weeks(1);
  1495. await this.manager.$_grantRole(ANOTHER_ROLE, user, this.grantDelay, 0);
  1496. this.delay = this.grantDelay; // For shouldBehaveLikeDelay
  1497. });
  1498. shouldBehaveLikeDelay('grant', {
  1499. before() {
  1500. beforeEach('consume previously set grant delay', async function () {
  1501. // Consume previously set delay
  1502. await mine();
  1503. });
  1504. it('revokes a granted role that will take effect in the future', async function () {
  1505. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1506. false,
  1507. '0',
  1508. ]);
  1509. const { receipt } = await this.manager.revokeRole(ANOTHER_ROLE, user, { from: admin });
  1510. expectEvent(receipt, 'RoleRevoked', { roleId: ANOTHER_ROLE, account: user });
  1511. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1512. false,
  1513. '0',
  1514. ]);
  1515. const access = await this.manager.getAccess(ANOTHER_ROLE, user);
  1516. expect(access[0]).to.be.bignumber.equal('0'); // inRoleSince
  1517. expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
  1518. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  1519. expect(access[3]).to.be.bignumber.equal('0'); // effect
  1520. });
  1521. },
  1522. after() {
  1523. beforeEach('consume previously set grant delay', async function () {
  1524. // Consume previously set delay
  1525. await mine();
  1526. });
  1527. it('revokes a granted role that already took effect', async function () {
  1528. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1529. true,
  1530. '0',
  1531. ]);
  1532. const { receipt } = await this.manager.revokeRole(ANOTHER_ROLE, user, { from: admin });
  1533. expectEvent(receipt, 'RoleRevoked', { roleId: ANOTHER_ROLE, account: user });
  1534. expect(await this.manager.hasRole(ANOTHER_ROLE, user).then(formatAccess)).to.be.deep.equal([
  1535. false,
  1536. '0',
  1537. ]);
  1538. const access = await this.manager.getAccess(ANOTHER_ROLE, user);
  1539. expect(access[0]).to.be.bignumber.equal('0'); // inRoleSince
  1540. expect(access[1]).to.be.bignumber.equal('0'); // currentDelay
  1541. expect(access[2]).to.be.bignumber.equal('0'); // pendingDelay
  1542. expect(access[3]).to.be.bignumber.equal('0'); // effect
  1543. });
  1544. },
  1545. });
  1546. });
  1547. describe('when role has not been granted', function () {
  1548. it('has no effect', async function () {
  1549. expect(await this.manager.hasRole(this.roles.SOME.id, user).then(formatAccess)).to.be.deep.equal([
  1550. false,
  1551. '0',
  1552. ]);
  1553. const { receipt } = await this.manager.revokeRole(this.roles.SOME.id, user, { from: manager });
  1554. expectEvent.notEmitted(receipt, 'RoleRevoked', { roleId: ANOTHER_ROLE, account: user });
  1555. expect(await this.manager.hasRole(this.roles.SOME.id, user).then(formatAccess)).to.be.deep.equal([
  1556. false,
  1557. '0',
  1558. ]);
  1559. });
  1560. });
  1561. it('reverts revoking PUBLIC_ROLE', async function () {
  1562. await expectRevertCustomError(
  1563. this.manager.revokeRole(this.roles.PUBLIC.id, user, { from: admin }),
  1564. 'AccessManagerLockedRole',
  1565. [this.roles.PUBLIC.id],
  1566. );
  1567. });
  1568. });
  1569. });
  1570. describe('self role operations', function () {
  1571. describe('#renounceRole', function () {
  1572. beforeEach('grant role', async function () {
  1573. this.role = { id: web3.utils.toBN(783164) };
  1574. this.caller = user;
  1575. await this.manager.$_grantRole(this.role.id, this.caller, 0, 0);
  1576. });
  1577. it('renounces a role', async function () {
  1578. expect(await this.manager.hasRole(this.role.id, this.caller).then(formatAccess)).to.be.deep.equal([
  1579. true,
  1580. '0',
  1581. ]);
  1582. const { receipt } = await this.manager.renounceRole(this.role.id, this.caller, {
  1583. from: this.caller,
  1584. });
  1585. expectEvent(receipt, 'RoleRevoked', {
  1586. roleId: this.role.id,
  1587. account: this.caller,
  1588. });
  1589. expect(await this.manager.hasRole(this.role.id, this.caller).then(formatAccess)).to.be.deep.equal([
  1590. false,
  1591. '0',
  1592. ]);
  1593. });
  1594. it('reverts if renouncing the PUBLIC_ROLE', async function () {
  1595. await expectRevertCustomError(
  1596. this.manager.renounceRole(this.roles.PUBLIC.id, this.caller, {
  1597. from: this.caller,
  1598. }),
  1599. 'AccessManagerLockedRole',
  1600. [this.roles.PUBLIC.id],
  1601. );
  1602. });
  1603. it('reverts if renouncing with bad caller confirmation', async function () {
  1604. await expectRevertCustomError(
  1605. this.manager.renounceRole(this.role.id, someAddress, {
  1606. from: this.caller,
  1607. }),
  1608. 'AccessManagerBadConfirmation',
  1609. [],
  1610. );
  1611. });
  1612. });
  1613. });
  1614. });
  1615. });
  1616. describe('access managed target operations', function () {
  1617. describe('when calling a restricted target function', function () {
  1618. const method = 'fnRestricted()';
  1619. beforeEach('set required role', function () {
  1620. this.role = { id: web3.utils.toBN(3597243) };
  1621. this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id);
  1622. });
  1623. describe('restrictions', function () {
  1624. beforeEach('set method and args', function () {
  1625. this.calldata = this.target.contract.methods[method]().encodeABI();
  1626. this.caller = user;
  1627. });
  1628. shouldBehaveLikeAManagedRestrictedOperation();
  1629. });
  1630. it('succeeds called by a role member', async function () {
  1631. await this.manager.$_grantRole(this.role.id, user, 0, 0);
  1632. const { receipt } = await this.target.methods[method]({
  1633. data: this.calldata,
  1634. from: user,
  1635. });
  1636. expectEvent(receipt, 'CalledRestricted', {
  1637. caller: user,
  1638. });
  1639. });
  1640. });
  1641. describe('when calling a non-restricted target function', function () {
  1642. const method = 'fnUnrestricted()';
  1643. beforeEach('set required role', async function () {
  1644. this.role = { id: web3.utils.toBN(879435) };
  1645. await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id);
  1646. });
  1647. it('succeeds called by anyone', async function () {
  1648. const { receipt } = await this.target.methods[method]({
  1649. data: this.calldata,
  1650. from: user,
  1651. });
  1652. expectEvent(receipt, 'CalledUnrestricted', {
  1653. caller: user,
  1654. });
  1655. });
  1656. });
  1657. });
  1658. describe('#schedule', function () {
  1659. const method = 'fnRestricted()';
  1660. beforeEach('set target function role', async function () {
  1661. this.role = { id: web3.utils.toBN(498305) };
  1662. this.caller = user;
  1663. await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id);
  1664. await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay
  1665. this.calldata = this.target.contract.methods[method]().encodeABI();
  1666. this.delay = time.duration.weeks(2);
  1667. });
  1668. describe('restrictions', function () {
  1669. shouldBehaveLikeCanCall({
  1670. closed() {
  1671. it('reverts as AccessManagerUnauthorizedCall', async function () {
  1672. await expectRevertCustomError(
  1673. scheduleOperation(this.manager, {
  1674. caller: this.caller,
  1675. target: this.target.address,
  1676. calldata: this.calldata,
  1677. delay: this.delay,
  1678. }),
  1679. 'AccessManagerUnauthorizedCall',
  1680. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  1681. );
  1682. });
  1683. },
  1684. open: {
  1685. callerIsTheManager: {
  1686. executing() {
  1687. it.skip('is not reachable because schedule is not restrictable');
  1688. },
  1689. notExecuting() {
  1690. it('reverts as AccessManagerUnauthorizedCall', async function () {
  1691. await expectRevertCustomError(
  1692. scheduleOperation(this.manager, {
  1693. caller: this.caller,
  1694. target: this.target.address,
  1695. calldata: this.calldata,
  1696. delay: this.delay,
  1697. }),
  1698. 'AccessManagerUnauthorizedCall',
  1699. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  1700. );
  1701. });
  1702. },
  1703. },
  1704. callerIsNotTheManager: {
  1705. publicRoleIsRequired() {
  1706. it('reverts as AccessManagerUnauthorizedCall', async function () {
  1707. // scheduleOperation is not used here because it alters the next block timestamp
  1708. await expectRevertCustomError(
  1709. this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, {
  1710. from: this.caller,
  1711. }),
  1712. 'AccessManagerUnauthorizedCall',
  1713. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  1714. );
  1715. });
  1716. },
  1717. specificRoleIsRequired: {
  1718. requiredRoleIsGranted: {
  1719. roleGrantingIsDelayed: {
  1720. callerHasAnExecutionDelay: {
  1721. beforeGrantDelay() {
  1722. it('reverts as AccessManagerUnauthorizedCall', async function () {
  1723. // scheduleOperation is not used here because it alters the next block timestamp
  1724. await expectRevertCustomError(
  1725. this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, {
  1726. from: this.caller,
  1727. }),
  1728. 'AccessManagerUnauthorizedCall',
  1729. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  1730. );
  1731. });
  1732. },
  1733. afterGrantDelay() {
  1734. it('succeeds', async function () {
  1735. // scheduleOperation is not used here because it alters the next block timestamp
  1736. await this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, {
  1737. from: this.caller,
  1738. });
  1739. });
  1740. },
  1741. },
  1742. callerHasNoExecutionDelay: {
  1743. beforeGrantDelay() {
  1744. it('reverts as AccessManagerUnauthorizedCall', async function () {
  1745. // scheduleOperation is not used here because it alters the next block timestamp
  1746. await expectRevertCustomError(
  1747. this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, {
  1748. from: this.caller,
  1749. }),
  1750. 'AccessManagerUnauthorizedCall',
  1751. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  1752. );
  1753. });
  1754. },
  1755. afterGrantDelay() {
  1756. it('reverts as AccessManagerUnauthorizedCall', async function () {
  1757. // scheduleOperation is not used here because it alters the next block timestamp
  1758. await expectRevertCustomError(
  1759. this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, {
  1760. from: this.caller,
  1761. }),
  1762. 'AccessManagerUnauthorizedCall',
  1763. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  1764. );
  1765. });
  1766. },
  1767. },
  1768. },
  1769. roleGrantingIsNotDelayed: {
  1770. callerHasAnExecutionDelay() {
  1771. it('succeeds', async function () {
  1772. await scheduleOperation(this.manager, {
  1773. caller: this.caller,
  1774. target: this.target.address,
  1775. calldata: this.calldata,
  1776. delay: this.delay,
  1777. });
  1778. });
  1779. },
  1780. callerHasNoExecutionDelay() {
  1781. it('reverts as AccessManagerUnauthorizedCall', async function () {
  1782. // scheduleOperation is not used here because it alters the next block timestamp
  1783. await expectRevertCustomError(
  1784. this.manager.schedule(this.target.address, this.calldata, MAX_UINT48, {
  1785. from: this.caller,
  1786. }),
  1787. 'AccessManagerUnauthorizedCall',
  1788. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  1789. );
  1790. });
  1791. },
  1792. },
  1793. },
  1794. requiredRoleIsNotGranted() {
  1795. it('reverts as AccessManagerUnauthorizedCall', async function () {
  1796. await expectRevertCustomError(
  1797. scheduleOperation(this.manager, {
  1798. caller: this.caller,
  1799. target: this.target.address,
  1800. calldata: this.calldata,
  1801. delay: this.delay,
  1802. }),
  1803. 'AccessManagerUnauthorizedCall',
  1804. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  1805. );
  1806. });
  1807. },
  1808. },
  1809. },
  1810. },
  1811. });
  1812. });
  1813. it('schedules an operation at the specified execution date if it is larger than caller execution delay', async function () {
  1814. const { operationId, scheduledAt, receipt } = await scheduleOperation(this.manager, {
  1815. caller: this.caller,
  1816. target: this.target.address,
  1817. calldata: this.calldata,
  1818. delay: this.delay,
  1819. });
  1820. expect(await this.manager.getSchedule(operationId)).to.be.bignumber.equal(scheduledAt.add(this.delay));
  1821. expectEvent(receipt, 'OperationScheduled', {
  1822. operationId,
  1823. nonce: '1',
  1824. schedule: scheduledAt.add(this.delay),
  1825. target: this.target.address,
  1826. data: this.calldata,
  1827. });
  1828. });
  1829. it('schedules an operation at the minimum execution date if no specified execution date (when == 0)', async function () {
  1830. const executionDelay = await time.duration.hours(72);
  1831. await this.manager.$_grantRole(this.role.id, this.caller, 0, executionDelay);
  1832. const timestamp = await time.latest();
  1833. const scheduledAt = timestamp.addn(1);
  1834. await setNextBlockTimestamp(scheduledAt);
  1835. const { receipt } = await this.manager.schedule(this.target.address, this.calldata, 0, {
  1836. from: this.caller,
  1837. });
  1838. const operationId = await this.manager.hashOperation(this.caller, this.target.address, this.calldata);
  1839. expect(await this.manager.getSchedule(operationId)).to.be.bignumber.equal(scheduledAt.add(executionDelay));
  1840. expectEvent(receipt, 'OperationScheduled', {
  1841. operationId,
  1842. nonce: '1',
  1843. schedule: scheduledAt.add(executionDelay),
  1844. target: this.target.address,
  1845. data: this.calldata,
  1846. });
  1847. });
  1848. it('increases the nonce of an operation scheduled more than once', async function () {
  1849. // Setup and check initial nonce
  1850. const expectedOperationId = await web3.utils.keccak256(
  1851. web3.eth.abi.encodeParameters(
  1852. ['address', 'address', 'bytes'],
  1853. [this.caller, this.target.address, this.calldata],
  1854. ),
  1855. );
  1856. expect(await this.manager.getNonce(expectedOperationId)).to.be.bignumber.eq('0');
  1857. // Schedule
  1858. const op1 = await scheduleOperation(this.manager, {
  1859. caller: this.caller,
  1860. target: this.target.address,
  1861. calldata: this.calldata,
  1862. delay: this.delay,
  1863. });
  1864. expectEvent(op1.receipt, 'OperationScheduled', {
  1865. operationId: op1.operationId,
  1866. nonce: '1',
  1867. schedule: op1.scheduledAt.add(this.delay),
  1868. target: this.target.address,
  1869. data: this.calldata,
  1870. });
  1871. expect(expectedOperationId).to.eq(op1.operationId);
  1872. // Consume
  1873. await time.increase(this.delay);
  1874. await this.manager.$_consumeScheduledOp(expectedOperationId);
  1875. // Check nonce
  1876. expect(await this.manager.getNonce(expectedOperationId)).to.be.bignumber.eq('1');
  1877. // Schedule again
  1878. const op2 = await scheduleOperation(this.manager, {
  1879. caller: this.caller,
  1880. target: this.target.address,
  1881. calldata: this.calldata,
  1882. delay: this.delay,
  1883. });
  1884. expectEvent(op2.receipt, 'OperationScheduled', {
  1885. operationId: op2.operationId,
  1886. nonce: '2',
  1887. schedule: op2.scheduledAt.add(this.delay),
  1888. target: this.target.address,
  1889. data: this.calldata,
  1890. });
  1891. expect(expectedOperationId).to.eq(op2.operationId);
  1892. // Check final nonce
  1893. expect(await this.manager.getNonce(expectedOperationId)).to.be.bignumber.eq('2');
  1894. });
  1895. it('reverts if the specified execution date is before the current timestamp + caller execution delay', async function () {
  1896. const executionDelay = time.duration.weeks(1).add(this.delay);
  1897. await this.manager.$_grantRole(this.role.id, this.caller, 0, executionDelay);
  1898. await expectRevertCustomError(
  1899. scheduleOperation(this.manager, {
  1900. caller: this.caller,
  1901. target: this.target.address,
  1902. calldata: this.calldata,
  1903. delay: this.delay,
  1904. }),
  1905. 'AccessManagerUnauthorizedCall',
  1906. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  1907. );
  1908. });
  1909. it('reverts if an operation is already schedule', async function () {
  1910. const { operationId } = await scheduleOperation(this.manager, {
  1911. caller: this.caller,
  1912. target: this.target.address,
  1913. calldata: this.calldata,
  1914. delay: this.delay,
  1915. });
  1916. await expectRevertCustomError(
  1917. scheduleOperation(this.manager, {
  1918. caller: this.caller,
  1919. target: this.target.address,
  1920. calldata: this.calldata,
  1921. delay: this.delay,
  1922. }),
  1923. 'AccessManagerAlreadyScheduled',
  1924. [operationId],
  1925. );
  1926. });
  1927. it('panics scheduling calldata with less than 4 bytes', async function () {
  1928. const calldata = '0x1234'; // 2 bytes
  1929. // Managed contract
  1930. await expectRevert.unspecified(
  1931. scheduleOperation(this.manager, {
  1932. caller: this.caller,
  1933. target: this.target.address,
  1934. calldata: calldata,
  1935. delay: this.delay,
  1936. }),
  1937. );
  1938. // Manager contract
  1939. await expectRevert.unspecified(
  1940. scheduleOperation(this.manager, {
  1941. caller: this.caller,
  1942. target: this.manager.address,
  1943. calldata: calldata,
  1944. delay: this.delay,
  1945. }),
  1946. );
  1947. });
  1948. it('reverts scheduling an unknown operation to the manager', async function () {
  1949. const calldata = '0x12345678';
  1950. await expectRevertCustomError(
  1951. scheduleOperation(this.manager, {
  1952. caller: this.caller,
  1953. target: this.manager.address,
  1954. calldata,
  1955. delay: this.delay,
  1956. }),
  1957. 'AccessManagerUnauthorizedCall',
  1958. [this.caller, this.manager.address, calldata],
  1959. );
  1960. });
  1961. });
  1962. describe('#execute', function () {
  1963. const method = 'fnRestricted()';
  1964. beforeEach('set target function role', async function () {
  1965. this.role = { id: web3.utils.toBN(9825430) };
  1966. this.caller = user;
  1967. await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id);
  1968. await this.manager.$_grantRole(this.role.id, this.caller, 0, 0);
  1969. this.calldata = this.target.contract.methods[method]().encodeABI();
  1970. });
  1971. describe('restrictions', function () {
  1972. shouldBehaveLikeCanCall({
  1973. closed() {
  1974. it('reverts as AccessManagerUnauthorizedCall', async function () {
  1975. await expectRevertCustomError(
  1976. this.manager.execute(this.target.address, this.calldata, { from: this.caller }),
  1977. 'AccessManagerUnauthorizedCall',
  1978. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  1979. );
  1980. });
  1981. },
  1982. open: {
  1983. callerIsTheManager: {
  1984. executing() {
  1985. it('succeeds', async function () {
  1986. await this.manager.execute(this.target.address, this.calldata, { from: this.caller });
  1987. });
  1988. },
  1989. notExecuting() {
  1990. it('reverts as AccessManagerUnauthorizedCall', async function () {
  1991. await expectRevertCustomError(
  1992. this.manager.execute(this.target.address, this.calldata, { from: this.caller }),
  1993. 'AccessManagerUnauthorizedCall',
  1994. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  1995. );
  1996. });
  1997. },
  1998. },
  1999. callerIsNotTheManager: {
  2000. publicRoleIsRequired() {
  2001. shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY);
  2002. },
  2003. specificRoleIsRequired: {
  2004. requiredRoleIsGranted: {
  2005. roleGrantingIsDelayed: {
  2006. callerHasAnExecutionDelay: {
  2007. beforeGrantDelay() {
  2008. it('reverts as AccessManagerUnauthorizedCall', async function () {
  2009. await expectRevertCustomError(
  2010. this.manager.execute(this.target.address, this.calldata, { from: this.caller }),
  2011. 'AccessManagerUnauthorizedCall',
  2012. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  2013. );
  2014. });
  2015. },
  2016. afterGrantDelay() {
  2017. beforeEach('define schedule delay', async function () {
  2018. // Consume previously set delay
  2019. await mine();
  2020. this.scheduleIn = time.duration.days(21);
  2021. });
  2022. shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH);
  2023. },
  2024. },
  2025. callerHasNoExecutionDelay: {
  2026. beforeGrantDelay() {
  2027. it('reverts as AccessManagerUnauthorizedCall', async function () {
  2028. await expectRevertCustomError(
  2029. this.manager.execute(this.target.address, this.calldata, { from: this.caller }),
  2030. 'AccessManagerUnauthorizedCall',
  2031. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  2032. );
  2033. });
  2034. },
  2035. afterGrantDelay() {
  2036. beforeEach('define schedule delay', async function () {
  2037. // Consume previously set delay
  2038. await mine();
  2039. });
  2040. shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY);
  2041. },
  2042. },
  2043. },
  2044. roleGrantingIsNotDelayed: {
  2045. callerHasAnExecutionDelay() {
  2046. beforeEach('define schedule delay', async function () {
  2047. this.scheduleIn = time.duration.days(15);
  2048. });
  2049. shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH);
  2050. },
  2051. callerHasNoExecutionDelay() {
  2052. shouldBehaveLikeSchedulableOperation(COMMON_SCHEDULABLE_PATH_IF_ZERO_DELAY);
  2053. },
  2054. },
  2055. },
  2056. requiredRoleIsNotGranted() {
  2057. it('reverts as AccessManagerUnauthorizedCall', async function () {
  2058. await expectRevertCustomError(
  2059. this.manager.execute(this.target.address, this.calldata, { from: this.caller }),
  2060. 'AccessManagerUnauthorizedCall',
  2061. [this.caller, this.target.address, this.calldata.substring(0, 10)],
  2062. );
  2063. });
  2064. },
  2065. },
  2066. },
  2067. },
  2068. });
  2069. });
  2070. it('executes with a delay consuming the scheduled operation', async function () {
  2071. const delay = time.duration.hours(4);
  2072. await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // Execution delay is needed so the operation is consumed
  2073. const { operationId } = await scheduleOperation(this.manager, {
  2074. caller: this.caller,
  2075. target: this.target.address,
  2076. calldata: this.calldata,
  2077. delay,
  2078. });
  2079. await time.increase(delay);
  2080. const { receipt } = await this.manager.execute(this.target.address, this.calldata, { from: this.caller });
  2081. expectEvent(receipt, 'OperationExecuted', {
  2082. operationId,
  2083. nonce: '1',
  2084. });
  2085. expect(await this.manager.getSchedule(operationId)).to.be.bignumber.equal('0');
  2086. });
  2087. it('executes with no delay consuming a scheduled operation', async function () {
  2088. const delay = time.duration.hours(4);
  2089. // give caller an execution delay
  2090. await this.manager.$_grantRole(this.role.id, this.caller, 0, 1);
  2091. const { operationId } = await scheduleOperation(this.manager, {
  2092. caller: this.caller,
  2093. target: this.target.address,
  2094. calldata: this.calldata,
  2095. delay,
  2096. });
  2097. // remove the execution delay
  2098. await this.manager.$_grantRole(this.role.id, this.caller, 0, 0);
  2099. await time.increase(delay);
  2100. const { receipt } = await this.manager.execute(this.target.address, this.calldata, { from: this.caller });
  2101. expectEvent(receipt, 'OperationExecuted', {
  2102. operationId,
  2103. nonce: '1',
  2104. });
  2105. expect(await this.manager.getSchedule(operationId)).to.be.bignumber.equal('0');
  2106. });
  2107. it('keeps the original _executionId after finishing the call', async function () {
  2108. const executionIdBefore = await getStorageAt(this.manager.address, EXECUTION_ID_STORAGE_SLOT);
  2109. await this.manager.execute(this.target.address, this.calldata, { from: this.caller });
  2110. const executionIdAfter = await getStorageAt(this.manager.address, EXECUTION_ID_STORAGE_SLOT);
  2111. expect(executionIdBefore).to.be.bignumber.equal(executionIdAfter);
  2112. });
  2113. it('reverts executing twice', async function () {
  2114. const delay = time.duration.hours(2);
  2115. await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // Execution delay is needed so the operation is consumed
  2116. const { operationId } = await scheduleOperation(this.manager, {
  2117. caller: this.caller,
  2118. target: this.target.address,
  2119. calldata: this.calldata,
  2120. delay,
  2121. });
  2122. await time.increase(delay);
  2123. await this.manager.execute(this.target.address, this.calldata, { from: this.caller });
  2124. await expectRevertCustomError(
  2125. this.manager.execute(this.target.address, this.calldata, { from: this.caller }),
  2126. 'AccessManagerNotScheduled',
  2127. [operationId],
  2128. );
  2129. });
  2130. });
  2131. describe('#consumeScheduledOp', function () {
  2132. beforeEach('define scheduling parameters', async function () {
  2133. const method = 'fnRestricted()';
  2134. this.caller = this.target.address;
  2135. this.calldata = this.target.contract.methods[method]().encodeABI();
  2136. this.role = { id: web3.utils.toBN(9834983) };
  2137. await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.role.id);
  2138. await this.manager.$_grantRole(this.role.id, this.caller, 0, 1); // nonzero execution delay
  2139. this.scheduleIn = time.duration.hours(10); // For shouldBehaveLikeSchedulableOperation
  2140. });
  2141. describe('when caller is not consuming scheduled operation', function () {
  2142. beforeEach('set consuming false', async function () {
  2143. await this.target.setIsConsumingScheduledOp(false, `0x${CONSUMING_SCHEDULE_STORAGE_SLOT.toString(16)}`);
  2144. });
  2145. it('reverts as AccessManagerUnauthorizedConsume', async function () {
  2146. await impersonate(this.caller);
  2147. await expectRevertCustomError(
  2148. this.manager.consumeScheduledOp(this.caller, this.calldata, { from: this.caller }),
  2149. 'AccessManagerUnauthorizedConsume',
  2150. [this.caller],
  2151. );
  2152. });
  2153. });
  2154. describe('when caller is consuming scheduled operation', function () {
  2155. beforeEach('set consuming true', async function () {
  2156. await this.target.setIsConsumingScheduledOp(true, `0x${CONSUMING_SCHEDULE_STORAGE_SLOT.toString(16)}`);
  2157. });
  2158. shouldBehaveLikeSchedulableOperation({
  2159. scheduled: {
  2160. before() {
  2161. it('reverts as AccessManagerNotReady', async function () {
  2162. await impersonate(this.caller);
  2163. await expectRevertCustomError(
  2164. this.manager.consumeScheduledOp(this.caller, this.calldata, { from: this.caller }),
  2165. 'AccessManagerNotReady',
  2166. [this.operationId],
  2167. );
  2168. });
  2169. },
  2170. after() {
  2171. it('consumes the scheduled operation and resets timepoint', async function () {
  2172. expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal(
  2173. this.scheduledAt.add(this.scheduleIn),
  2174. );
  2175. await impersonate(this.caller);
  2176. const { receipt } = await this.manager.consumeScheduledOp(this.caller, this.calldata, {
  2177. from: this.caller,
  2178. });
  2179. expectEvent(receipt, 'OperationExecuted', {
  2180. operationId: this.operationId,
  2181. nonce: '1',
  2182. });
  2183. expect(await this.manager.getSchedule(this.operationId)).to.be.bignumber.equal('0');
  2184. });
  2185. },
  2186. expired() {
  2187. it('reverts as AccessManagerExpired', async function () {
  2188. await impersonate(this.caller);
  2189. await expectRevertCustomError(
  2190. this.manager.consumeScheduledOp(this.caller, this.calldata, { from: this.caller }),
  2191. 'AccessManagerExpired',
  2192. [this.operationId],
  2193. );
  2194. });
  2195. },
  2196. },
  2197. notScheduled() {
  2198. it('reverts as AccessManagerNotScheduled', async function () {
  2199. await impersonate(this.caller);
  2200. await expectRevertCustomError(
  2201. this.manager.consumeScheduledOp(this.caller, this.calldata, { from: this.caller }),
  2202. 'AccessManagerNotScheduled',
  2203. [this.operationId],
  2204. );
  2205. });
  2206. },
  2207. });
  2208. });
  2209. });
  2210. describe('#cancelScheduledOp', function () {
  2211. const method = 'fnRestricted()';
  2212. beforeEach('setup scheduling', async function () {
  2213. this.caller = this.roles.SOME.members[0];
  2214. await this.manager.$_setTargetFunctionRole(this.target.address, selector(method), this.roles.SOME.id);
  2215. await this.manager.$_grantRole(this.roles.SOME.id, this.caller, 0, 1); // nonzero execution delay
  2216. this.calldata = await this.target.contract.methods[method]().encodeABI();
  2217. this.scheduleIn = time.duration.days(10); // For shouldBehaveLikeSchedulableOperation
  2218. });
  2219. shouldBehaveLikeSchedulableOperation({
  2220. scheduled: {
  2221. before() {
  2222. describe('when caller is the scheduler', function () {
  2223. it('succeeds', async function () {
  2224. await this.manager.cancel(this.caller, this.target.address, this.calldata, { from: this.caller });
  2225. });
  2226. });
  2227. describe('when caller is an admin', function () {
  2228. it('succeeds', async function () {
  2229. await this.manager.cancel(this.caller, this.target.address, this.calldata, {
  2230. from: this.roles.ADMIN.members[0],
  2231. });
  2232. });
  2233. });
  2234. describe('when caller is the role guardian', function () {
  2235. it('succeeds', async function () {
  2236. await this.manager.cancel(this.caller, this.target.address, this.calldata, {
  2237. from: this.roles.SOME_GUARDIAN.members[0],
  2238. });
  2239. });
  2240. });
  2241. describe('when caller is any other account', function () {
  2242. it('reverts as AccessManagerUnauthorizedCancel', async function () {
  2243. await expectRevertCustomError(
  2244. this.manager.cancel(this.caller, this.target.address, this.calldata, { from: other }),
  2245. 'AccessManagerUnauthorizedCancel',
  2246. [other, this.caller, this.target.address, selector(method)],
  2247. );
  2248. });
  2249. });
  2250. },
  2251. after() {
  2252. it('succeeds', async function () {
  2253. await this.manager.cancel(this.caller, this.target.address, this.calldata, { from: this.caller });
  2254. });
  2255. },
  2256. expired() {
  2257. it('succeeds', async function () {
  2258. await this.manager.cancel(this.caller, this.target.address, this.calldata, { from: this.caller });
  2259. });
  2260. },
  2261. },
  2262. notScheduled() {
  2263. it('reverts as AccessManagerNotScheduled', async function () {
  2264. await expectRevertCustomError(
  2265. this.manager.cancel(this.caller, this.target.address, this.calldata),
  2266. 'AccessManagerNotScheduled',
  2267. [this.operationId],
  2268. );
  2269. });
  2270. },
  2271. });
  2272. it('cancels an operation and resets schedule', async function () {
  2273. const { operationId } = await scheduleOperation(this.manager, {
  2274. caller: this.caller,
  2275. target: this.target.address,
  2276. calldata: this.calldata,
  2277. delay: this.scheduleIn,
  2278. });
  2279. const { receipt } = await this.manager.cancel(this.caller, this.target.address, this.calldata, {
  2280. from: this.caller,
  2281. });
  2282. expectEvent(receipt, 'OperationCanceled', {
  2283. operationId,
  2284. nonce: '1',
  2285. });
  2286. expect(await this.manager.getSchedule(operationId)).to.be.bignumber.eq('0');
  2287. });
  2288. });
  2289. describe('with Ownable target contract', function () {
  2290. const roleId = web3.utils.toBN(1);
  2291. beforeEach(async function () {
  2292. this.ownable = await Ownable.new(this.manager.address);
  2293. // add user to role
  2294. await this.manager.$_grantRole(roleId, user, 0, 0);
  2295. });
  2296. it('initial state', async function () {
  2297. expect(await this.ownable.owner()).to.be.equal(this.manager.address);
  2298. });
  2299. describe('Contract is closed', function () {
  2300. beforeEach(async function () {
  2301. await this.manager.$_setTargetClosed(this.ownable.address, true);
  2302. });
  2303. it('directly call: reverts', async function () {
  2304. await expectRevertCustomError(this.ownable.$_checkOwner({ from: user }), 'OwnableUnauthorizedAccount', [user]);
  2305. });
  2306. it('relayed call (with role): reverts', async function () {
  2307. await expectRevertCustomError(
  2308. this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: user }),
  2309. 'AccessManagerUnauthorizedCall',
  2310. [user, this.ownable.address, selector('$_checkOwner()')],
  2311. );
  2312. });
  2313. it('relayed call (without role): reverts', async function () {
  2314. await expectRevertCustomError(
  2315. this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: other }),
  2316. 'AccessManagerUnauthorizedCall',
  2317. [other, this.ownable.address, selector('$_checkOwner()')],
  2318. );
  2319. });
  2320. });
  2321. describe('Contract is managed', function () {
  2322. describe('function is open to specific role', function () {
  2323. beforeEach(async function () {
  2324. await this.manager.$_setTargetFunctionRole(this.ownable.address, selector('$_checkOwner()'), roleId);
  2325. });
  2326. it('directly call: reverts', async function () {
  2327. await expectRevertCustomError(this.ownable.$_checkOwner({ from: user }), 'OwnableUnauthorizedAccount', [
  2328. user,
  2329. ]);
  2330. });
  2331. it('relayed call (with role): success', async function () {
  2332. await this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: user });
  2333. });
  2334. it('relayed call (without role): reverts', async function () {
  2335. await expectRevertCustomError(
  2336. this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: other }),
  2337. 'AccessManagerUnauthorizedCall',
  2338. [other, this.ownable.address, selector('$_checkOwner()')],
  2339. );
  2340. });
  2341. });
  2342. describe('function is open to public role', function () {
  2343. beforeEach(async function () {
  2344. await this.manager.$_setTargetFunctionRole(
  2345. this.ownable.address,
  2346. selector('$_checkOwner()'),
  2347. this.roles.PUBLIC.id,
  2348. );
  2349. });
  2350. it('directly call: reverts', async function () {
  2351. await expectRevertCustomError(this.ownable.$_checkOwner({ from: user }), 'OwnableUnauthorizedAccount', [
  2352. user,
  2353. ]);
  2354. });
  2355. it('relayed call (with role): success', async function () {
  2356. await this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: user });
  2357. });
  2358. it('relayed call (without role): success', async function () {
  2359. await this.manager.execute(this.ownable.address, selector('$_checkOwner()'), { from: other });
  2360. });
  2361. });
  2362. });
  2363. });
  2364. });