Ownable.spec 4.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import "helpers/helpers.spec";
  2. import "methods/IOwnable.spec";
  3. methods {
  4. function restricted() external;
  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 == sig:transferOwnership(address).selector) ||
  58. (e.msg.sender == oldCurrent && newCurrent == 0 && f.selector == sig:renounceOwnership().selector)
  59. );
  60. }