ETH Price: $1,974.93 (-1.93%)

Contract Diff Checker

Contract Name:
Timelock

Contract Source Code:

<i class='far fa-question-circle text-muted ms-2' data-bs-trigger='hover' data-bs-toggle='tooltip' data-bs-html='true' data-bs-title='Click on the check box to select individual contract to compare. Only 1 contract can be selected from each side.'></i>

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

contract Timelock {
	event NewAdmin(address indexed newAdmin);
	event NewPendingAdmin(address indexed newPendingAdmin);
	event NewDelay(uint indexed newDelay);
	event CancelTransaction(
		bytes32 indexed txHash,
		address indexed target,
		uint value,
		string signature,
		bytes data,
		uint eta
	);
	event ExecuteTransaction(
		bytes32 indexed txHash,
		address indexed target,
		uint value,
		string signature,
		bytes data,
		uint eta
	);
	event QueueTransaction(
		bytes32 indexed txHash,
		address indexed target,
		uint value,
		string signature,
		bytes data,
		uint eta
	);

	error Timelock__DelayMustExceedMininumDelay();
	error Timelock__DelayMustNotExceedMaximumDelay();
	error Timelock__TimelockOnly();
	error Timelock__PendingAdminOnly();
	error Timelock__AdminOnly();
	error Timelock__ETAMustSatisfyDelay();
	error Timelock__TxNoQueued();
	error Timelock__TxAlreadyQueued();
	error Timelock__TxStillLocked();
	error Timelock__TxExpired();
	error Timelock__TxReverted();

	string public constant NAME = "Timelock";

	uint public constant GRACE_PERIOD = 14 days;
	//uint public constant MINIMUM_DELAY = 2 days;
    uint public constant MINIMUM_DELAY = 5 minutes;
	uint public constant MAXIMUM_DELAY = 15 days;

	address public admin;
	address public pendingAdmin;
	uint public delay;

	mapping(bytes32 => bool) public queuedTransactions;

	modifier isValidDelay(uint256 _delay) virtual {
		if (_delay < MINIMUM_DELAY) {
			revert Timelock__DelayMustExceedMininumDelay();
		}
		if (_delay > MAXIMUM_DELAY) {
			revert Timelock__DelayMustNotExceedMaximumDelay();
		}
		_;
	}

	modifier adminOnly() {
		if (msg.sender != admin) {
			revert Timelock__AdminOnly();
		}
		_;
	}

	constructor(uint _delay, address _adminAddress) isValidDelay(_delay) {
		require(_adminAddress != address(0));
		admin = _adminAddress;
		delay = _delay;
	}

	receive() external payable {}

	function setDelay(uint _delay) external isValidDelay(_delay) {
		if (msg.sender != address(this)) {
			revert Timelock__TimelockOnly();
		}
		delay = _delay;

		emit NewDelay(_delay);
	}

	function acceptAdmin() external {
		if (msg.sender != pendingAdmin) {
			revert Timelock__PendingAdminOnly();
		}
		admin = msg.sender;
		pendingAdmin = address(0);

		emit NewAdmin(msg.sender);
	}

	function setPendingAdmin(address _pendingAdmin) external {
		if (msg.sender != address(this)) {
			revert Timelock__TimelockOnly();
		}
		pendingAdmin = _pendingAdmin;

		emit NewPendingAdmin(_pendingAdmin);
	}

	function queueTransaction(
		address target,
		uint value,
		string memory signature,
		bytes memory data,
		uint eta
	) external adminOnly returns (bytes32) {
		if (eta < block.timestamp + delay || eta > block.timestamp + delay + GRACE_PERIOD) {
			revert Timelock__ETAMustSatisfyDelay();
		}

		bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
		if (queuedTransactions[txHash]) {
			revert Timelock__TxAlreadyQueued();
		}
		queuedTransactions[txHash] = true;

		emit QueueTransaction(txHash, target, value, signature, data, eta);
		return txHash;
	}

	function cancelTransaction(
		address target,
		uint value,
		string memory signature,
		bytes memory data,
		uint eta
	) external adminOnly {
		bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
		if (!queuedTransactions[txHash]) {
			revert Timelock__TxNoQueued();
		}
		queuedTransactions[txHash] = false;

		emit CancelTransaction(txHash, target, value, signature, data, eta);
	}

	function executeTransaction(
		address target,
		uint value,
		string memory signature,
		bytes memory data,
		uint eta
	) external payable adminOnly returns (bytes memory) {
		bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
		if (!queuedTransactions[txHash]) {
			revert Timelock__TxNoQueued();
		}
		if (block.timestamp < eta) {
			revert Timelock__TxStillLocked();
		}
		if (block.timestamp > eta + GRACE_PERIOD) {
			revert Timelock__TxExpired();
		}

		queuedTransactions[txHash] = false;

		bytes memory callData;

		if (bytes(signature).length == 0) {
			callData = data;
		} else {
			callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);
		}

		// Execute the call
		(bool success, bytes memory returnData) = target.call{ value: value }(callData);
		if (!success) {
			revert Timelock__TxReverted();
		}

		emit ExecuteTransaction(txHash, target, value, signature, data, eta);

		return returnData;
	}
}

Please enter a contract address above to load the contract details and source code.

Context size (optional):