AccessManager.spec 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  1. import "helpers/helpers.spec";
  2. import "methods/IAccessManager.spec";
  3. methods {
  4. // FV
  5. function canCall_immediate(address,address,bytes4) external returns (bool);
  6. function canCall_delay(address,address,bytes4) external returns (uint32);
  7. function canCallExtended(address,address,bytes) external returns (bool,uint32);
  8. function canCallExtended_immediate(address,address,bytes) external returns (bool);
  9. function canCallExtended_delay(address,address,bytes) external returns (uint32);
  10. function getAdminRestrictions_restricted(bytes) external returns (bool);
  11. function getAdminRestrictions_roleAdminId(bytes) external returns (uint64);
  12. function getAdminRestrictions_executionDelay(bytes) external returns (uint32);
  13. function hasRole_isMember(uint64,address) external returns (bool);
  14. function hasRole_executionDelay(uint64,address) external returns (uint32);
  15. function getAccess_since(uint64,address) external returns (uint48);
  16. function getAccess_currentDelay(uint64,address) external returns (uint32);
  17. function getAccess_pendingDelay(uint64,address) external returns (uint32);
  18. function getAccess_effect(uint64,address) external returns (uint48);
  19. function getTargetAdminDelay_after(address target) external returns (uint32);
  20. function getTargetAdminDelay_effect(address target) external returns (uint48);
  21. function getRoleGrantDelay_after(uint64 roleId) external returns (uint32);
  22. function getRoleGrantDelay_effect(uint64 roleId) external returns (uint48);
  23. function hashExecutionId(address,bytes4) external returns (bytes32) envfree;
  24. function executionId() external returns (bytes32) envfree;
  25. function getSelector(bytes) external returns (bytes4) envfree;
  26. function getFirstArgumentAsAddress(bytes) external returns (address) envfree;
  27. function getFirstArgumentAsUint64(bytes) external returns (uint64) envfree;
  28. }
  29. /*
  30. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  31. โ”‚ Helpers โ”‚
  32. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  33. */
  34. definition isOnlyAuthorized(bytes4 selector) returns bool =
  35. selector == to_bytes4(sig:labelRole(uint64,string).selector ) ||
  36. selector == to_bytes4(sig:setRoleAdmin(uint64,uint64).selector ) ||
  37. selector == to_bytes4(sig:setRoleGuardian(uint64,uint64).selector ) ||
  38. selector == to_bytes4(sig:setGrantDelay(uint64,uint32).selector ) ||
  39. selector == to_bytes4(sig:setTargetAdminDelay(address,uint32).selector ) ||
  40. selector == to_bytes4(sig:updateAuthority(address,address).selector ) ||
  41. selector == to_bytes4(sig:setTargetClosed(address,bool).selector ) ||
  42. selector == to_bytes4(sig:setTargetFunctionRole(address,bytes4[],uint64).selector) ||
  43. selector == to_bytes4(sig:grantRole(uint64,address,uint32).selector ) ||
  44. selector == to_bytes4(sig:revokeRole(uint64,address).selector );
  45. /*
  46. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  47. โ”‚ Invariant: executionId must be clean when not in the middle of a call โ”‚
  48. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  49. */
  50. invariant cleanExecutionId()
  51. executionId() == to_bytes32(0);
  52. /*
  53. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  54. โ”‚ Invariant: public role โ”‚
  55. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  56. */
  57. invariant publicRole(env e, address account)
  58. hasRole_isMember(e, PUBLIC_ROLE(), account) &&
  59. hasRole_executionDelay(e, PUBLIC_ROLE(), account) == 0 &&
  60. getAccess_since(e, PUBLIC_ROLE(), account) == 0 &&
  61. getAccess_currentDelay(e, PUBLIC_ROLE(), account) == 0 &&
  62. getAccess_pendingDelay(e, PUBLIC_ROLE(), account) == 0 &&
  63. getAccess_effect(e, PUBLIC_ROLE(), account) == 0;
  64. /*
  65. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  66. โ”‚ Invariant: hasRole is consistent with getAccess โ”‚
  67. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  68. */
  69. invariant hasRoleGetAccessConsistency(env e, uint64 roleId, address account)
  70. hasRole_isMember(e, roleId, account) == (roleId == PUBLIC_ROLE() || isSetAndPast(e, getAccess_since(e, roleId, account))) &&
  71. hasRole_executionDelay(e, roleId, account) == getAccess_currentDelay(e, roleId, account);
  72. /*
  73. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  74. โ”‚ Functions: canCall, canCallExtended, getAccess, hasRole, isTargetClosed and getTargetFunctionRole do NOT revert โ”‚
  75. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  76. */
  77. rule noRevert(env e) {
  78. require nonpayable(e);
  79. require sanity(e);
  80. address caller;
  81. address target;
  82. bytes data;
  83. bytes4 selector;
  84. uint64 roleId;
  85. canCall@withrevert(e, caller, target, selector);
  86. assert !lastReverted;
  87. // require data.length <= max_uint64;
  88. //
  89. // canCallExtended@withrevert(e, caller, target, data);
  90. // assert !lastReverted;
  91. getAccess@withrevert(e, roleId, caller);
  92. assert !lastReverted;
  93. hasRole@withrevert(e, roleId, caller);
  94. assert !lastReverted;
  95. isTargetClosed@withrevert(target);
  96. assert !lastReverted;
  97. getTargetFunctionRole@withrevert(target, selector);
  98. assert !lastReverted;
  99. // Not covered:
  100. // - getAdminRestrictions (_1, _2 & _3)
  101. // - getSelector
  102. }
  103. /*
  104. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  105. โ”‚ Functions: admin restrictions are correct โ”‚
  106. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  107. */
  108. rule getAdminRestrictions(env e, bytes data) {
  109. bool restricted = getAdminRestrictions_restricted(e, data);
  110. uint64 roleId = getAdminRestrictions_roleAdminId(e, data);
  111. uint32 delay = getAdminRestrictions_executionDelay(e, data);
  112. bytes4 selector = getSelector(data);
  113. if (data.length < 4) {
  114. assert restricted == false;
  115. assert roleId == 0;
  116. assert delay == 0;
  117. } else if (
  118. selector == to_bytes4(sig:labelRole(uint64,string).selector) ||
  119. selector == to_bytes4(sig:setRoleAdmin(uint64,uint64).selector) ||
  120. selector == to_bytes4(sig:setRoleGuardian(uint64,uint64).selector) ||
  121. selector == to_bytes4(sig:setGrantDelay(uint64,uint32).selector) ||
  122. selector == to_bytes4(sig:setTargetAdminDelay(address,uint32).selector)
  123. ) {
  124. assert restricted == true;
  125. assert roleId == ADMIN_ROLE();
  126. assert delay == 0;
  127. } else if (
  128. selector == to_bytes4(sig:updateAuthority(address,address).selector) ||
  129. selector == to_bytes4(sig:setTargetClosed(address,bool).selector) ||
  130. selector == to_bytes4(sig:setTargetFunctionRole(address,bytes4[],uint64).selector)
  131. ) {
  132. assert restricted == true;
  133. assert roleId == ADMIN_ROLE();
  134. assert delay == getTargetAdminDelay(e, getFirstArgumentAsAddress(data));
  135. } else if (
  136. selector == to_bytes4(sig:grantRole(uint64,address,uint32).selector) ||
  137. selector == to_bytes4(sig:revokeRole(uint64,address).selector)
  138. ) {
  139. assert restricted == true;
  140. assert roleId == getRoleAdmin(getFirstArgumentAsUint64(data));
  141. assert delay == 0;
  142. } else {
  143. assert restricted == false;
  144. assert roleId == getTargetFunctionRole(currentContract, selector);
  145. assert delay == 0;
  146. }
  147. }
  148. /*
  149. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  150. โ”‚ Functions: canCall โ”‚
  151. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  152. */
  153. rule canCall(env e) {
  154. address caller;
  155. address target;
  156. bytes4 selector;
  157. // Get relevant values
  158. bool immediate = canCall_immediate(e, caller, target, selector);
  159. uint32 delay = canCall_delay(e, caller, target, selector);
  160. bool closed = isTargetClosed(target);
  161. uint64 roleId = getTargetFunctionRole(target, selector);
  162. bool isMember = hasRole_isMember(e, roleId, caller);
  163. uint32 currentDelay = hasRole_executionDelay(e, roleId, caller);
  164. // Can only execute without delay in specific cases:
  165. // - target not closed
  166. // - if self-execution: `executionId` must match
  167. // - if third party execution: must be member with no delay
  168. assert immediate <=> (
  169. !closed &&
  170. (
  171. (caller == currentContract && executionId() == hashExecutionId(target, selector))
  172. ||
  173. (caller != currentContract && isMember && currentDelay == 0)
  174. )
  175. );
  176. // Can only execute with delay in specific cases:
  177. // - target not closed
  178. // - third party execution
  179. // - caller is a member and has an execution delay
  180. assert delay > 0 <=> (
  181. !closed &&
  182. caller != currentContract &&
  183. isMember &&
  184. currentDelay > 0
  185. );
  186. // If there is a delay, then it must be the caller's execution delay
  187. assert delay > 0 => delay == currentDelay;
  188. // Immediate execute means no delayed execution
  189. assert immediate => delay == 0;
  190. }
  191. /*
  192. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  193. โ”‚ Functions: canCallExtended โ”‚
  194. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  195. */
  196. rule canCallExtended(env e) {
  197. address caller;
  198. address target;
  199. bytes data;
  200. bytes4 selector = getSelector(data);
  201. bool immediate = canCallExtended_immediate(e, caller, target, data);
  202. uint32 delay = canCallExtended_delay(e, caller, target, data);
  203. bool restricted = getAdminRestrictions_restricted(e, data);
  204. bool closed = isTargetClosed(target);
  205. uint64 roleId = getAdminRestrictions_roleAdminId(e, data);
  206. uint32 operationDelay = getAdminRestrictions_executionDelay(e, data);
  207. bool inRole = hasRole_isMember(e, roleId, caller);
  208. uint32 executionDelay = hasRole_executionDelay(e, roleId, caller);
  209. if (data.length < 4) {
  210. assert immediate == false;
  211. assert delay == 0;
  212. } else if (target == currentContract) {
  213. // Can only execute without delay in the specific cases:
  214. // - caller is the AccessManager and the executionId is set
  215. // or
  216. // - data matches an admin restricted function OR non-admin restricted function on open target
  217. // - caller has the necessary role
  218. // - operation delay is not set
  219. // - execution delay is not set
  220. assert immediate <=> (
  221. (
  222. caller == currentContract &&
  223. executionId() == hashExecutionId(target, selector)
  224. ) || (
  225. caller != currentContract &&
  226. inRole &&
  227. (restricted || !closed) &&
  228. operationDelay == 0 &&
  229. executionDelay == 0
  230. )
  231. );
  232. // Immediate execute means no delayed execution
  233. // This is equivalent to "delay > 0 => !immediate"
  234. assert immediate => delay == 0;
  235. // Can only execute with delay in specific cases:
  236. // - caller is a third party
  237. // - data matches an admin restricted function OR non-admin restricted function on open target
  238. // - caller has the necessary role
  239. // - operation delay or execution delay is set
  240. assert delay > 0 <=> (
  241. caller != currentContract &&
  242. inRole &&
  243. (restricted || !closed) &&
  244. (operationDelay > 0 || executionDelay > 0)
  245. );
  246. // If there is a delay, then it must be the maximum of caller's execution delay and the operation delay
  247. assert delay > 0 => to_mathint(delay) == max(operationDelay, executionDelay);
  248. } else {
  249. // results are equivalent when targeting third party contracts
  250. assert immediate == canCall_immediate(e, caller, target, selector);
  251. assert delay == canCall_delay(e, caller, target, selector);
  252. }
  253. }
  254. /*
  255. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  256. โ”‚ State transitions: getAccess โ”‚
  257. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  258. */
  259. rule getAccessChangeTime(uint64 roleId, address account) {
  260. env e1;
  261. env e2;
  262. // values before
  263. mathint getAccess1Before = getAccess_since(e1, roleId, account);
  264. mathint getAccess2Before = getAccess_currentDelay(e1, roleId, account);
  265. mathint getAccess3Before = getAccess_pendingDelay(e1, roleId, account);
  266. mathint getAccess4Before = getAccess_effect(e1, roleId, account);
  267. // time pass: e1 โ†’ e2
  268. require clock(e1) <= clock(e2);
  269. // values after
  270. mathint getAccess1After = getAccess_since(e2, roleId, account);
  271. mathint getAccess2After = getAccess_currentDelay(e2, roleId, account);
  272. mathint getAccess3After = getAccess_pendingDelay(e2, roleId, account);
  273. mathint getAccess4After = getAccess_effect(e2, roleId, account);
  274. // member "since" cannot change as a consequence of time passing
  275. assert getAccess1Before == getAccess1After;
  276. // any change of any other value should be a consequence of the effect timepoint being reached
  277. assert (
  278. getAccess2Before != getAccess2After ||
  279. getAccess3Before != getAccess3After ||
  280. getAccess4Before != getAccess4After
  281. ) => (
  282. getAccess4Before != 0 &&
  283. getAccess4Before > clock(e1) &&
  284. getAccess4Before <= clock(e2) &&
  285. getAccess2After == getAccess3Before &&
  286. getAccess3After == 0 &&
  287. getAccess4After == 0
  288. );
  289. }
  290. rule getAccessChangeCall(uint64 roleId, address account) {
  291. env e;
  292. // sanity
  293. require sanity(e);
  294. // values before
  295. mathint getAccess1Before = getAccess_since(e, roleId, account);
  296. mathint getAccess2Before = getAccess_currentDelay(e, roleId, account);
  297. mathint getAccess3Before = getAccess_pendingDelay(e, roleId, account);
  298. mathint getAccess4Before = getAccess_effect(e, roleId, account);
  299. // arbitrary function call
  300. method f; calldataarg args; f(e, args);
  301. // values before
  302. mathint getAccess1After = getAccess_since(e, roleId, account);
  303. mathint getAccess2After = getAccess_currentDelay(e, roleId, account);
  304. mathint getAccess3After = getAccess_pendingDelay(e, roleId, account);
  305. mathint getAccess4After = getAccess_effect(e, roleId, account);
  306. // transitions
  307. assert (
  308. getAccess1Before != getAccess1After ||
  309. getAccess2Before != getAccess2After ||
  310. getAccess3Before != getAccess3After ||
  311. getAccess4Before != getAccess4After
  312. ) => (
  313. (
  314. f.selector == sig:grantRole(uint64,address,uint32).selector &&
  315. getAccess1After > 0
  316. ) || (
  317. (
  318. f.selector == sig:revokeRole(uint64,address).selector ||
  319. f.selector == sig:renounceRole(uint64,address).selector
  320. ) &&
  321. getAccess1After == 0 &&
  322. getAccess2After == 0 &&
  323. getAccess3After == 0 &&
  324. getAccess4After == 0
  325. )
  326. );
  327. }
  328. /*
  329. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  330. โ”‚ State transitions: isTargetClosed โ”‚
  331. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  332. */
  333. rule isTargetClosedChangeTime(address target) {
  334. env e1;
  335. env e2;
  336. // values before
  337. bool isClosedBefore = isTargetClosed(e1, target);
  338. // time pass: e1 โ†’ e2
  339. require clock(e1) <= clock(e2);
  340. // values after
  341. bool isClosedAfter = isTargetClosed(e2, target);
  342. // transitions
  343. assert isClosedBefore == isClosedAfter;
  344. }
  345. rule isTargetClosedChangeCall(address target) {
  346. env e;
  347. // values before
  348. bool isClosedBefore = isTargetClosed(e, target);
  349. // arbitrary function call
  350. method f; calldataarg args; f(e, args);
  351. // values after
  352. bool isClosedAfter = isTargetClosed(e, target);
  353. // transitions
  354. assert isClosedBefore != isClosedAfter => (
  355. f.selector == sig:setTargetClosed(address,bool).selector
  356. );
  357. }
  358. /*
  359. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  360. โ”‚ State transitions: getTargetFunctionRole โ”‚
  361. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  362. */
  363. rule getTargetFunctionRoleChangeTime(address target, bytes4 selector) {
  364. env e1;
  365. env e2;
  366. // values before
  367. mathint roleIdBefore = getTargetFunctionRole(e1, target, selector);
  368. // time pass: e1 โ†’ e2
  369. require clock(e1) <= clock(e2);
  370. // values after
  371. mathint roleIdAfter = getTargetFunctionRole(e2, target, selector);
  372. // transitions
  373. assert roleIdBefore == roleIdAfter;
  374. }
  375. rule getTargetFunctionRoleChangeCall(address target, bytes4 selector) {
  376. env e;
  377. // values before
  378. mathint roleIdBefore = getTargetFunctionRole(e, target, selector);
  379. // arbitrary function call
  380. method f; calldataarg args; f(e, args);
  381. // values after
  382. mathint roleIdAfter = getTargetFunctionRole(e, target, selector);
  383. // transitions
  384. assert roleIdBefore != roleIdAfter => (
  385. f.selector == sig:setTargetFunctionRole(address,bytes4[],uint64).selector
  386. );
  387. }
  388. /*
  389. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  390. โ”‚ State transitions: getTargetAdminDelay โ”‚
  391. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  392. */
  393. rule getTargetAdminDelayChangeTime(address target) {
  394. env e1;
  395. env e2;
  396. // values before
  397. mathint delayBefore = getTargetAdminDelay(e1, target);
  398. mathint delayPendingBefore = getTargetAdminDelay_after(e1, target);
  399. mathint delayEffectBefore = getTargetAdminDelay_effect(e1, target);
  400. // time pass: e1 โ†’ e2
  401. require clock(e1) <= clock(e2);
  402. // values after
  403. mathint delayAfter = getTargetAdminDelay(e2, target);
  404. mathint delayPendingAfter = getTargetAdminDelay_after(e2, target);
  405. mathint delayEffectAfter = getTargetAdminDelay_effect(e2, target);
  406. assert (
  407. delayBefore != delayAfter ||
  408. delayPendingBefore != delayPendingAfter ||
  409. delayEffectBefore != delayEffectAfter
  410. ) => (
  411. delayEffectBefore > clock(e1) &&
  412. delayEffectBefore <= clock(e2) &&
  413. delayAfter == delayPendingBefore &&
  414. delayPendingAfter == 0 &&
  415. delayEffectAfter == 0
  416. );
  417. }
  418. rule getTargetAdminDelayChangeCall(address target) {
  419. env e;
  420. // values before
  421. mathint delayBefore = getTargetAdminDelay(e, target);
  422. mathint delayPendingBefore = getTargetAdminDelay_after(e, target);
  423. mathint delayEffectBefore = getTargetAdminDelay_effect(e, target);
  424. // arbitrary function call
  425. method f; calldataarg args; f(e, args);
  426. // values after
  427. mathint delayAfter = getTargetAdminDelay(e, target);
  428. mathint delayPendingAfter = getTargetAdminDelay_after(e, target);
  429. mathint delayEffectAfter = getTargetAdminDelay_effect(e, target);
  430. // if anything changed ...
  431. assert (
  432. delayBefore != delayAfter ||
  433. delayPendingBefore != delayPendingAfter ||
  434. delayEffectBefore != delayEffectAfter
  435. ) => (
  436. (
  437. // ... it was the consequence of a call to setTargetAdminDelay
  438. f.selector == sig:setTargetAdminDelay(address,uint32).selector
  439. ) && (
  440. // ... delay cannot decrease instantly
  441. delayAfter >= delayBefore
  442. ) && (
  443. // ... if setback is not 0, value cannot change instantly
  444. minSetback() > 0 => (
  445. delayBefore == delayAfter
  446. )
  447. ) && (
  448. // ... if the value did not change and there is a minSetback, there must be something scheduled in the future
  449. delayAfter == delayBefore && minSetback() > 0 => (
  450. delayEffectAfter >= clock(e) + minSetback()
  451. )
  452. // note: if there is no minSetback, and if the caller "confirms" the current value,
  453. // then this as immediate effect and nothing is scheduled
  454. ) && (
  455. // ... if the value changed, then no further change should be scheduled
  456. delayAfter != delayBefore => (
  457. delayPendingAfter == 0 &&
  458. delayEffectAfter == 0
  459. )
  460. )
  461. );
  462. }
  463. /*
  464. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  465. โ”‚ State transitions: getRoleGrantDelay โ”‚
  466. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  467. */
  468. rule getRoleGrantDelayChangeTime(uint64 roleId) {
  469. env e1;
  470. env e2;
  471. // values before
  472. mathint delayBefore = getRoleGrantDelay(e1, roleId);
  473. mathint delayPendingBefore = getRoleGrantDelay_after(e1, roleId);
  474. mathint delayEffectBefore = getRoleGrantDelay_effect(e1, roleId);
  475. // time pass: e1 โ†’ e2
  476. require clock(e1) <= clock(e2);
  477. // values after
  478. mathint delayAfter = getRoleGrantDelay(e2, roleId);
  479. mathint delayPendingAfter = getRoleGrantDelay_after(e2, roleId);
  480. mathint delayEffectAfter = getRoleGrantDelay_effect(e2, roleId);
  481. assert (
  482. delayBefore != delayAfter ||
  483. delayPendingBefore != delayPendingAfter ||
  484. delayEffectBefore != delayEffectAfter
  485. ) => (
  486. delayEffectBefore > clock(e1) &&
  487. delayEffectBefore <= clock(e2) &&
  488. delayAfter == delayPendingBefore &&
  489. delayPendingAfter == 0 &&
  490. delayEffectAfter == 0
  491. );
  492. }
  493. rule getRoleGrantDelayChangeCall(uint64 roleId) {
  494. env e;
  495. // values before
  496. mathint delayBefore = getRoleGrantDelay(e, roleId);
  497. mathint delayPendingBefore = getRoleGrantDelay_after(e, roleId);
  498. mathint delayEffectBefore = getRoleGrantDelay_effect(e, roleId);
  499. // arbitrary function call
  500. method f; calldataarg args; f(e, args);
  501. // values after
  502. mathint delayAfter = getRoleGrantDelay(e, roleId);
  503. mathint delayPendingAfter = getRoleGrantDelay_after(e, roleId);
  504. mathint delayEffectAfter = getRoleGrantDelay_effect(e, roleId);
  505. // if anything changed ...
  506. assert (
  507. delayBefore != delayAfter ||
  508. delayPendingBefore != delayPendingAfter ||
  509. delayEffectBefore != delayEffectAfter
  510. ) => (
  511. (
  512. // ... it was the consequence of a call to setTargetAdminDelay
  513. f.selector == sig:setGrantDelay(uint64,uint32).selector
  514. ) && (
  515. // ... delay cannot decrease instantly
  516. delayAfter >= delayBefore
  517. ) && (
  518. // ... if setback is not 0, value cannot change instantly
  519. minSetback() > 0 => (
  520. delayBefore == delayAfter
  521. )
  522. ) && (
  523. // ... if the value did not change and there is a minSetback, there must be something scheduled in the future
  524. delayAfter == delayBefore && minSetback() > 0 => (
  525. delayEffectAfter >= clock(e) + minSetback()
  526. )
  527. // note: if there is no minSetback, and if the caller "confirms" the current value,
  528. // then this as immediate effect and nothing is scheduled
  529. ) && (
  530. // ... if the value changed, then no further change should be scheduled
  531. delayAfter != delayBefore => (
  532. delayPendingAfter == 0 &&
  533. delayEffectAfter == 0
  534. )
  535. )
  536. );
  537. }
  538. /*
  539. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  540. โ”‚ State transitions: getRoleAdmin & getRoleGuardian โ”‚
  541. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  542. */
  543. rule getRoleAdminChangeCall(uint64 roleId) {
  544. // values before
  545. mathint adminIdBefore = getRoleAdmin(roleId);
  546. // arbitrary function call
  547. env e; method f; calldataarg args; f(e, args);
  548. // values after
  549. mathint adminIdAfter = getRoleAdmin(roleId);
  550. // transitions
  551. assert adminIdBefore != adminIdAfter => f.selector == sig:setRoleAdmin(uint64,uint64).selector;
  552. }
  553. rule getRoleGuardianChangeCall(uint64 roleId) {
  554. // values before
  555. mathint guardianIdBefore = getRoleGuardian(roleId);
  556. // arbitrary function call
  557. env e; method f; calldataarg args; f(e, args);
  558. // values after
  559. mathint guardianIdAfter = getRoleGuardian(roleId);
  560. // transitions
  561. assert guardianIdBefore != guardianIdAfter => (
  562. f.selector == sig:setRoleGuardian(uint64,uint64).selector
  563. );
  564. }
  565. /*
  566. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  567. โ”‚ State transitions: getNonce โ”‚
  568. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  569. */
  570. rule getNonceChangeCall(bytes32 operationId) {
  571. // values before
  572. mathint nonceBefore = getNonce(operationId);
  573. // reasonable assumption
  574. require nonceBefore < max_uint32;
  575. // arbitrary function call
  576. env e; method f; calldataarg args; f(e, args);
  577. // values after
  578. mathint nonceAfter = getNonce(operationId);
  579. // transitions
  580. assert nonceBefore != nonceAfter => (
  581. f.selector == sig:schedule(address,bytes,uint48).selector &&
  582. nonceAfter == nonceBefore + 1
  583. );
  584. }
  585. /*
  586. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  587. โ”‚ State transitions: getSchedule โ”‚
  588. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  589. */
  590. rule getScheduleChangeTime(bytes32 operationId) {
  591. env e1;
  592. env e2;
  593. // values before
  594. mathint scheduleBefore = getSchedule(e1, operationId);
  595. // time pass: e1 โ†’ e2
  596. require clock(e1) <= clock(e2);
  597. // values after
  598. mathint scheduleAfter = getSchedule(e2, operationId);
  599. // transition
  600. assert scheduleBefore != scheduleAfter => (
  601. scheduleBefore + expiration() > clock(e1) &&
  602. scheduleBefore + expiration() <= clock(e2) &&
  603. scheduleAfter == 0
  604. );
  605. }
  606. rule getScheduleChangeCall(bytes32 operationId) {
  607. env e;
  608. // values before
  609. mathint scheduleBefore = getSchedule(e, operationId);
  610. // arbitrary function call
  611. method f; calldataarg args; f(e, args);
  612. // values after
  613. mathint scheduleAfter = getSchedule(e, operationId);
  614. // transitions
  615. assert scheduleBefore != scheduleAfter => (
  616. (f.selector == sig:schedule(address,bytes,uint48).selector && scheduleAfter >= clock(e)) ||
  617. (f.selector == sig:execute(address,bytes).selector && scheduleAfter == 0 ) ||
  618. (f.selector == sig:cancel(address,address,bytes).selector && scheduleAfter == 0 ) ||
  619. (f.selector == sig:consumeScheduledOp(address,bytes).selector && scheduleAfter == 0 ) ||
  620. (isOnlyAuthorized(to_bytes4(f.selector)) && scheduleAfter == 0 )
  621. );
  622. }
  623. /*
  624. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  625. โ”‚ Functions: restricted functions can only be called by owner โ”‚
  626. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  627. */
  628. rule restrictedFunctions(env e) {
  629. require nonpayable(e);
  630. require sanity(e);
  631. method f;
  632. calldataarg args;
  633. f(e,args);
  634. assert (
  635. f.selector == sig:labelRole(uint64,string).selector ||
  636. f.selector == sig:setRoleAdmin(uint64,uint64).selector ||
  637. f.selector == sig:setRoleGuardian(uint64,uint64).selector ||
  638. f.selector == sig:setGrantDelay(uint64,uint32).selector ||
  639. f.selector == sig:setTargetAdminDelay(address,uint32).selector ||
  640. f.selector == sig:updateAuthority(address,address).selector ||
  641. f.selector == sig:setTargetClosed(address,bool).selector ||
  642. f.selector == sig:setTargetFunctionRole(address,bytes4[],uint64).selector
  643. ) => (
  644. hasRole_isMember(e, ADMIN_ROLE(), e.msg.sender) || e.msg.sender == currentContract
  645. );
  646. }
  647. rule restrictedFunctionsGrantRole(env e) {
  648. require nonpayable(e);
  649. require sanity(e);
  650. uint64 roleId;
  651. address account;
  652. uint32 executionDelay;
  653. // We want to check that the caller has the admin role before we possibly grant it.
  654. bool hasAdminRoleBefore = hasRole_isMember(e, getRoleAdmin(roleId), e.msg.sender);
  655. grantRole(e, roleId, account, executionDelay);
  656. assert hasAdminRoleBefore || e.msg.sender == currentContract;
  657. }
  658. rule restrictedFunctionsRevokeRole(env e) {
  659. require nonpayable(e);
  660. require sanity(e);
  661. uint64 roleId;
  662. address account;
  663. // This is needed if roleId is self-administered, the `revokeRole` call could target
  664. // e.msg.sender and remove the very role that is necessary for authorizing the call.
  665. bool hasAdminRoleBefore = hasRole_isMember(e, getRoleAdmin(roleId), e.msg.sender);
  666. revokeRole(e, roleId, account);
  667. assert hasAdminRoleBefore || e.msg.sender == currentContract;
  668. }
  669. /*
  670. โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
  671. โ”‚ Functions: canCall delay is enforced for calls to execute (only for others target) โ”‚
  672. โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
  673. */
  674. // getScheduleChangeCall proves that only {schedule} can set an operation schedule to a non 0 value
  675. rule callDelayEnforce_scheduleInTheFuture(env e) {
  676. address target;
  677. bytes data;
  678. uint48 when;
  679. // Condition: calling a third party with a delay
  680. mathint delay = canCallExtended_delay(e, e.msg.sender, target, data);
  681. require delay > 0;
  682. // Schedule
  683. schedule(e, target, data, when);
  684. // Get operation schedule
  685. mathint timepoint = getSchedule(e, hashOperation(e.msg.sender, target, data));
  686. // Schedule is far enough in the future
  687. assert timepoint == max(clock(e) + delay, when);
  688. }
  689. rule callDelayEnforce_executeAfterDelay(env e) {
  690. address target;
  691. bytes data;
  692. // Condition: calling a third party with a delay
  693. mathint delay = canCallExtended_delay(e, e.msg.sender, target, data);
  694. // Get operation schedule before
  695. mathint scheduleBefore = getSchedule(e, hashOperation(e.msg.sender, target, data));
  696. // Do call
  697. execute@withrevert(e, target, data);
  698. bool success = !lastReverted;
  699. // Get operation schedule after
  700. mathint scheduleAfter = getSchedule(e, hashOperation(e.msg.sender, target, data));
  701. // Can only execute if delay is set and has passed
  702. assert success => (
  703. delay > 0 => (
  704. scheduleBefore != 0 &&
  705. scheduleBefore <= clock(e)
  706. ) &&
  707. scheduleAfter == 0
  708. );
  709. }