> ## 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.

# Storage Lookup

> Access the value of a storage variable at a specific address. Even if the variable is not publicly accessible and not part of the contract's state.

Storage lookup mappings describe how assertions can read raw storage slots from a target contract when a public getter is not available.

## Status

* [x] Supported
* [ ] Partially Supported
* [ ] Not Supported Yet

## Implementation Details

### Required Cheatcodes

* `loadStateAt(address target, bytes32 slot, ForkId fork)` - Reads the raw storage value at the given slot for the specified contract address and snapshot

### Example Implementation

Protocol:

```solidity theme={null}
import {AssertionSpec} from "credible-std/SpecRecorder.sol";

contract Protocol {
    // This variable is stored in slot 0
    address owner;

    function setOwner(address owner_) public {
        owner = owner_;
    }
}
```

Assertion:

```solidity theme={null}
contract StorageLookupAssertion is Assertion {
    constructor() {
        registerAssertionSpec(AssertionSpec.Reshiram);
    }

    function triggers() public view override {
        registerTxEndTrigger(this.assertionStorageLookup.selector);
    }

    function assertionStorageLookup() public view {
        Protocol protocol = Protocol(ph.getAssertionAdopter());
        // Define a whitelist of allowed owner addresses
        address[] memory whitelist = new address[](2);
        whitelist[0] = address(0x1);
        whitelist[1] = address(0x2);

        // Read owner from storage slot 0 at the post-transaction snapshot.
        // Complex casting is needed because loadStateAt() returns bytes32.
        // 1. Convert bytes32 to uint256
        // 2. Convert uint256 to uint160 (address size)
        // 3. Cast to address type
        PhEvm.ForkId memory postTx = _postTx();
        address owner = address(uint160(uint256(ph.loadStateAt(address(protocol), bytes32(uint256(0)), postTx))));

        // Verify the owner is in the whitelist
        for (uint256 i = 0; i < whitelist.length; i++) {
            if (owner == whitelist[i]) {
                return;
            }
        }

        revert("Owner not in whitelist");
    }
}
```

### Implementation Notes

* **Storage access capabilities:**
  * You can load specific slots from any address, even if no public getter exists
  * Works with both external and internal contract storage

## Example Use Cases

* Read slots of private inputs where no getter is available:
  * e.g. implementation address of ERC1967
* Access internal contract state for validation
* Verify ownership or admin privileges properly set

## Implementation Considerations

1. **State snapshot semantics:**
   * Values can only be read from pre or post states of the executed transactions
   * No access to intermediate state changes during transaction execution
   * To work around this, use `getStateChanges()` to capture all intermediate values

2. **Storage layout knowledge:**
   * Requires understanding of the target contract's storage layout
   * May need complex casting for packed storage slots

## Future Improvements

* Provide intra-transaction snapshot states
* Add helper functions for common storage patterns
* Implement automatic storage layout detection
