# 「入门科普 」初涉 Solidity：安全、Gas 优化以及创建众筹平台

By [BTX ｜ Research](https://paragraph.com/@btx-research) · 2022-07-30

---

原文作者：0xRusowsky 编译：BTX Capital

导读：本文分析了ETH 的三种转移方式：send、transfer、call，三者在交易费优化和安全方面的区别，以及索引和非索引事件的交易费比较。此外，本文还手把手教大家如何创建一个众筹平台。

由于有很多公开的优秀在线资源，因此，我不会解释所有的基本概念，而是尝试解释一些值得分享的有趣事物（即安全性和gas优化技巧），并在尝试解决一些练习时回顾一下我的思考过程。

提示 三种转移方式：send、transfer 和 call 尽管可以使用这 3 种方法来转移以太坊，但它们具有值得了解的关键区别。send()和transfer()曾经被推荐使用，因为它们会将 gas 支出限制在 2300 gwei。利用这个数量的gas，人们可以进行一些次要的 fallback 操作，比如发出事件，甚至更新存储，但这还不足以重入合约。然而，这从来都不是避免重入攻击的好方法，因为 gas 成本会随着协议更新而变化（即伊斯坦布尔分叉增加了SLOD操作码的 gas 成本）。 因此，建议使用低级功能call()，默认转发所有可用的gas。然后，你可以使用 Reentrancy Guard 或 Checks-Effects-Interactions 模式 来保护你的函数。

### 索引事件参数与非索引（常规）

具有索引参数的事件更容易检索，因为它们在世界状态（在logsBloom中）中被特别索引。因此，它们比只有常规参数的事件稍微贵一些。

这个解释可以通过这个简单的 Foundry 示例来确认：

![索引事件和非索引事件之间的 gas 费比较。](https://storage.googleapis.com/papyrus_images/d0e7d001ea3fdf9c59d74d3fbbc60626f54b2a9abb4d50211a400540c5505141.png)

索引事件和非索引事件之间的 gas 费比较。

注意：日志由主题（最多 4 个）和数据组成。其中一个主题为事件签名保留，因此你最多可以有 3 个索引参数。 在以太坊黄皮书中，可以断言每个主题花费 375 gwei，数据中的每个字节花费 8gwei。

![以太坊黄皮书中定义的事件 gas 成本](https://storage.googleapis.com/papyrus_images/58ad2681198440a69bd87062fcc95e44e120fa7abe9184ba05ec4a7cd1da1b8d.png)

以太坊黄皮书中定义的事件 gas 成本

### 任务：创建一个基本的众筹平台

搭建一个符合以下要求的简单众筹平台的主干：

*   任何人都可以创建一个活动（Campaign）来为其项目获取资金。
    
*   每个活动至少必须拥有：
    
    *   名字
        
    *   所有者
        
    *   活动类型（初创公司或慈善机构）。
        
    *   筹资目标
        
    *   时间限制，不能超过 60 天
        
*   上述所有属性都必须在活动创建时定义，并且无法被更新。
    
*   在达到给定活动的时间限制之前，任何人都可以通过发送以太坊来资助它。达到时限后，便无法再接收资金。
    
*   活动的所有者只有在达到时限后才能提取所筹集的以太坊。
    
*   所有者提取资金后，应将活动标记为完全资助 FullyFunded（如果筹得资金 >= 资金目标）或部分资助 PartiallyFunded（如果筹得资金 < 资金目标）。
    
*   所有者必须能够取消活动。如果发生这种情况，该活动将无法再收到以太坊。
    
*   实施所有相关的事件。
    

### 解决方案设计

当有一个想法时，你首先需要弄清楚的是解决方案应该具有的架构设计。在我看来，最合理的做法是为每个活动制定一个独立的合约，这样所有者就可以直接与之互动并拥有完全的所有权。因此，我决定创建一个工厂合约 CampaignFactory 和一个名为 Campaign 的活动合约。

![工厂合约的运作模式](https://storage.googleapis.com/papyrus_images/730dd5a24817e7da991c0bee26460e1e1fbfa502ce6a7c02dcb67f458a4527e1.png)

工厂合约的运作模式

鉴于上述的架构，我首先创建了 Campaign 合约，确保它符合所有给定的要求。

你可以在此 GitHub gist中查看完整的脚本[https://gist.github.com/0xRusowsky/5b583aeff7e387fa00652a9b079c34ad](https://gist.github.com/0xRusowsky/5b583aeff7e387fa00652a9b079c34ad)

首先，我们需要定义变量以及可能需要的任何 枚举 enum 或 结构 structs。

![注意 owner 必须是一个 payable address，因为它将具有提取资金的能力。](https://storage.googleapis.com/papyrus_images/432ae2470711739db2864828681866fc359c3776f7e98e78bceca5831709146d.png)

注意 owner 必须是一个 payable address，因为它将具有提取资金的能力。

一旦我们设置了所有变量，我们就可以创建合约构造函数。在这种情况下，构造函数将使用 require() 函数来确保截止日期小于 60 天。

由于在 solidity 中的时间戳是 unix 格式（从1970 年1 月1 日开始以表计算）中表示的，因此构造函数\_deadline中使用的输入变量将具有相对范围（require 语句状态\_deadline <= 3600_24_60）。尽管如此，全局变量deadline将具有绝对引用，因此我们可以将它与任何给定的时间戳进行比较。

![由于 owner 是 a payable address，我们必须更改 _owner 类型以使其符合要求。](https://storage.googleapis.com/papyrus_images/250058103abcf77fe0f8b686b771baf84880d99b9a0de6edb6cc5600772303f2.png)

由于 owner 是 a payable address，我们必须更改 \_owner 类型以使其符合要求。

在对构建的合约进行编码之后，我创建了相关的事件和一些修改器，这些修改器将有助于我们在活动功能中实现所需的验证。

![事件和修饰符的实现。](https://storage.googleapis.com/papyrus_images/40de1d621e61a6a88384805833c654376549ddea8d7b813891cfceb9d0d01d34.png)

事件和修饰符的实现。

最后，我们需要实现合约功能。在这种情况下，我们只需要 4 个函数：fallback(), receive(), withdrawFunds(), cancelCampaign().

为了 fallback() 和 receive() 能够从其他合约以及 EOA 中接收以太币，我们需要使它们payable。最重要的是，我们还将添加liveCampaign修改器以确保在活动结束后不再收到捐款。

另一个值得一提的话题是如何处理提款。正如之前在提示部分中所解释的，我们在这里使用低级函数call()。

![ 执行竞选合约功能。](https://storage.googleapis.com/papyrus_images/2a2f6b149c71bc4dd3c57c8c96d0c47a312a045021961a26d85ea6145af1370d.png)

执行竞选合约功能。

至此，活动合约完成。现在，我们只需要再创建一个众筹工厂合约。

在这种情况下，工厂合约将只有一个函数，该函数将在调用时部署活动合约的新实例。最重要的是，我们还将添加一些映射以更好地处理已部署的活动。这些映射将按所有者（使用数组）跟踪已部署的活动合约，以及每个人已部署的活动数量（以导航数组）。

![执行众筹工厂合约](https://storage.googleapis.com/papyrus_images/ceeefc5aedfccd32739d172a572f14a3c530cc55888297b20929db4e9443aa1d.png)

执行众筹工厂合约

原文链接：[https://journal0xrusowsky.substack.com/p/first-interactions-with-solidity?utm\_source=twitter&sd=pf](https://journal0xrusowsky.substack.com/p/first-interactions-with-solidity?utm_source=twitter&sd=pf)

---

*Originally published on [BTX ｜ Research](https://paragraph.com/@btx-research/solidity-gas)*
