AccessManager.spec 41 KB

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