Timelock Contract

The TimeLock contract is designed to enhance security and transparency of contract operations. This contract serves to enforce a mandatory delay (minDelay) on the execution of scheduled actions. Contract actions are scheduled by the admin role and can be cleared by the admin role or the contract role.

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

import '../ChallengeBase.sol';

/// @title Timelock contract
/// @author Challenge.GG
/// @dev The TimeLock contract is designed to enhance security and transparency of contract operations.  
/// This contract serves to enforce a mandatory delay (minDelay) on the execution of scheduled actions. 
/// Contract actions are scheduled by the admin role and can be cleared by the admin role or the contract role.
contract TimeLock {

    ChallengeBase private _baseContract; // Address to base contract that handles roles, templates and other common data
    uint public minDelay;
    mapping(bytes32 => uint) public timestampOf;

    /// Action scheduLed event
    event ActionScheduled(bytes32 indexed actionId, uint executionTime, string actionName, bytes data);

    /// @dev Restricted to members of the admin role.
    modifier onlyAdmin()
    {
        require(_baseContract.isAdmin(msg.sender), "Restricted to admin");
        _;
    }  

    /// @dev Restricted to members of the Contract role.
    modifier onlyContractOrAdmin()
    {
        require(_baseContract.isAdmin(msg.sender) || _baseContract.isContract(msg.sender), "Restricted to admin or allowed contracts");
        _;
    }

    /// @dev Constructor
    /// @param delay Delay in seconds
    constructor(address baseContract, uint delay) {
        require(baseContract != address(0), "Base contract address is the zero address");
        require(delay > 0, "Delay too short");
        _baseContract = ChallengeBase(baseContract);     
        minDelay = delay;
    }

    /// @dev Schedule an action to only be executed after the set delay
    /// @param actionName Name of the action
    /// @param parameters Parameters of the action
    /// @param initiator Address of the initiator
    /// @return actionId Id of the action
    function scheduleAction(string memory actionName, bytes memory parameters, address initiator) onlyAdmin external returns (bytes32) {
        bytes32 actionId = generateActionId(actionName, parameters, initiator);
        require(timestampOf[actionId] == 0, "Action already scheduled");
        uint executeAfter = block.timestamp + minDelay;
        timestampOf[actionId] = executeAfter;
        emit ActionScheduled(actionId, executeAfter, actionName, parameters);
        return actionId;
    }

    /// @dev Sets the base contract address
    /// @param baseContract Address to base contract that handles roles, templates and other common data
    function setBaseContract(address baseContract) external onlyAdmin {
         require(baseContract != address(0), "Base contract address is the zero address");
        _baseContract = ChallengeBase(baseContract);
    }


    /// @dev Clear a scheduled action
    /// @param actionId Id of the action
    function clearAction(bytes32 actionId) onlyContractOrAdmin public {
        require(timestampOf[actionId] != 0, "Action not scheduled");
        require(block.timestamp >= timestampOf[actionId], "Action time not elapsed");
        timestampOf[actionId] = 0;
    }

    /// @dev Get the execution time of an action
    function getExecutionTime(bytes32 actionId) public view returns (uint) {
        return timestampOf[actionId];
    }

    /// @dev Get the id of an action
    /// @param actionName Name of the action
    /// @param parameters Parameters of the action
    /// @param initiator Address of the initiator
    /// @return actionId Id of the actio
    function generateActionId(string memory actionName, bytes memory parameters, address initiator) public pure returns (bytes32) {
        return keccak256(abi.encodePacked(actionName, parameters, initiator));
    }
}

Last updated