【从0学习Solidity】45. 时间锁

news/2024/12/23 1:33:37/

【从0学习Solidity】45. 时间锁

在这里插入图片描述

  • 博主简介:不写代码没饭吃,一名全栈领域的创作者,专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构,分享一些项目实战经验以及前沿技术的见解。
  • 关注我们的主页,探索全栈开发,期待与您一起在移动开发的世界中,不断进步和创造!
  • 本文收录于 不写代码没饭吃 的学习汇报系列,大家有兴趣的可以看一看。
  • 欢迎访问我们的微信公众号:不写代码没饭吃,获取更多精彩内容、实用技巧、行业资讯等。您关注的是我们前进的动力!

这一讲,我们介绍时间锁和时间锁合约。代码由Compound的Timelock合约简化而来。

时间锁

45-1.jpeg

时间锁(Timelock)是银行金库和其他高安全性容器中常见的锁定机制。它是一种计时器,旨在防止保险箱或保险库在预设时间之前被打开,即便开锁的人知道正确密码。

在区块链,时间锁被DeFiDAO大量采用。它是一段代码,他可以将智能合约的某些功能锁定一段时间。它可以大大改善智能合约的安全性,举个例子,假如一个黑客黑了Uniswap的多签,准备提走金库的钱,但金库合约加了2天锁定期的时间锁,那么黑客从创建提钱的交易,到实际把钱提走,需要2天的等待期。在这一段时间,项目方可以找应对办法,投资者可以提前抛售代币减少损失。

时间锁合约

下面,我们介绍一下时间锁Timelock合约。它的逻辑并不复杂:

  • 在创建Timelock合约时,项目方可以设定锁定期,并把合约的管理员设为自己。

  • 时间锁主要有三个功能:

    • 创建交易,并加入到时间锁队列。
    • 在交易的锁定期满后,执行交易。
    • 后悔了,取消时间锁队列中的某些交易。
  • 项目方一般会把时间锁合约设为重要合约的管理员,例如金库合约,再通过时间锁操作他们。

  • 时间锁合约的管理员一般为项目的多签钱包,保证去中心化。

事件

Timelock合约中共有4个事件。

  • QueueTransaction:交易创建并进入时间锁队列的事件。
  • ExecuteTransaction:锁定期满后交易执行的事件。
  • CancelTransaction:交易取消事件。
  • NewAdmin:修改管理员地址的事件。
    // 事件// 交易取消事件event CancelTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature,  bytes data, uint executeTime);// 交易执行事件event ExecuteTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature,  bytes data, uint executeTime);// 交易创建并进入队列 事件event QueueTransaction(bytes32 indexed txHash, address indexed target, uint value, string signature, bytes data, uint executeTime);// 修改管理员地址的事件event NewAdmin(address indexed newAdmin);

状态变量

Timelock合约中共有4个状态变量。

  • admin:管理员地址。
  • delay:锁定期。
  • GRACE_PERIOD:交易过期时间。如果交易到了执行的时间点,但在GRACE_PERIOD没有被执行,就会过期。
  • queuedTransactions:进入时间锁队列交易的标识符txHashbool的映射,记录所有在时间锁队列中的交易。
    // 状态变量address public admin; // 管理员地址uint public constant GRACE_PERIOD = 7 days; // 交易有效期,过期的交易作废uint public delay; // 交易锁定时间 (秒)mapping (bytes32 => bool) public queuedTransactions; // txHash到bool,记录所有在时间锁队列中的交易

修饰器

Timelock合约中共有2modifier

  • onlyOwner():被修饰的函数只能被管理员执行。
  • onlyTimelock():被修饰的函数只能被时间锁合约执行。
    // onlyOwner modifiermodifier onlyOwner() {require(msg.sender == admin, "Timelock: Caller not admin");_;}// onlyTimelock modifiermodifier onlyTimelock() {require(msg.sender == address(this), "Timelock: Caller not Timelock");_;}

函数

