Finish Ownable and Ownable2Step

This commit is contained in:
ernestognw
2023-08-11 11:45:20 -06:00
parent ae24e3c6a4
commit 6370b1398d
8 changed files with 225 additions and 200 deletions

View File

@ -0,0 +1,11 @@
--- access/Ownable.sol 2023-08-09 11:45:05
+++ access/Ownable.sol 2023-08-11 11:37:19
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
-pragma solidity ^0.8.20;
+pragma solidity ^0.8.19;
import {Context} from "../utils/Context.sol";

View File

@ -0,0 +1,11 @@
--- access/Ownable2Step.sol 2023-08-09 11:45:05
+++ access/Ownable2Step.sol 2023-08-11 11:37:27
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable2Step.sol)
-pragma solidity ^0.8.20;
+pragma solidity ^0.8.19;
import {Ownable} from "./Ownable.sol";

View File

@ -1,9 +1,11 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20; pragma solidity ^0.8.19;
import "../patched/access/Ownable2Step.sol"; import {Ownable2Step, Ownable} from "../patched/access/Ownable2Step.sol";
contract Ownable2StepHarness is Ownable2Step { contract Ownable2StepHarness is Ownable2Step {
function restricted() external onlyOwner {} constructor(address initialOwner) Ownable(initialOwner) {}
function restricted() external onlyOwner {}
} }

View File

@ -1,9 +1,11 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity ^0.8.20; pragma solidity ^0.8.19;
import "../patched/access/Ownable.sol"; import {Ownable} from "../patched/access/Ownable.sol";
contract OwnableHarness is Ownable { contract OwnableHarness is Ownable {
function restricted() external onlyOwner {} constructor(address initialOwner) Ownable(initialOwner) {}
function restricted() external onlyOwner {}
} }

View File

@ -1,78 +1,77 @@
import "helpers/helpers.spec" import "helpers/helpers.spec";
import "methods/IOwnable.spec" import "methods/IOwnable.spec";
methods { methods {
restricted() function restricted() external;
} }
/* /*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Function correctness: transferOwnership changes ownership Function correctness: transferOwnership changes ownership
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/ */
rule transferOwnership(env e) { rule transferOwnership(env e) {
require nonpayable(e); require nonpayable(e);
address newOwner; address newOwner;
address current = owner(); address current = owner();
transferOwnership@withrevert(e, newOwner); transferOwnership@withrevert(e, newOwner);
bool success = !lastReverted; bool success = !lastReverted;
assert success <=> (e.msg.sender == current && newOwner != 0), "unauthorized caller or invalid arg"; assert success <=> (e.msg.sender == current && newOwner != 0), "unauthorized caller or invalid arg";
assert success => owner() == newOwner, "current owner changed"; assert success => owner() == newOwner, "current owner changed";
} }
/* /*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Function correctness: renounceOwnership removes the owner Function correctness: renounceOwnership removes the owner
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */
*/ rule renounceOwnership(env e) {
rule renounceOwnership(env e) { require nonpayable(e);
require nonpayable(e);
address current = owner();
address current = owner();
renounceOwnership@withrevert(e);
renounceOwnership@withrevert(e); bool success = !lastReverted;
bool success = !lastReverted;
assert success <=> e.msg.sender == current, "unauthorized caller";
assert success <=> e.msg.sender == current, "unauthorized caller"; assert success => owner() == 0, "owner not cleared";
assert success => owner() == 0, "owner not cleared"; }
}
/*
/* ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ Access control: only current owner can call restricted functions
Access control: only current owner can call restricted functions └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */
*/ rule onlyCurrentOwnerCanCallOnlyOwner(env e) {
rule onlyCurrentOwnerCanCallOnlyOwner(env e) { require nonpayable(e);
require nonpayable(e);
address current = owner();
address current = owner();
calldataarg args;
calldataarg args; restricted@withrevert(e, args);
restricted@withrevert(e, args);
assert !lastReverted <=> e.msg.sender == current, "access control failed";
assert !lastReverted <=> e.msg.sender == current, "access control failed"; }
}
/*
/* ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ Rule: ownership can only change in specific ways
Rule: ownership can only change in specific ways └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ */
*/ rule onlyOwnerOrPendingOwnerCanChangeOwnership(env e) {
rule onlyOwnerOrPendingOwnerCanChangeOwnership(env e) { address oldCurrent = owner();
address oldCurrent = owner();
method f; calldataarg args;
method f; calldataarg args; f(e, args);
f(e, args);
address newCurrent = owner();
address newCurrent = owner();
// If owner changes, must be either transferOwnership or renounceOwnership
// If owner changes, must be either transferOwnership or renounceOwnership assert oldCurrent != newCurrent => (
assert oldCurrent != newCurrent => ( (e.msg.sender == oldCurrent && newCurrent != 0 && f.selector == sig:transferOwnership(address).selector) ||
(e.msg.sender == oldCurrent && newCurrent != 0 && f.selector == transferOwnership(address).selector) || (e.msg.sender == oldCurrent && newCurrent == 0 && f.selector == sig:renounceOwnership().selector)
(e.msg.sender == oldCurrent && newCurrent == 0 && f.selector == renounceOwnership().selector) );
); }
}

View File

