Compound 治理——执行队列 TimeLock

简介

对应的代码TimeLock.sol

TimeLock.sol 直译为时间锁。其实是一个在solidity中实现的队列。
可以将代码加入队列,从队列中执行。执行方式为call调用。不支持重复调用,相同的地址和参数作为一个任务,重复添加无效,调用时只会调用一次,后续调用会失败,调用后再次加入队列可以调用成功。

代码解析

  • uint public constant GRACE_PERIOD = 14 days; 宽限时间

  • uint public constant MINIMUM_DELAY = 0; 最小延期时间

  • uint public constant MAXIMUM_DELAY = 30 days;最大延期时间

  • address public admin; 管理员

  • address public pendingAdmin; 待定管理员

  • uint public delay; 延期时间

  • mapping (bytes32 => bool) public queuedTransactions; 交易队列

  • constructor(address admin_, uint delay_) 构造方法
    传入 管理员的地址和延期时间,延期时间需要大于等于 MINIMUM_DELAY且小于等于MAXIMUM_DELAY。
    管理员地址不能是0地址。

    constructor(address admin_, uint delay_) public {
        require(delay_ >= MINIMUM_DELAY, "Timelock: Delay must exceed minimum delay.");
        require(delay_ <= MAXIMUM_DELAY, "Timelock: Delay must not exceed maximum delay.");
        require(admin_ != address(0), "Timelock: Admin must not be 0 address");

        admin = admin_;
        delay = delay_;
    }
  • receive() external payable { }
    合约最多可以具有一个receive函数。这个函数不能有参数,不能返回任何参数,并且必须具有receive可见性和payable状态可变性。当向合约发送 Ether 且未指定调用任何函数(calldata 为空)时执行。这是在普通的以太坊转账上执行的函数(例如,通过.send()或.transfer()转账)。
    如果 receive 函数不存在,但是有payable的 fallback 回退函数,那么在进行纯以太转账时,fallback 函数会调用。
    如果两个函数都没有,这个合约就没法通过常规的转账交易接收以太(会抛出异常)。

  • function setDelay(uint delay_)
    设置新的延期时间,只有管理员能进行设置,延期时间需要大于等于MINIMUM_DELAY且小于等于MAXIMUM_DELAY

    function setDelay(uint delay_) public {
        require(msg.sender == address(this), "Timelock: Call must come from Timelock.");
        require(delay_ >= MINIMUM_DELAY, "Timelock: Delay must exceed minimum delay.");
        require(delay_ <= MAXIMUM_DELAY, "Timelock: Delay must not exceed maximum delay.");
        delay = delay_;

        emit NewDelay(delay);
    }
  • function acceptAdmin() 任职管理员
    待定管理员转正,由待定管理员调用,并将其设置为管理员,待定管理员设置为0地址。
    function acceptAdmin() public {
        require(msg.sender == pendingAdmin, "Timelock: Call must come from pendingAdmin.");
        admin = msg.sender;
        pendingAdmin = address(0);

        emit NewAdmin(admin);
    }
  • function setPendingAdmin(address pendingAdmin_) 设置待定管理员
    由管理员调用,将某人设置为待定管理员
    function setPendingAdmin(address pendingAdmin_) public {
        require(msg.sender == address(this), "Timelock: Call must come from Timelock.");
        pendingAdmin = pendingAdmin_;

        emit NewPendingAdmin(pendingAdmin);
    }
  • function queueTransaction
    加入队列
    由管理员调用 当 eta>=当前区块时间+延期时间时可以调用,将某提案的target, value, signature, data, eta存入队列,并设置状态为true,代表队列等待执行
    function queueTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public returns (bytes32) {
        require(msg.sender == admin, "Timelock: Call must come from admin.");
        require(eta >= getBlockTimestamp().add(delay), "Timelock: 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
    取消队列由管理员调用 将target, value, signature, data, eta的提案状态设置为false
    function cancelTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public {
        require(msg.sender == admin, "Timelock: 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 执行队列
    由管理员执行。
    根据target, value, signature, data, eta取出队列,如果是待执行状态,则执行该队列。
    只有区块在eta及之后,eta+宽限时间之前才能执行。
    队列使用call的方式进行执行。
    function executeTransaction(address target, uint value, string memory signature, bytes memory data, uint eta) public payable returns (bytes memory) {
        require(msg.sender == admin, "Timelock: Call must come from admin.");

        bytes32 txHash = keccak256(abi.encode(target, value, signature, data, eta));
        require(queuedTransactions[txHash], "Timelock: Transaction hasn't been queued.");
        require(getBlockTimestamp() >= eta, "Timelock: Transaction hasn't surpassed time lock.");
        require(getBlockTimestamp() <= eta.add(GRACE_PERIOD), "Timelock: 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);
        }

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returnData) = target.call{value: value}(callData); //solhint-disable avoid-call-value
        require(success, "Timelock: Transaction execution reverted.");

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

        return returnData;
    }
  • getBlockTimestamp()获取当前区块的时间戳
    function getBlockTimestamp() internal view returns (uint) {
        // solhint-disable-next-line not-rely-on-time
        return block.timestamp;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子显

来杯咖啡鼓励下吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值