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

```solidity
// 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));
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://whitepaper.challenge.gg/tokenomics/contracts/timelock-contract.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
