3分钟Solidity: 10.6 时间锁定

欢迎订阅专栏 :3分钟Solidity--智能合约--Web3区块链技术必学

如需获取本内容的最新版本,请参见 Cyfrin.io 的Time Lock(代码示例)

TimeLock是一种合约,用于发布将在未来执行的交易。

经过最短等待期后,该交易即可执行。

TimeLock在DAO中经常被使用。

scss 复制代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

contract TimeLock {
    error NotOwnerError();
    error AlreadyQueuedError(bytes32 txId);
    error TimestampNotInRangeError(uint256 blockTimestamp, uint256 timestamp);
    error NotQueuedError(bytes32 txId);
    error TimestampNotPassedError(uint256 blockTimestamp, uint256 timestamp);
    error TimestampExpiredError(uint256 blockTimestamp, uint256 expiresAt);
    error TxFailedError();

    event Queue(
        bytes32 indexed txId,
        address indexed target,
        uint256 value,
        string func,
        bytes data,
        uint256 timestamp
    );
    event Execute(
        bytes32 indexed txId,
        address indexed target,
        uint256 value,
        string func,
        bytes data,
        uint256 timestamp
    );
    event Cancel(bytes32 indexed txId);

    uint256 public constant MIN_DELAY = 10; // seconds
    uint256 public constant MAX_DELAY = 1000; // seconds
    uint256 public constant GRACE_PERIOD = 1000; // seconds

    address public owner;
    // tx id => queued
    mapping(bytes32 => bool) public queued;

    constructor() {
        owner = msg.sender;
    }

    modifier onlyOwner() {
        if (msg.sender != owner) {
            revert NotOwnerError();
        }
        _;
    }

    receive() external payable {}

    function getTxId(
        address _target,
        uint256 _value,
        string calldata _func,
        bytes calldata _data,
        uint256 _timestamp
    ) public pure returns (bytes32) {
        return keccak256(abi.encode(_target, _value, _func, _data, _timestamp));
    }

    /**
     * @param _target Address of contract or account to call
     * @param _value Amount of ETH to send
     * @param _func Function signature, for example "foo(address,uint256)"
     * @param _data ABI encoded data send.
     * @param _timestamp Timestamp after which the transaction can be executed.
     */
    function queue(
        address _target,
        uint256 _value,
        string calldata _func,
        bytes calldata _data,
        uint256 _timestamp
    ) external onlyOwner returns (bytes32 txId) {
        txId = getTxId(_target, _value, _func, _data, _timestamp);
        if (queued[txId]) {
            revert AlreadyQueuedError(txId);
        }
        // ---|------------|---------------|-------
        //  block    block + min     block + max
        if (
            _timestamp < block.timestamp + MIN_DELAY
                || _timestamp > block.timestamp + MAX_DELAY
        ) {
            revert TimestampNotInRangeError(block.timestamp, _timestamp);
        }

        queued[txId] = true;

        emit Queue(txId, _target, _value, _func, _data, _timestamp);
    }

    function execute(
        address _target,
        uint256 _value,
        string calldata _func,
        bytes calldata _data,
        uint256 _timestamp
    ) external payable onlyOwner returns (bytes memory) {
        bytes32 txId = getTxId(_target, _value, _func, _data, _timestamp);
        if (!queued[txId]) {
            revert NotQueuedError(txId);
        }
        // ----|-------------------|-------
        //  timestamp    timestamp + grace period
        if (block.timestamp < _timestamp) {
            revert TimestampNotPassedError(block.timestamp, _timestamp);
        }
        if (block.timestamp > _timestamp + GRACE_PERIOD) {
            revert TimestampExpiredError(
                block.timestamp, _timestamp + GRACE_PERIOD
            );
        }

        queued[txId] = false;

        // prepare data
        bytes memory data;
        if (bytes(_func).length > 0) {
            // data = func selector + _data
            data = abi.encodePacked(bytes4(keccak256(bytes(_func))), _data);
        } else {
            // call fallback with data
            data = _data;
        }

        // call target
        (bool ok, bytes memory res) = _target.call{value: _value}(data);
        if (!ok) {
            revert TxFailedError();
        }

        emit Execute(txId, _target, _value, _func, _data, _timestamp);

        return res;
    }

    function cancel(bytes32 _txId) external onlyOwner {
        if (!queued[_txId]) {
            revert NotQueuedError(_txId);
        }

        queued[_txId] = false;

        emit Cancel(_txId);
    }
}

Remix Lite 尝试一下

相关推荐
kjmkq18 小时前
区块链项目出海宣发,依托全球Web3垂直媒体快速建立行业背书
web3·区块链·媒体
梦帮科技1 天前
【3.0修订版】跨链中继与事件编排:Relayer 监听、多签验证与故障自愈
web安全·金融·区块链·密码学·智能合约·安全架构·信任链
梦帮科技2 天前
【3.0修订版】钱包与安全:Web4 智能钱包、硬件隔离与后量子密码实践
安全·去中心化·区块链·智能合约·同态加密·共识算法·信任链
梦帮科技2 天前
【3.0修订版】音乐权利 NFT:MusicRightsNFT 的确权思想与授权关联
网络协议·算法·web3·区块链·密码学·智能合约·零知识证明
怒放de生命20102 天前
2026年新加坡TOKEN2049大会:传统金融与加密世界的深度融合与现实叩问
人工智能·web3·去中心化·区块链·以太坊·分布式账本
梦帮科技3 天前
【3.0修订版】多链版图演进:BSC、Ethereum、TRON、Base、Arbitrum 部署路线
去中心化·区块链·智能合约·同态加密·共识算法·信任链·分布式账本
梦帮科技4 天前
【3.0修订版】# 创作者激励池与空投分发:AirdropDistributor 与 20% 生态分配
去中心化·区块链·智能合约·同态加密·共识算法·信任链·分布式账本
梦帮科技4 天前
【3.0修订版】跨链桥架构与资产守恒:BSCBridge、BSCMirrorBridge 与 Lock-and-Mint 模型
架构·去中心化·区块链·智能合约·共识算法·信任链
梦帮科技5 天前
【3.0修订版】创世与节点工程:genesis.json 与 node.toml 解剖
数据结构·算法·json·去中心化·区块链·智能合约·信任链
怒放de生命20107 天前
【web3基础】区块链演化逻辑:从分布式账本到可编程世界
web3·区块链·分布式账本