简介
对应的代码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_DELAYfunction 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的提案状态设置为falsefunction 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; }