AccessControl.spec 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import "helpers/helpers.spec";
  2. import "methods/IAccessControl.spec";
  3. /*
  4. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  5. │ Identify entrypoints: only grantRole, revokeRole and renounceRole can alter permissions │
  6. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  7. */
  8. rule onlyGrantCanGrant(env e, method f, bytes32 role, address account) {
  9. calldataarg args;
  10. bool hasRoleBefore = hasRole(role, account);
  11. f(e, args);
  12. bool hasRoleAfter = hasRole(role, account);
  13. assert (
  14. !hasRoleBefore &&
  15. hasRoleAfter
  16. ) => (
  17. f.selector == sig:grantRole(bytes32, address).selector
  18. );
  19. assert (
  20. hasRoleBefore &&
  21. !hasRoleAfter
  22. ) => (
  23. f.selector == sig:revokeRole(bytes32, address).selector ||
  24. f.selector == sig:renounceRole(bytes32, address).selector
  25. );
  26. }
  27. /*
  28. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  29. │ Function correctness: grantRole only affects the specified user/role combo │
  30. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  31. */
  32. rule grantRoleEffect(env e, bytes32 role) {
  33. require nonpayable(e);
  34. bytes32 otherRole;
  35. address account;
  36. address otherAccount;
  37. bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender);
  38. bool hasOtherRoleBefore = hasRole(otherRole, otherAccount);
  39. grantRole@withrevert(e, role, account);
  40. bool success = !lastReverted;
  41. bool hasOtherRoleAfter = hasRole(otherRole, otherAccount);
  42. // liveness
  43. assert success <=> isCallerAdmin;
  44. // effect
  45. assert success => hasRole(role, account);
  46. // no side effect
  47. assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount);
  48. }
  49. /*
  50. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  51. │ Function correctness: revokeRole only affects the specified user/role combo │
  52. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  53. */
  54. rule revokeRoleEffect(env e, bytes32 role) {
  55. require nonpayable(e);
  56. bytes32 otherRole;
  57. address account;
  58. address otherAccount;
  59. bool isCallerAdmin = hasRole(getRoleAdmin(role), e.msg.sender);
  60. bool hasOtherRoleBefore = hasRole(otherRole, otherAccount);
  61. revokeRole@withrevert(e, role, account);
  62. bool success = !lastReverted;
  63. bool hasOtherRoleAfter = hasRole(otherRole, otherAccount);
  64. // liveness
  65. assert success <=> isCallerAdmin;
  66. // effect
  67. assert success => !hasRole(role, account);
  68. // no side effect
  69. assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount);
  70. }
  71. /*
  72. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  73. │ Function correctness: renounceRole only affects the specified user/role combo │
  74. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  75. */
  76. rule renounceRoleEffect(env e, bytes32 role) {
  77. require nonpayable(e);
  78. bytes32 otherRole;
  79. address account;
  80. address otherAccount;
  81. bool hasOtherRoleBefore = hasRole(otherRole, otherAccount);
  82. renounceRole@withrevert(e, role, account);
  83. bool success = !lastReverted;
  84. bool hasOtherRoleAfter = hasRole(otherRole, otherAccount);
  85. // liveness
  86. assert success <=> account == e.msg.sender;
  87. // effect
  88. assert success => !hasRole(role, account);
  89. // no side effect
  90. assert hasOtherRoleBefore != hasOtherRoleAfter => (role == otherRole && account == otherAccount);
  91. }