Timelock合约中共有7个函数。

  • 构造函数:初始化交易锁定时间(秒)和管理员地址。

  • queueTransaction():创建交易并添加到时间锁队列中。参数比较复杂,因为要描述一个完整的交易:

    • target:目标合约地址
    • value:发送ETH数额
    • signature:调用的函数签名(function signature)
    • data:交易的call data
    • executeTime:交易执行的区块链时间戳。

    调用这个函数时,要保证交易预计执行时间executeTime大于当前区块链时间戳+锁定时间delay。交易的唯一标识符为所有参数的哈希值,利用getTxHash()函数计算。进入队列的交易会更新在queuedTransactions变量中,并释放QueueTransaction事件。

  • executeTransaction():执行交易。它的参数与queueTransaction()相同。要求被执行的交易在时间锁队列中,达到交易的执行时间,且没有过期。执行交易时用到了solidity的低级成员函数call,在第22讲中有介绍。

  • cancelTransaction():取消交易。它的参数与queueTransaction()相同。它要求被取消的交易在队列中,会更新queuedTransactions并释放CancelTransaction事件。

  • changeAdmin():修改管理员地址,只能被Timelock合约调用。

  • getBlockTimestamp():获取当前区块链时间戳。

  • getTxHash():返回交易的标识符,为很多交易参数的hash

    /*** @dev 构造函数,初始化交易锁定时间 (秒)和管理员地址*/constructor(uint delay_) {delay = delay_;admin = msg.sender;}/*** @dev 改变管理员地址,调用者必须是Timelock合约。*/function changeAdmin(address newAdmin) public onlyTimelock {admin = newAdmin;emit NewAdmin(newAdmin);}/*** @dev 创建交易并添加到时间锁队列中。* @param target: 目标合约地址* @param value: 发送eth数额* @param signature: 要调用的函数签名(function signature)* @param data: call data,里面是一些参数* @param executeTime: 交易执行的区块链时间戳** 要求:executeTime 大于 当前区块链时间戳+delay*/function queueTransaction(address target, uint256 value, string memory signature, bytes memory data, uint256 executeTime) public onlyOwner returns (bytes32) {// 检查:交易执行时间满足锁定时间require(executeTime >= getBlockTimestamp() + delay, "Timelock::queueTransaction: Estimated execution block must satisfy delay.");// 计算交易的唯一识别符:一堆东西的hashbytes32 txHash = getTxHash(target, value, signature, data, executeTime);// 将交易添加到队列queuedTransactions[txHash] = true;emit QueueTransaction(txHash, target, value, signature, data, executeTime);return txHash;}/*** @dev 取消特定交易。** 要求:交易在时间锁队列中*/function cancelTransaction(address target, uint256 value, string memory signature, bytes memory data, uint256 executeTime) public onlyOwner{// 计算交易的唯一识别符:一堆东西的hashbytes32 txHash = getTxHash(target, value, signature, data, executeTime);// 检查:交易在时间锁队列中require(queuedTransactions[txHash], "Timelock::cancelTransaction: Transaction hasn't been queued.");// 将交易移出队列queuedTransactions[txHash] = false;emit CancelTransaction(txHash, target, value, signature, data, executeTime);}/*** @dev 执行特定交易。** 要求:* 1. 交易在时间锁队列中* 2. 达到交易的执行时间* 3. 交易没过期*/function executeTransaction(address target, uint256 value, string memory signature, bytes memory data, uint256 executeTime) public payable onlyOwner returns (bytes memory) {bytes32 txHash = getTxHash(target, value, signature, data, executeTime);// 检查:交易是否在时间锁队列中require(queuedTransactions[txHash], "Timelock::executeTransaction: Transaction hasn't been queued.");// 检查:达到交易的执行时间require(getBlockTimestamp() >= executeTime, "Timelock::executeTransaction: Transaction hasn't surpassed time lock.");// 检查:交易没过期require(getBlockTimestamp() <= executeTime + GRACE_PERIOD, "Timelock::executeTransaction: Transaction is stale.");// 将交易移出队列queuedTransactions[txHash] = false;// 获取call databytes memory callData;if (bytes(signature).length == 0) {callData = data;} else {callData = abi.encodePacked(bytes4(keccak256(bytes(signature))), data);}// 利用call执行交易(bool success, bytes memory returnData) = target.call{value: value}(callData);require(success, "Timelock::executeTransaction: Transaction execution reverted.");emit ExecuteTransaction(txHash, target, value, signature, data, executeTime);return returnData;}/*** @dev 获取当前区块链时间戳*/function getBlockTimestamp() public view returns (uint) {return block.timestamp;}/*** @dev 将一堆东西拼成交易的标识符*/function getTxHash(address target,uint value,string memory signature,bytes memory data,uint executeTime) public pure returns (bytes32) {return keccak256(abi.encode(target, value, signature, data, executeTime));}

Remix演示

1. 部署Timelock合约,锁定期设为120秒。

45-1.jpg

2. 直接调用changeAdmin()将报错。

45-2.jpg

3. 构造更改管理员的交易。

为了构造交易,我们要分别填入以下参数:
address target, uint256 value, string memory signature, bytes memory data, uint256 executeTime

  • target:因为调用的是Timelock自己的函数,填入合约地址。
  • value:不用转入ETH,这里填0
  • signaturechangeAdmin()的函数签名为:"changeAdmin(address)"
  • data:这里填要传入的参数,也就是新管理员的地址。但是要把地址填充为32字节的数据,以满足以太坊ABI编码标准。可以使用hashex网站进行参数的ABI编码。例子:
    编码前地址:0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2
    编码后地址:0x000000000000000000000000ab8483f64d9c6d1ecf9b849ae677dd3315835cb2
    
  • executeTime:先调用getBlockTimestamp()得到当前区块链时间,再在它的基础上加个150秒填入。
    45-3.jpg

4. 调用queueTransaction,将交易放入时间锁队列。

45-4.jpg

5. 在锁定期内调用executeTransaction,调用失败。

45-5.jpg

6. 在锁定期满调用executeTransaction,交易成功。

45-6.jpg

7. 查看新的admin地址。

45-7.jpg

总结

时间锁可以将智能合约的某些功能锁定一段时间,大大减少项目方rug pull和黑客攻击的机会,增加去中心化应用的安全性。它被DeFiDAO大量采用,其中包括UniswapCompound。你投资的项目有使用时间锁吗?

在这里插入图片描述

如果这份博客对大家有帮助,希望各位给作者一个免费的点赞👍作为鼓励,并评论收藏一下⭐,谢谢大家!!!
制作不易,如果大家有什么疑问或给作者的意见,欢迎评论区留言。


http://www.ppmy.cn/news/1124772.html

相关文章

IDEA新建.xml文件显示为普通文本

情况如下&#xff1a; 1. 在XML文件中添加*.xml的文件名模式 2. 在文本中&#xff0c;选中*.xml进行删除

【洛谷 P1403】[AHOI2005] 约数研究 题解(数学)

[AHOI2005] 约数研究 题目描述 科学家们在 Samuel 星球上的探险得到了丰富的能源储备&#xff0c;这使得空间站中大型计算机 Samuel II 的长时间运算成为了可能。由于在去年一年的辛苦工作取得了不错的成绩&#xff0c;小联被允许用 Samuel II 进行数学研究。 小联最近在研究…

企业如何实现设备管理数字化?企业有什么办法做到降本增效?

随着时代的发展&#xff0c;科学技术的进步以及自动化水平的不断提高&#xff0c;设备的维护保养成为日常工作中不可或缺的事项。但是&#xff0c;许多工作人员对于设备操作和保养规程的不熟悉&#xff0c;导致误操作、保养不到位或不能及时发现设备故障隐患等情况的大量出现。…

vue3 + elementPlus实现select下拉框插入确定和取消按钮。

实现思路 Select 选择器 | Element Plus 1、select方法visible-change这个方法是下拉框出现/隐藏时触发&#xff0c;当显示的时候将两个按钮插入到下拉框里面&#xff0c;是基于原生插入DOM的这种方式&#xff1b; 2、通过vue3 ref获取selectDOM&#xff0c;在获取select的p…

百度实习一面(知识图谱部门)

百度面经&#xff08;知识图谱部&#xff09;一面 1.自我介绍 介绍完了&#xff0c;打开共享&#xff0c;对着简历一点一点问 2.ffmpeg在项目中是怎么使用的 回答了ffmpeg在项目中使用的命令&#xff0c;用来干了什么 3.为什么使用toml配置&#xff0c;了解过yml配置吗&am…

xss原理分析

插入法&#xff0c;弹窗法&#xff0c;事件法 绕过HttpOnly通过找到phpinfo的方式&#xff0c;可以看到cookie

客观题:Android基础【基础题】

一. 单选题&#xff08;共6题&#xff0c;60分&#xff09; 1. (单选题, 10分)Android四层架构中&#xff0c;应用框架层使用的是什么语法&#xff1f; A. Java B. Android C. C D.C 正确答案: A Android 四层架构通常指的是 Android 应用的四个关键组件&#xff0c;包括&a…

UniAccess Agent卸载

异常场景&#xff1a; UniAccess Agent导致系统中的好多设置打不开 例如:ipv4的协议,注册表,host等等 需要进行删除,亲测有效,及多家答案平凑的 借鉴了这位大神及他里面引用的大神的内容 https://blog.csdn.net/weixin_44476410/article/details/121605455 问题描述 这个进…