AccessControlDefaultAdminRules.spec 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. import "helpers/helpers.spec";
  2. import "methods/IAccessControlDefaultAdminRules.spec";
  3. import "methods/IAccessControl.spec";
  4. import "AccessControl.spec";
  5. use rule onlyGrantCanGrant filtered {
  6. f -> f.selector != sig:acceptDefaultAdminTransfer().selector
  7. }
  8. /*
  9. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  10. │ Definitions │
  11. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  12. */
  13. definition timeSanity(env e) returns bool =
  14. e.block.timestamp > 0 && e.block.timestamp + defaultAdminDelay(e) < max_uint48;
  15. definition delayChangeWaitSanity(env e, uint48 newDelay) returns bool =
  16. e.block.timestamp + delayChangeWait_(e, newDelay) < max_uint48;
  17. definition isSet(uint48 schedule) returns bool =
  18. schedule != 0;
  19. definition hasPassed(env e, uint48 schedule) returns bool =
  20. assert_uint256(schedule) < e.block.timestamp;
  21. definition increasingDelaySchedule(env e, uint48 newDelay) returns mathint =
  22. e.block.timestamp + min(newDelay, defaultAdminDelayIncreaseWait());
  23. definition decreasingDelaySchedule(env e, uint48 newDelay) returns mathint =
  24. e.block.timestamp + defaultAdminDelay(e) - newDelay;
  25. /*
  26. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  27. │ Invariant: defaultAdmin holds the DEFAULT_ADMIN_ROLE │
  28. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  29. */
  30. invariant defaultAdminConsistency(address account)
  31. (account == defaultAdmin() && account != 0) <=> hasRole(DEFAULT_ADMIN_ROLE(), account)
  32. {
  33. preserved with (env e) {
  34. require nonzerosender(e);
  35. }
  36. }
  37. /*
  38. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  39. │ Invariant: Only one account holds the DEFAULT_ADMIN_ROLE │
  40. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  41. */
  42. invariant singleDefaultAdmin(address account, address another)
  43. hasRole(DEFAULT_ADMIN_ROLE(), account) && hasRole(DEFAULT_ADMIN_ROLE(), another) => another == account
  44. {
  45. preserved {
  46. requireInvariant defaultAdminConsistency(account);
  47. requireInvariant defaultAdminConsistency(another);
  48. }
  49. }
  50. /*
  51. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  52. │ Invariant: DEFAULT_ADMIN_ROLE's admin is always DEFAULT_ADMIN_ROLE │
  53. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  54. */
  55. invariant defaultAdminRoleAdminConsistency()
  56. getRoleAdmin(DEFAULT_ADMIN_ROLE()) == DEFAULT_ADMIN_ROLE();
  57. /*
  58. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  59. │ Rule: owner is the defaultAdmin │
  60. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  61. */
  62. // Writing this as an invariant would be flagged by Certora as trivial. Writing it as a rule is just as valid: we
  63. // verify the is true for any state of the storage
  64. rule ownerConsistency() {
  65. assert defaultAdmin() == owner();
  66. }
  67. /*
  68. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  69. │ Function correctness: revokeRole only affects the specified user/role combo │
  70. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  71. */
  72. rule revokeRoleEffect(env e, bytes32 role) {
  73. require nonpayable(e);
  74. bytes32 otherRole;
  75. address account;
  76. address otherAccount;
  77. bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender);
  78. bool hasOtherRoleBefore = hasRole(otherRole, otherAccount);
  79. revokeRole@withrevert(e, role, account);
  80. bool success = !lastReverted;
  81. bool hasOtherRoleAfter = hasRole(otherRole, otherAccount);
  82. // liveness
  83. assert success <=> isCallerAdmin && role != DEFAULT_ADMIN_ROLE(),
  84. "roles can only be revoked by their owner except for the default admin role";
  85. // effect
  86. assert success => !hasRole(role, account),
  87. "role is revoked";
  88. // no side effect
  89. assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount),
  90. "no other role is affected";
  91. }
  92. /*
  93. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  94. │ Function correctness: renounceRole only affects the specified user/role combo │
  95. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  96. */
  97. rule renounceRoleEffect(env e, bytes32 role) {
  98. require nonpayable(e);
  99. bytes32 otherRole;
  100. address account;
  101. address otherAccount;
  102. bool hasOtherRoleBefore = hasRole(otherRole, otherAccount);
  103. address adminBefore = defaultAdmin();
  104. address pendingAdminBefore = pendingDefaultAdmin_();
  105. uint48 scheduleBefore = pendingDefaultAdminSchedule_();
  106. renounceRole@withrevert(e, role, account);
  107. bool success = !lastReverted;
  108. bool hasOtherRoleAfter = hasRole(otherRole, otherAccount);
  109. address adminAfter = defaultAdmin();
  110. address pendingAdminAfter = pendingDefaultAdmin_();
  111. uint48 scheduleAfter = pendingDefaultAdminSchedule_();
  112. // liveness
  113. assert success <=> (
  114. account == e.msg.sender &&
  115. (
  116. role != DEFAULT_ADMIN_ROLE() ||
  117. account != adminBefore ||
  118. (
  119. pendingAdminBefore == 0 &&
  120. isSet(scheduleBefore) &&
  121. hasPassed(e, scheduleBefore)
  122. )
  123. )
  124. ),
  125. "an account only can renounce by itself with a delay for the default admin role";
  126. // effect
  127. assert success => !hasRole(role, account),
  128. "role is renounced";
  129. assert success => (
  130. (
  131. role == DEFAULT_ADMIN_ROLE() &&
  132. account == adminBefore
  133. ) ? (
  134. adminAfter == 0 &&
  135. pendingAdminAfter == 0 &&
  136. scheduleAfter == 0
  137. ) : (
  138. adminAfter == adminBefore &&
  139. pendingAdminAfter == pendingAdminBefore &&
  140. scheduleAfter == scheduleBefore
  141. )
  142. ),
  143. "renouncing default admin role cleans state iff called by previous admin";
  144. // no side effect
  145. assert hasOtherRoleBefore != hasOtherRoleAfter => (
  146. role == otherRole &&
  147. account == otherAccount
  148. ),
  149. "no other role is affected";
  150. }
  151. /*
  152. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  153. │ Rule: defaultAdmin is only affected by accepting an admin transfer or renouncing │
  154. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  155. */
  156. rule noDefaultAdminChange(env e, method f, calldataarg args) {
  157. address adminBefore = defaultAdmin();
  158. f(e, args);
  159. address adminAfter = defaultAdmin();
  160. assert adminBefore != adminAfter => (
  161. f.selector == sig:acceptDefaultAdminTransfer().selector ||
  162. f.selector == sig:renounceRole(bytes32,address).selector
  163. ),
  164. "default admin is only affected by accepting an admin transfer or renouncing";
  165. }
  166. /*
  167. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  168. │ Rule: pendingDefaultAdmin is only affected by beginning, completing (accept or renounce), or canceling an admin │
  169. │ transfer │
  170. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  171. */
  172. rule noPendingDefaultAdminChange(env e, method f, calldataarg args) {
  173. address pendingAdminBefore = pendingDefaultAdmin_();
  174. uint48 scheduleBefore = pendingDefaultAdminSchedule_();
  175. f(e, args);
  176. address pendingAdminAfter = pendingDefaultAdmin_();
  177. uint48 scheduleAfter = pendingDefaultAdminSchedule_();
  178. assert (
  179. pendingAdminBefore != pendingAdminAfter ||
  180. scheduleBefore != scheduleAfter
  181. ) => (
  182. f.selector == sig:beginDefaultAdminTransfer(address).selector ||
  183. f.selector == sig:acceptDefaultAdminTransfer().selector ||
  184. f.selector == sig:cancelDefaultAdminTransfer().selector ||
  185. f.selector == sig:renounceRole(bytes32,address).selector
  186. ),
  187. "pending admin and its schedule is only affected by beginning, completing, or cancelling an admin transfer";
  188. }
  189. /*
  190. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  191. │ Rule: defaultAdminDelay can't be changed atomically by any function │
  192. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  193. */
  194. rule noDefaultAdminDelayChange(env e, method f, calldataarg args) {
  195. uint48 delayBefore = defaultAdminDelay(e);
  196. f(e, args);
  197. uint48 delayAfter = defaultAdminDelay(e);
  198. assert delayBefore == delayAfter,
  199. "delay can't be changed atomically by any function";
  200. }
  201. /*
  202. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  203. │ Rule: pendingDefaultAdminDelay is only affected by changeDefaultAdminDelay or rollbackDefaultAdminDelay │
  204. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  205. */
  206. rule noPendingDefaultAdminDelayChange(env e, method f, calldataarg args) {
  207. uint48 pendingDelayBefore = pendingDelay_(e);
  208. f(e, args);
  209. uint48 pendingDelayAfter = pendingDelay_(e);
  210. assert pendingDelayBefore != pendingDelayAfter => (
  211. f.selector == sig:changeDefaultAdminDelay(uint48).selector ||
  212. f.selector == sig:rollbackDefaultAdminDelay().selector
  213. ),
  214. "pending delay is only affected by changeDefaultAdminDelay or rollbackDefaultAdminDelay";
  215. }
  216. /*
  217. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  218. │ Rule: defaultAdminDelayIncreaseWait can't be changed atomically by any function │
  219. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  220. */
  221. rule noDefaultAdminDelayIncreaseWaitChange(env e, method f, calldataarg args) {
  222. uint48 delayIncreaseWaitBefore = defaultAdminDelayIncreaseWait();
  223. f(e, args);
  224. uint48 delayIncreaseWaitAfter = defaultAdminDelayIncreaseWait();
  225. assert delayIncreaseWaitBefore == delayIncreaseWaitAfter,
  226. "delay increase wait can't be changed atomically by any function";
  227. }
  228. /*
  229. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  230. │ Function correctness: beginDefaultAdminTransfer sets a pending default admin and its schedule │
  231. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  232. */
  233. rule beginDefaultAdminTransfer(env e, address newAdmin) {
  234. require timeSanity(e);
  235. require nonpayable(e);
  236. require nonzerosender(e);
  237. requireInvariant defaultAdminConsistency(e.msg.sender);
  238. beginDefaultAdminTransfer@withrevert(e, newAdmin);
  239. bool success = !lastReverted;
  240. // liveness
  241. assert success <=> e.msg.sender == defaultAdmin(),
  242. "only the current default admin can begin a transfer";
  243. // effect
  244. assert success => pendingDefaultAdmin_() == newAdmin,
  245. "pending default admin is set";
  246. assert success => to_mathint(pendingDefaultAdminSchedule_()) == e.block.timestamp + defaultAdminDelay(e),
  247. "pending default admin delay is set";
  248. }
  249. /*
  250. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  251. │ Rule: A default admin can't change in less than the applied schedule │
  252. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  253. */
  254. rule pendingDefaultAdminDelayEnforced(env e1, env e2, method f, calldataarg args, address newAdmin) {
  255. require e1.block.timestamp <= e2.block.timestamp;
  256. uint48 delayBefore = defaultAdminDelay(e1);
  257. address adminBefore = defaultAdmin();
  258. // There might be a better way to generalize this without requiring `beginDefaultAdminTransfer`, but currently
  259. // it's the only way in which we can attest that only `delayBefore` has passed before a change.
  260. beginDefaultAdminTransfer(e1, newAdmin);
  261. f(e2, args);
  262. address adminAfter = defaultAdmin();
  263. // change can only happen towards the newAdmin, with the delay
  264. assert adminAfter != adminBefore => (
  265. adminAfter == newAdmin &&
  266. to_mathint(e2.block.timestamp) >= e1.block.timestamp + delayBefore
  267. ),
  268. "The admin can only change after the enforced delay and to the previously scheduled new admin";
  269. }
  270. /*
  271. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  272. │ Function correctness: acceptDefaultAdminTransfer updates defaultAdmin resetting the pending admin and its schedule │
  273. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  274. */
  275. rule acceptDefaultAdminTransfer(env e) {
  276. require nonpayable(e);
  277. address pendingAdminBefore = pendingDefaultAdmin_();
  278. uint48 scheduleBefore = pendingDefaultAdminSchedule_();
  279. acceptDefaultAdminTransfer@withrevert(e);
  280. bool success = !lastReverted;
  281. // liveness
  282. assert success <=> (
  283. e.msg.sender == pendingAdminBefore &&
  284. isSet(scheduleBefore) &&
  285. hasPassed(e, scheduleBefore)
  286. ),
  287. "only the pending default admin can accept the role after the schedule has been set and passed";
  288. // effect
  289. assert success => defaultAdmin() == pendingAdminBefore,
  290. "Default admin is set to the previous pending default admin";
  291. assert success => pendingDefaultAdmin_() == 0,
  292. "Pending default admin is reset";
  293. assert success => pendingDefaultAdminSchedule_() == 0,
  294. "Pending default admin delay is reset";
  295. }
  296. /*
  297. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  298. │ Function correctness: cancelDefaultAdminTransfer resets pending default admin and its schedule │
  299. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  300. */
  301. rule cancelDefaultAdminTransfer(env e) {
  302. require nonpayable(e);
  303. require nonzerosender(e);
  304. requireInvariant defaultAdminConsistency(e.msg.sender);
  305. cancelDefaultAdminTransfer@withrevert(e);
  306. bool success = !lastReverted;
  307. // liveness
  308. assert success <=> e.msg.sender == defaultAdmin(),
  309. "only the current default admin can cancel a transfer";
  310. // effect
  311. assert success => pendingDefaultAdmin_() == 0,
  312. "Pending default admin is reset";
  313. assert success => pendingDefaultAdminSchedule_() == 0,
  314. "Pending default admin delay is reset";
  315. }
  316. /*
  317. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  318. │ Function correctness: changeDefaultAdminDelay sets a pending default admin delay and its schedule │
  319. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  320. */
  321. rule changeDefaultAdminDelay(env e, uint48 newDelay) {
  322. require timeSanity(e);
  323. require nonpayable(e);
  324. require nonzerosender(e);
  325. require delayChangeWaitSanity(e, newDelay);
  326. requireInvariant defaultAdminConsistency(e.msg.sender);
  327. uint48 delayBefore = defaultAdminDelay(e);
  328. changeDefaultAdminDelay@withrevert(e, newDelay);
  329. bool success = !lastReverted;
  330. // liveness
  331. assert success <=> e.msg.sender == defaultAdmin(),
  332. "only the current default admin can begin a delay change";
  333. // effect
  334. assert success => pendingDelay_(e) == newDelay,
  335. "pending delay is set";
  336. assert success => (
  337. assert_uint256(pendingDelaySchedule_(e)) > e.block.timestamp ||
  338. delayBefore == newDelay || // Interpreted as decreasing, x - x = 0
  339. defaultAdminDelayIncreaseWait() == 0
  340. ),
  341. "pending delay schedule is set in the future unless accepted edge cases";
  342. }
  343. /*
  344. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  345. │ Rule: A delay can't change in less than the applied schedule │
  346. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  347. */
  348. rule pendingDelayWaitEnforced(env e1, env e2, method f, calldataarg args, uint48 newDelay) {
  349. require e1.block.timestamp <= e2.block.timestamp;
  350. uint48 delayBefore = defaultAdminDelay(e1);
  351. changeDefaultAdminDelay(e1, newDelay);
  352. f(e2, args);
  353. uint48 delayAfter = defaultAdminDelay(e2);
  354. mathint delayWait = newDelay > delayBefore ? increasingDelaySchedule(e1, newDelay) : decreasingDelaySchedule(e1, newDelay);
  355. assert delayAfter != delayBefore => (
  356. delayAfter == newDelay &&
  357. to_mathint(e2.block.timestamp) >= delayWait
  358. ),
  359. "A delay can only change after the applied schedule";
  360. }
  361. /*
  362. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  363. │ Rule: pending delay wait is set depending on increasing or decreasing the delay │
  364. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  365. */
  366. rule pendingDelayWait(env e, uint48 newDelay) {
  367. uint48 oldDelay = defaultAdminDelay(e);
  368. changeDefaultAdminDelay(e, newDelay);
  369. assert newDelay > oldDelay => to_mathint(pendingDelaySchedule_(e)) == increasingDelaySchedule(e, newDelay),
  370. "Delay wait is the minimum between the new delay and a threshold when the delay is increased";
  371. assert newDelay <= oldDelay => to_mathint(pendingDelaySchedule_(e)) == decreasingDelaySchedule(e, newDelay),
  372. "Delay wait is the difference between the current and the new delay when the delay is decreased";
  373. }
  374. /*
  375. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  376. │ Function correctness: rollbackDefaultAdminDelay resets the delay and its schedule │
  377. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  378. */
  379. rule rollbackDefaultAdminDelay(env e) {
  380. require nonpayable(e);
  381. require nonzerosender(e);
  382. requireInvariant defaultAdminConsistency(e.msg.sender);
  383. rollbackDefaultAdminDelay@withrevert(e);
  384. bool success = !lastReverted;
  385. // liveness
  386. assert success <=> e.msg.sender == defaultAdmin(),
  387. "only the current default admin can rollback a delay change";
  388. // effect
  389. assert success => pendingDelay_(e) == 0,
  390. "Pending default admin is reset";
  391. assert success => pendingDelaySchedule_(e) == 0,
  392. "Pending default admin delay is reset";
  393. }