@ -1,108 +1,108 @@
import "helpers/helpers.spec" import "helpers/helpers.spec";
import "methods/IOwnable2Step.spec" import "methods/IOwnable2Step.spec";
methods { methods {
restricted() function restricted() external;
} }
/* /*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Function correctness: transferOwnership sets the pending owner Function correctness: transferOwnership sets the pending owner
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/ */
rule transferOwnership(env e) { rule transferOwnership(env e) {
require nonpayable(e); require nonpayable(e);
address newOwner; address newOwner;
address current = owner(); address current = owner();
transferOwnership@withrevert(e, newOwner); transferOwnership@withrevert(e, newOwner);
bool success = !lastReverted; bool success = !lastReverted;
assert success <=> e.msg.sender == current, "unauthorized caller"; assert success <=> e.msg.sender == current, "unauthorized caller";
assert success => pendingOwner() == newOwner, "pending owner not set"; assert success => pendingOwner() == newOwner, "pending owner not set";
assert success => owner() == current, "current owner changed"; assert success => owner() == current, "current owner changed";
} }
/* /*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Function correctness: renounceOwnership removes the owner and the pendingOwner Function correctness: renounceOwnership removes the owner and the pendingOwner
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/ */
rule renounceOwnership(env e) { rule renounceOwnership(env e) {
require nonpayable(e); require nonpayable(e);
address current = owner(); address current = owner();
renounceOwnership@withrevert(e); renounceOwnership@withrevert(e);
bool success = !lastReverted; bool success = !lastReverted;
assert success <=> e.msg.sender == current, "unauthorized caller"; assert success <=> e.msg.sender == current, "unauthorized caller";
assert success => pendingOwner() == 0, "pending owner not cleared"; assert success => pendingOwner() == 0, "pending owner not cleared";
assert success => owner() == 0, "owner not cleared"; assert success => owner() == 0, "owner not cleared";
} }
/* /*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Function correctness: acceptOwnership changes owner and reset pending owner Function correctness: acceptOwnership changes owner and reset pending owner
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/ */
rule acceptOwnership(env e) { rule acceptOwnership(env e) {
require nonpayable(e); require nonpayable(e);
address current = owner(); address current = owner();
address pending = pendingOwner(); address pending = pendingOwner();
acceptOwnership@withrevert(e); acceptOwnership@withrevert(e);
bool success = !lastReverted; bool success = !lastReverted;
assert success <=> e.msg.sender == pending, "unauthorized caller"; assert success <=> e.msg.sender == pending, "unauthorized caller";
assert success => pendingOwner() == 0, "pending owner not cleared"; assert success => pendingOwner() == 0, "pending owner not cleared";
assert success => owner() == pending, "owner not transferred"; assert success => owner() == pending, "owner not transferred";
} }
/* /*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Access control: only current owner can call restricted functions Access control: only current owner can call restricted functions
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/ */
rule onlyCurrentOwnerCanCallOnlyOwner(env e) { rule onlyCurrentOwnerCanCallOnlyOwner(env e) {
require nonpayable(e); require nonpayable(e);
address current = owner(); address current = owner();
calldataarg args; calldataarg args;
restricted@withrevert(e, args); restricted@withrevert(e, args);
assert !lastReverted <=> e.msg.sender == current, "access control failed"; assert !lastReverted <=> e.msg.sender == current, "access control failed";
} }
/* /*
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
Rule: ownership and pending ownership can only change in specific ways Rule: ownership and pending ownership can only change in specific ways
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
*/ */
rule ownerOrPendingOwnerChange(env e, method f) { rule ownerOrPendingOwnerChange(env e, method f) {
address oldCurrent = owner(); address oldCurrent = owner();
address oldPending = pendingOwner(); address oldPending = pendingOwner();
calldataarg args; calldataarg args;
f(e, args); f(e, args);
address newCurrent = owner(); address newCurrent = owner();
address newPending = pendingOwner(); address newPending = pendingOwner();
// If owner changes, must be either acceptOwnership or renounceOwnership // If owner changes, must be either acceptOwnership or renounceOwnership
assert oldCurrent != newCurrent => ( assert oldCurrent != newCurrent => (
(e.msg.sender == oldPending && newCurrent == oldPending && newPending == 0 && f.selector == acceptOwnership().selector) || (e.msg.sender == oldPending && newCurrent == oldPending && newPending == 0 && f.selector == sig:acceptOwnership().selector) ||
(e.msg.sender == oldCurrent && newCurrent == 0 && newPending == 0 && f.selector == renounceOwnership().selector) (e.msg.sender == oldCurrent && newCurrent == 0 && newPending == 0 && f.selector == sig:renounceOwnership().selector)
); );
// If pending changes, must be either acceptance or reset // If pending changes, must be either acceptance or reset
assert oldPending != newPending => ( assert oldPending != newPending => (
(e.msg.sender == oldCurrent && newCurrent == oldCurrent && f.selector == transferOwnership(address).selector) || (e.msg.sender == oldCurrent && newCurrent == oldCurrent && f.selector == sig:transferOwnership(address).selector) ||
(e.msg.sender == oldPending && newCurrent == oldPending && newPending == 0 && f.selector == acceptOwnership().selector) || (e.msg.sender == oldPending && newCurrent == oldPending && newPending == 0 && f.selector == sig:acceptOwnership().selector) ||
(e.msg.sender == oldCurrent && newCurrent == 0 && newPending == 0 && f.selector == renounceOwnership().selector) (e.msg.sender == oldCurrent && newCurrent == 0 && newPending == 0 && f.selector == sig:renounceOwnership().selector)
); );
} }

View File

@ -1,5 +1,5 @@
methods { methods {
owner() returns (address) envfree function owner() external returns (address) envfree;
transferOwnership(address) function transferOwnership(address) external;
renounceOwnership() function renounceOwnership() external;
} }

View File

@ -1,7 +1,7 @@
methods { methods {
owner() returns (address) envfree function owner() external returns (address) envfree;
pendingOwner() returns (address) envfree function pendingOwner() external returns (address) envfree;
transferOwnership(address) function transferOwnership(address) external;
acceptOwnership() function acceptOwnership() external;
renounceOwnership() function renounceOwnership() external;
} }