Use Case & Applications

Ensures timelocks are correctly triggered for governance actions, enforcing delays between proposal and execution to allow community review. Critical for DeFi lending protocols, DEX protocols, yield aggregators, cross-chain bridges, and DAOs that use timelocks to prevent flash loan attacks, allow security review periods, and protect against governance attacks. Timelocks provide a buffer against malicious governance actions - without proper enforcement, changes could be executed immediately.

Explanation

Verifies timelock integrity by comparing timelock state and parameters before and after transactions:
  • forkPreState() / forkPostState(): Compare timelock state before and after transaction
  • registerStorageChangeTrigger(): Monitor changes to timelock storage slot
  • Ensures timelock delay is within acceptable bounds (1 day to 2 weeks)
  • Confirms timelock activation follows proper procedures
The assertion performs both pre/post state comparison and parameter validation to ensure governance changes follow proper timelock procedures. For more information about cheatcodes, see the Cheatcodes Documentation.

Code Example

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

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

contract TimelockVerificationAssertion is Assertion {
    function triggers() external view override {
        // Register trigger for changes to the timelock storage slot
        registerStorageChangeTrigger(this.assertionTimelock.selector, bytes32(uint256(0)));
    }

    // Verify that a timelock is working as expected after some governance action
    function assertionTimelock() external {
        // Get the assertion adopter address
        IGovernance adopter = IGovernance(ph.getAssertionAdopter());

        // Get pre-state timelock information
        ph.forkPreTx();
        bool preActive = adopter.timelockActive();

        // If timelock was already active, no need to check further
        if (preActive) {
            return;
        }

        // Get post-state timelock information
        ph.forkPostTx();

        // If timelock is now active, verify all parameters
        if (adopter.timelockActive()) {
            // Verify timelock delay is within acceptable bounds
            bool minDelayCorrect = adopter.timelockDelay() >= 1 days;
            bool maxDelayCorrect = adopter.timelockDelay() <= 2 weeks;

            // Require all parameters to be correct
            require(minDelayCorrect && maxDelayCorrect, "Timelock parameters invalid");
        }
    }
}

interface IGovernance {
    struct Timelock {
        uint256 timelockDelay;
        bool isActive;
    }

    function timelockActive() external view returns (bool);
    function timelockDelay() external view returns (uint256);
    function activateTimelock() external;
    function setTimelock(uint256 _delay) external;
}
Note: Full examples with tests available in the Phylax Assertion Examples Repository.