> ## Documentation Index
> Fetch the complete documentation index at: https://docs.phylax.systems/llms.txt
> Use this file to discover all available pages before exploring further.

# Owner Change

> Assert that the owner of a contract has not changed unexpectedly

## When to Use This Pattern

Prevents unauthorized ownership transfers, which could allow attackers to take complete control of the protocol. Critical for DeFi protocols with owner-controlled administrative functions, lending protocols, yield aggregators, cross-chain bridges, and governance systems.

For example, in the [Radiant Capital hack](/assertions-book/previous-hacks/hack1-radiant-capital), 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.

## What This Pattern Checks

Monitors changes to the owner address storage slot in contracts using:

* `_preTx()` / `_postTx()` with Reshiram snapshot reads: Compare owner address before and after transaction
* `ph.loadStateAt()`: Load the owner and admin slots at each snapshot
* `registerTxEndTrigger()`: Trigger when owner address changes

The assertion performs both direct pre/post comparison and verification of all intermediate state changes to detect unauthorized ownership modifications.

For more information about cheatcodes, see the [Cheatcodes Documentation](/credible/cheatcodes-reference).

## Assertion Pattern

```solidity theme={null}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {Assertion} from "credible-std/Assertion.sol";
import {AssertionSpec} from "credible-std/SpecRecorder.sol";
import {PhEvm} from "credible-std/PhEvm.sol";

contract OwnerChangeAssertion is Assertion {
    bytes32 internal constant OWNER_SLOT = bytes32(uint256(0));
    bytes32 internal constant ADMIN_SLOT = bytes32(uint256(1));

    constructor() {
        registerAssertionSpec(AssertionSpec.Reshiram);
    }

    function triggers() external view override {
        registerTxEndTrigger(this.assertionOwnerChange.selector);
        registerTxEndTrigger(this.assertionAdminChange.selector);
    }

    /// @notice Checks that the owner slot is unchanged across the transaction.
    function assertionOwnerChange() external view {
        address adopter = ph.getAssertionAdopter();
        PhEvm.ForkId memory preFork = _preTx();
        PhEvm.ForkId memory postFork = _postTx();

        address preOwner = _loadAddressAt(adopter, OWNER_SLOT, preFork);
        address postOwner = _loadAddressAt(adopter, OWNER_SLOT, postFork);

        require(preOwner == postOwner, "Owner changed");
    }

    /// @notice Checks that the admin slot is unchanged across the transaction.
    function assertionAdminChange() external view {
        address adopter = ph.getAssertionAdopter();
        PhEvm.ForkId memory preFork = _preTx();
        PhEvm.ForkId memory postFork = _postTx();

        address preAdmin = _loadAddressAt(adopter, ADMIN_SLOT, preFork);
        address postAdmin = _loadAddressAt(adopter, ADMIN_SLOT, postFork);

        require(preAdmin == postAdmin, "Admin changed");
    }

    function _loadAddressAt(address target, bytes32 slot, PhEvm.ForkId memory fork) internal view returns (address) {
        return address(uint160(uint256(ph.loadStateAt(target, slot, fork))));
    }
}
```

<Note>Full examples and mock protocol code are available in [credible-std](https://github.com/phylaxsystems/credible-std/tree/master/examples/assertions-book).</Note>

## Related Patterns

* [Implementation Address Change](/assertions-book/assertions/ass01-impl-addr-change)
* [Timelock Verification](/assertions-book/assertions/ass09-timelock-verification)
