2021-03-22 07:45:44 +00:00
|
|
|
pragma solidity ^0.7.0;
|
|
|
|
|
|
|
|
import "./SafeMath.sol";
|
|
|
|
|
2024-02-05 20:32:20 +00:00
|
|
|
contract InstaTimelock {
|
2021-03-22 07:45:44 +00:00
|
|
|
using SafeMath for uint;
|
|
|
|
|
|
|
|
event NewAdmin(address indexed newAdmin);
|
|
|
|
event NewPendingAdmin(address indexed newPendingAdmin);
|
|
|
|
event NewDelay(uint indexed newDelay);
|
2024-02-03 23:00:34 +00:00
|
|
|
event NewGuardian(address indexed newGuardian);
|
2021-03-22 07:45:44 +00:00
|
|
|
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);
|
|
|
|
|
|
|
|
uint public constant GRACE_PERIOD = 14 days;
|
2024-02-03 23:00:51 +00:00
|
|
|
uint public constant MINIMUM_DELAY = 1 hours;
|
2021-03-22 07:45:44 +00:00
|
|
|
uint public constant MAXIMUM_DELAY = 30 days;
|
|
|
|
|
|
|
|
address public admin;
|
|
|
|
address public pendingAdmin;
|
2024-02-04 20:45:51 +00:00
|
|
|
address public guardian;
|
2021-03-22 07:45:44 +00:00
|
|
|
uint public delay;
|
|
|
|
|
|
|
|
mapping (bytes32 => bool) public queuedTransactions;
|
|
|
|
|
|
|
|
|
2024-02-06 21:42:57 +00:00
|
|
|
constructor(address admin_, address guardian_) {
|
2021-03-22 07:45:44 +00:00
|
|
|
admin = admin_;
|
2024-02-06 21:42:57 +00:00
|
|
|
delay = 0; // delay set to "0"
|
2024-02-03 23:00:34 +00:00
|
|
|
guardian = guardian_;
|
2021-03-22 07:45:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fallback() external payable { }
|
|
|
|
|
|
|
|
function setDelay(uint delay_) public {
|
|
|
|
require(msg.sender == address(this), "Timelock::setDelay: Call must come from Timelock.");
|
|
|
|
require(delay_ >= MINIMUM_DELAY, "Timelock::setDelay: Delay must exceed minimum delay.");
|
|
|
|
require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay.");
|
|
|
|
delay = delay_;
|
|
|
|
|
|
|
|
emit NewDelay(delay);
|
|
|
|
}
|
|
|
|
|
2024-02-03 23:00:34 +00:00
|
|
|
function setGuardian(address guardian_) public {
|
|
|
|
require(msg.sender == address(this), "Timelock::setGuardian: Call must come from Timelock.");
|
|
|
|
guardian = guardian_;
|
|
|
|
|
|
|
|
emit NewGuardian(guardian_);
|
|
|
|
}
|
|
|
|
|
2021-03-22 07:45:44 +00:00
|
|
|
function acceptAdmin() public {
|
|
|
|
require(msg.sender == pendingAdmin, "Timelock::acceptAdmin: Call must come from pendingAdmin.");
|
|
|
|
admin = msg.sender;
|
|
|
|
pendingAdmin = address(0);
|
|
|
|
|
|
|
|
emit NewAdmin(admin);
|
|
|
|
}
|
|
|
|
|
|
|
|
function setPendingAdmin(address pendingAdmin_) public {
|
|
|
|
require(msg.sender == address(this), "Timelock::setPendingAdmin: Call must come from Timelock.");
|
|
|
|
pendingAdmin = pendingAdmin_;
|
|
|
|
|
|
|
|
emit NewPendingAdmin(pendingAdmin);
|
|
|
|
}
|
|
|
|
|
|
|
|
function queueTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public returns (bytes32) {
|
|
|
|
require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin.");
|
2024-02-06 21:42:57 +00:00
|
|
|
require(delay == 0 || eta >= getBlockTimestamp().add(delay), "Timelock::queueTransaction: Estimated execution block must satisfy delay.");
|
2021-03-22 07:45:44 +00:00
|
|
|
|
|
|
|
bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
|
|
|
|
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) public {
|
2024-02-03 23:00:34 +00:00
|
|
|
require(msg.sender == admin || msg.sender == guardian, "Timelock::cancelTransaction: Call must come from admin or guardian.");
|
2021-03-22 07:45:44 +00:00
|
|
|
|
|
|
|
bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
|
|
|
|
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) public payable returns (bytes memory) {
|
|
|
|
require(msg.sender == admin, "Timelock::executeTransaction: Call must come from admin.");
|
|
|
|
|
|
|
|
bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
|
|
|
|
require(queuedTransactions[txHash], "Timelock::executeTransaction: Transaction hasn't been queued.");
|
|
|
|
require(getBlockTimestamp() >= eta, "Timelock::executeTransaction: Transaction hasn't surpassed time lock.");
|
|
|
|
require(getBlockTimestamp() <= eta.add(GRACE_PERIOD), "Timelock::executeTransaction: Transaction is stale.");
|
|
|
|
|
|
|
|
queuedTransactions[txHash] = false;
|
|
|
|
|
|
|
|
bytes memory callData;
|
|
|
|
|
|
|
|
if (bytes(signature).length == 0) {
|
|
|
|
callData = data;
|
|
|
|
} else {
|
|
|
|
callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);
|
|
|
|
}
|
|
|
|
|
|
|
|
// solium-disable-next-line security/no-call-value
|
|
|
|
(bool success, bytes memory returnData) = target.call{value: value}(callData);
|
|
|
|
require(success, "Timelock::executeTransaction: Transaction execution reverted.");
|
|
|
|
|
|
|
|
emit ExecuteTransaction(txHash, target, value, signature, data, eta);
|
|
|
|
|
|
|
|
return returnData;
|
|
|
|
}
|
|
|
|
|
2024-02-04 18:57:47 +00:00
|
|
|
function executePayload(address target, string memory signature, bytes memory data) public returns (bytes memory) {
|
|
|
|
require(msg.sender == address(this), "Timelock::executePayload: Call must come from Timelock.");
|
|
|
|
bytes memory callData;
|
|
|
|
|
|
|
|
if (bytes(signature).length == 0) {
|
|
|
|
callData = data;
|
|
|
|
} else {
|
|
|
|
callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);
|
|
|
|
}
|
|
|
|
|
|
|
|
// solium-disable-next-line security/no-call-value
|
|
|
|
(bool success, bytes memory returnData) = target.delegatecall(callData);
|
|
|
|
require(success, "Timelock::executePayload: Transaction execution reverted.");
|
|
|
|
|
|
|
|
return returnData;
|
|
|
|
}
|
|
|
|
|
2021-03-22 07:45:44 +00:00
|
|
|
function getBlockTimestamp() internal view returns (uint) {
|
|
|
|
// solium-disable-next-line security/no-block-members
|
|
|
|
return block.timestamp;
|
|
|
|
}
|
|
|
|
}
|