Use Case

Check if the owner of a contract has changed. This is useful in cases where you want to make sure that the owner of a contract is not changed. An example where this has happened was in the Radiant Capital hack where the owner was changed through a hijacked multisig transaction. This allowed the attacker to drain the protocol.

Explanation

The assertion checks if the owner of a contract has changed after a transaction has been executed.

Code Example

// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

import {Assertion} from "../lib/credible-std/Assertion.sol";

interface IOwnership {
    function owner() external view returns (address);

    function admin() external view returns (address);
}

// This is a simple example of an assertion that checks if the owner has changed.
// You can import your own ownership contract and modify the assertion accordingly.
contract OwnerChange is Assertion {
    IOwnership public ownership = IOwnership(address(0xbeef));

    function fnSelectors() external pure override returns (Trigger[] memory) {
        Trigger[] memory triggers = new Trigger[](2); // Define the number of triggers
        triggers[0] = Trigger(TriggerType.STORAGE, this.assertionOwnerChange.selector); // Define the trigger
        triggers[1] = Trigger(TriggerType.STORAGE, this.assertionAdminChange.selector); // Example of another trigger
        return triggers;
    }

    // This function is used to check if the owner has changed.
    // return true indicates a valid state
    // return false indicates an invalid state
    function assertionOwnerChange() external returns (bool) {
        ph.forkPreState(); // fork the pre state - the state before the transaction
        address preOwner = ownership.owner(); // get the owner before the transaction
        ph.forkPostState(); // fork the post state - the state after the transaction
        address postOwner = ownership.owner(); // get the owner after the transaction
        return preOwner == postOwner; // return false if the owner has changed (invalid state)
    }

    // This function is used to check if the admin has changed.
    // It works in the same way as the ownerChange function, and here it's used as
    // an example of how to add another trigger to the assertion.
    function assertionAdminChange() external virtual returns (bool) {
        ph.forkPreState(); // fork the pre state - the state before the transaction
        address preAdmin = ownership.admin(); // get the admin before the transaction
        ph.forkPostState(); // fork the post state - the state after the transaction
        address postAdmin = ownership.admin(); // get the admin after the transaction
        return preAdmin == postAdmin; // return false if the admin has changed (invalid state)
    }
}