AccessControl.spec 5.7 KB

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