Ownable.spec 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. import "helpers/helpers.spec"
  2. import "methods/IOwnable.spec"
  3. methods {
  4. restricted()
  5. }
  6. /*
  7. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  8. │ Function correctness: transferOwnership changes ownership │
  9. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  10. */
  11. rule transferOwnership(env e) {
  12. require nonpayable(e);
  13. address newOwner;
  14. address current = owner();
  15. transferOwnership@withrevert(e, newOwner);
  16. bool success = !lastReverted;
  17. assert success <=> (e.msg.sender == current && newOwner != 0), "unauthorized caller or invalid arg";
  18. assert success => owner() == newOwner, "current owner changed";
  19. }
  20. /*
  21. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  22. │ Function correctness: renounceOwnership removes the owner │
  23. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  24. */
  25. rule renounceOwnership(env e) {
  26. require nonpayable(e);
  27. address current = owner();
  28. renounceOwnership@withrevert(e);
  29. bool success = !lastReverted;
  30. assert success <=> e.msg.sender == current, "unauthorized caller";
  31. assert success => owner() == 0, "owner not cleared";
  32. }
  33. /*
  34. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  35. │ Access control: only current owner can call restricted functions │
  36. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  37. */
  38. rule onlyCurrentOwnerCanCallOnlyOwner(env e) {
  39. require nonpayable(e);
  40. address current = owner();
  41. calldataarg args;
  42. restricted@withrevert(e, args);
  43. assert !lastReverted <=> e.msg.sender == current, "access control failed";
  44. }
  45. /*
  46. ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
  47. │ Rule: ownership can only change in specific ways │
  48. └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
  49. */
  50. rule onlyOwnerOrPendingOwnerCanChangeOwnership(env e) {
  51. address oldCurrent = owner();
  52. method f; calldataarg args;
  53. f(e, args);
  54. address newCurrent = owner();
  55. // If owner changes, must be either transferOwnership or renounceOwnership
  56. assert oldCurrent != newCurrent => (
  57. (e.msg.sender == oldCurrent && newCurrent != 0 && f.selector == transferOwnership(address).selector) ||
  58. (e.msg.sender == oldCurrent && newCurrent == 0 && f.selector == renounceOwnership().selector)
  59. );
  60. }