全面掌握Solidity智能合约开发

2024年09月25日更新 796 人订阅
原价: ¥ 46 限时优惠
专栏简介 跟我学 Solidity :开发环境 跟我学 Solidity:关于变量 跟我学 Solidity : 变量的存储 跟我学 Solidity :引用变量 跟我学 Solidity :函数 跟我学 Solidity :合约的创建和继承 跟我学 Solidity :工厂模式 用Web3.js构建第一个Dapp 跟我学Solidity:事件 Solidity 中 immutable (不可变量)与constant(常量) [译] Solidity 0.6.x更新:继承 解析 Solidity 0.6 新引入的 try/catch 特性 探究新的 Solidity 0.8 版本 探索以太坊合约委托调用(DelegateCall) 停止使用Solidity的transfer() 使用工厂提高智能合约安全性 Solidity 怎样写出最节省Gas的智能合约[译] Solidity 优化 - 编写 O(1) 复杂度的可迭代映射 Solidity 优化 - 控制 gas 成本 Solidity 优化 - 减少智能合约的 gas 消耗的8种方法 Solidity 优化 - 如何维护排序列表 Solidity 优化:打包变量优化 gas 使用 Solidity 瞬态存储操作码 在 Solidity中使用值数组以降低 gas 消耗 Gas 优化:Solidity 中的使用动态值数组 计算Solidity 函数的Gas 消耗 Solidity 技巧:如何减少字节码大小及节省 gas 一些简单的 Gas 优化基础 "Stack Too Deep(堆栈太深)" 解决方案 智能合约Gas 优化的几个技术 合约实践:避免区块Gas限制导致问题 如何缩减合约以规避合约大小限制 Solidity 类特性 无需gas代币和ERC20-Permit还任重而道远 智能合约实现白名单的3个机制 Solidity智能合约安全:防止重入攻击的4种方法 Solidity 十大常见安全问题 [译]更好Solidity合约调试工具: console.log 智能合约开发的最佳实践 - 强烈推荐 全面理解智能合约升级 Solidity可升级代理模式: 透明代理与UUPS代理 使用OpenZeppelin编写可升级的智能合约 实战:调整NFT智能合约,减少70%的铸币Gas成本 Solidity 优化 - 隐藏的 Gas 成本 Gas 技巧:Solidity 中利用位图大幅节省Gas费 Solidity Gas 优化 - 理解不同变量 Gas 差异 关于Solidity 事件,我希望早一点了解到这些 Solidity 编码规范推荐标准 深入了解 Solidity bytes OpenZeppelin Contracts 5.0 版本发布 Solidity Gas优化:高效的智能合约策略 智能合约安全的新最低测试标准:Fuzz / Invariant Test 智能合约的白名单技术 模糊测试利器 - Echidna 简介 智能合约设计模式:代理 离线授权 NFT EIP-4494:ERC721 -Permit

使用工厂提高智能合约安全性

使用工厂模式的利与弊

智能合约可以部署其他智能合约,通常称为工厂模式,让你不是创建一个合约跟踪很多事情,而是创建多个智能合约,每个合约只跟踪各个的事情。 使用这种模式可以简化合约代码,减少某些类型的安全漏洞的影响。

在这篇文章中,我将带你了解一个例子,这个例子是基于最近的一次审计中发现的一个关键漏洞修改而来。 如果使用了工厂模式,这个漏洞就不会那么严重了。

一个错误的智能合约

下面是一个智能合约,通过一个相当简单的接口来出售 WETH。 如果你有WETH,你只需要 approve(授权)这个智能合约来出售你的代币,它将确保你得到正确的金额。 只要批准了足够的代币,任何人都可以向你购买WETH 。

合约采用提现模式向卖家交付出售所得的ETH,但合约作者却犯了严重错误,代码如下:

 // 技术上可以实现出售任何代币,但这个例子仅出售  WETH 。
  // 因为这里不想关注价格. 1 WETH = 1 ETH.
 contract WETHMarket {
     IERC20 public weth;
     mapping(address => uint256) public balanceOf;

     constructor(IERC20 _weth) public {
         weth = _weth;
     }

    // 从指定的seller购买 WETH . seller 需要先授权 WETH.
    function buyFrom(address seller) external payable {
        balanceOf[seller] += msg.value;
        require(weth.transferFrom(seller, msg.sender, msg.value),
            "WETH transfer failed.");
    }

    // 出售者调用,提取ETH
    function withdraw(uint256 amount) external {
        require(amount <= balanceOf[msg.sender], "Insufficient funds.");

        // Whoops! Forgot this:
        // balanceOf[msg.sender] -= amount;

        (bool success, ) = msg.sender.call.value(amount)("");
        require(success, "ETH transfer failed.");
    }
}

如果你想知道为什么代码使用.call而不是.transfer,请阅读停止使用transfer())。

由于卖方的余额永远不会减少,所以,一...

剩余50%的内容订阅专栏后可查看

点赞 4
收藏 4
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

1 条评论

请先 登录 后评论