Owner Change
Assert that the owner of a contract has not changed unexpectedly
Use Case
Check that the owner of a contract has not changed unexpectedly. In many DeFi protocols, the owner address is a critical security parameter that controls administrative functions and protocol upgrades. An unauthorized change to this address could allow an attacker to take complete control of the protocol.
This assertion is particularly important for:
- Preventing unauthorized ownership transfers
- Ensuring ownership changes only occur through proper governance channels
- Detecting potential protocol hijacking attempts
- Maintaining protocol security by enforcing ownership invariants
For example, in the Radiant Capital hack, the attacker gained control over 3 signers of the multisig, which allowed them to change ownership of the lending pools and ultimately drain the protocol. This assertion would have prevented such an attack.
Applicable Protocols
- DeFi protocols with owner-controlled administrative functions
- Lending protocols where owner controls critical parameters
- Yield aggregators with owner-controlled strategy updates
- Cross-chain bridges with owner-controlled security parameters
- Governance systems that manage protocol upgrades
- Any protocol where owner privileges could lead to fund extraction or other security risks
Explanation
The assertion monitors changes to the owner address storage slot in contracts. The owner address typically determines who has administrative privileges over the contract.
The assertion uses the following cheatcodes and functions:
ph.forkPreState()
: Creates a fork of the state before the transaction to capture the original owner addressph.forkPostState()
: Creates a fork of the state after the transaction to detect any changesgetStateChangesAddress()
: Gets all state changes for the owner address storage slot in the callstack of the transaction to detect any changes to the owner addressregisterStorageChangeTrigger()
: Triggers the assertion when a change is detected in the owner address storage slot
The implementation performs two checks:
- A direct comparison between pre-state and post-state owner addresses
- A thorough verification of all state changes to the owner slot during the transaction’s execution
This multi-layered approach ensures that:
- The owner address remains constant unless explicitly changed through proper channels
- Any unauthorized attempts to modify the owner address are detected
- The contract’s administrative privileges cannot be transferred to malicious actors
For more information about cheatcodes, see the Cheatcodes Documentation.
Code Example
Note: This code example is maintained in the Phylax Assertion Examples Repository. For a full examples with mock protocol code and tests please refer to the repository.
Testing
To test this assertion:
- Deploy a mock contract implementing the
IOwnership
interface - Set up the assertion with the mock contract address
- Test various scenarios:
- Normal operation with no ownership changes
- Attempted unauthorized ownership transfer
- Legitimate ownership transfer through proper channels (pausing the assertion or using a whitelist)
- Multiple ownership changes in a single transaction
For complete test examples, see the Phylax Assertion Examples Repository.
Assertion Best Practices
- Consider combining this assertion with other assertions like Implementation Address Change for comprehensive security
- Use the
getStateChangesAddress
cheatcode to detect changes to the owner address throughout the callstack of the transaction - Consider whitelisting specific owner addresses if you know the set of allowed future owners
- Ensure proper error messages in the assertion to help with debugging
- Add additional checks for admin/operator addresses if your protocol uses multiple administrative roles