Add Governor contracts (#2672)
Co-authored-by: Francisco Giordano <frangio.1@gmail.com>
This commit is contained in:
174
contracts/mocks/compound/CompTimelock.sol
Normal file
174
contracts/mocks/compound/CompTimelock.sol
Normal file
@ -0,0 +1,174 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
// solhint-disable private-vars-leading-underscore
|
||||
/**
|
||||
* Copyright 2020 Compound Labs, Inc.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
|
||||
* following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
|
||||
* disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
|
||||
* following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
|
||||
* products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
contract CompTimelock {
|
||||
event NewAdmin(address indexed newAdmin);
|
||||
event NewPendingAdmin(address indexed newPendingAdmin);
|
||||
event NewDelay(uint256 indexed newDelay);
|
||||
event CancelTransaction(
|
||||
bytes32 indexed txHash,
|
||||
address indexed target,
|
||||
uint256 value,
|
||||
string signature,
|
||||
bytes data,
|
||||
uint256 eta
|
||||
);
|
||||
event ExecuteTransaction(
|
||||
bytes32 indexed txHash,
|
||||
address indexed target,
|
||||
uint256 value,
|
||||
string signature,
|
||||
bytes data,
|
||||
uint256 eta
|
||||
);
|
||||
event QueueTransaction(
|
||||
bytes32 indexed txHash,
|
||||
address indexed target,
|
||||
uint256 value,
|
||||
string signature,
|
||||
bytes data,
|
||||
uint256 eta
|
||||
);
|
||||
|
||||
uint256 public constant GRACE_PERIOD = 14 days;
|
||||
uint256 public constant MINIMUM_DELAY = 2 days;
|
||||
uint256 public constant MAXIMUM_DELAY = 30 days;
|
||||
|
||||
address public admin;
|
||||
address public pendingAdmin;
|
||||
uint256 public delay;
|
||||
|
||||
mapping(bytes32 => bool) public queuedTransactions;
|
||||
|
||||
constructor(address admin_, uint256 delay_) {
|
||||
require(delay_ >= MINIMUM_DELAY, "Timelock::constructor: Delay must exceed minimum delay.");
|
||||
require(delay_ <= MAXIMUM_DELAY, "Timelock::setDelay: Delay must not exceed maximum delay.");
|
||||
|
||||
admin = admin_;
|
||||
delay = delay_;
|
||||
}
|
||||
|
||||
receive() external payable {}
|
||||
|
||||
function setDelay(uint256 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);
|
||||
}
|
||||
|
||||
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,
|
||||
uint256 value,
|
||||
string memory signature,
|
||||
bytes memory data,
|
||||
uint256 eta
|
||||
) public returns (bytes32) {
|
||||
require(msg.sender == admin, "Timelock::queueTransaction: Call must come from admin.");
|
||||
require(
|
||||
eta >= getBlockTimestamp() + delay,
|
||||
"Timelock::queueTransaction: Estimated execution block must satisfy delay."
|
||||
);
|
||||
|
||||
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,
|
||||
uint256 value,
|
||||
string memory signature,
|
||||
bytes memory data,
|
||||
uint256 eta
|
||||
) public {
|
||||
require(msg.sender == admin, "Timelock::cancelTransaction: Call must come from admin.");
|
||||
|
||||
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,
|
||||
uint256 value,
|
||||
string memory signature,
|
||||
bytes memory data,
|
||||
uint256 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 + 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;
|
||||
}
|
||||
|
||||
function getBlockTimestamp() internal view returns (uint256) {
|
||||
// solium-disable-next-line security/no-block-members
|
||||
return block.timestamp;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user