本章介绍了以太坊的基础知识,包括ether的货币单位、钱包的选择与使用,以及私钥的管理。通过MetaMask钱包,用户可以进行以太币的发送和接收。同时,还介绍了如何使用Solidity编写智能合约,并通过Remix IDE进行编译和部署,最终实现与合约的交互,如向合约发送以太币和从合约提取资金。本章旨在帮助读者入门以太坊,掌握基本概念和操作,为后续深入学习打下基础。
在这一章,我们将开始探索以太坊。我们将讨论如何使用钱包、创建交易以及运行一个基础的智能合约。
以太坊的货币单位称为 ether,也被标识为 ETH 或使用符号 Ξ (来自希腊字母 Xi,看起来像一个风格化的字母 E) 或较少使用的 ♦:例如,1 ether, 1 ETH, Ξ1, 或 ♦1。
提示
使用 Unicode 字符 U+039E 表示 Ξ,U+2666 表示 ♦。
Ether 被细分为更小的单位,直至最小的可能单位,名为 wei。一个 ether 等于 1 百京 wei (1 × 10^18^, 或 1,000,000,000,000,000,000)。你可能也会听到人们将这种货币称为“以太坊”,但这是一个常见的新手错误。以太坊是一个系统;ether 是货币。
ether 的价值在以太坊内部始终表示为一个以 wei 为单位的无符号整数值。当你交易 1 ether 时,该交易将 1,000,000,000,000,000,000 wei 编码为价值。
ether 的各种面额既有使用国际单位制 (SI) 的科学名称,也有向计算机和密码学的许多伟大思想致敬的口语化名称。表 2-1 列出了各种单位、它们的口语化(常用)名称以及它们的 SI 名称。为了与价值的内部表示保持一致,该表显示了所有以 wei 为单位的面额(第一行),其中 ether 在第七行显示为 10^18^ wei。
表 2-1. Ether 的面额和单位名称
| 价值 (以 wei 为单位) | 指数 | 常用名称 | SI 名称 |
|---|---|---|---|
| 1 | 1 | Wei | Wei |
| 1,000 | 10^3^ | Babbage | Kilowei 或 femtoether |
| 1,000,000 | 10^6^ | Lovelace | Megawei 或 picoether |
| 1,000,000,000 | 10^9^ | Shannon | Gigawei 或 nanoether |
| 1,000,000,000,000 | 10^12^ | Szabo | Microether 或 micro |
| 1,000,000,000,000,000 | 10^15^ | Finney | Milliether 或 milli |
| 1,000,000,000,000,000,000 | 10^18^ | Ether | Ether |
| 1,000,000,000,000,000,000,000 | 10^21^ | Grand | Kiloether |
| 1,000,000,000,000,000,000,000,000 | 10^24^ | Megaether |
术语 钱包 已经有了多种含义,尽管这些定义都是相关的,并且在日常生活中,它们最终几乎都归结为同一件事。我们将使用术语 钱包 来指代帮助你管理以太坊账户的软件应用程序。简而言之,以太坊钱包是你进入以太坊系统的门户。它持有你的密钥,并且可以代表你创建和广播交易。选择以太坊钱包可能很困难,因为有很多具有不同功能和设计的选项。有些更适合初学者,有些更适合专家。以太坊平台本身仍在不断改进,“最佳”钱包通常是那些适应平台升级带来的变化的钱包。
但别担心!如果你选择了一个钱包,但不喜欢它的工作方式——或者如果你一开始喜欢它,但后来想尝试其他的东西——你可以很容易地更换钱包。你所要做的就是创建一个交易,将你的资金从旧钱包发送到新钱包,或者导出你的私钥并将它们导入到新钱包中。
请记住,为了使钱包应用程序工作,它必须能够访问你的私钥,因此至关重要的是,你只从你信任的来源下载和使用钱包应用程序。幸运的是,一般来说,钱包应用程序越受欢迎,它就越值得信赖。然而,避免“把所有鸡蛋放在一个篮子里”,并将你的以太坊账户分散在几个钱包和助记词中,是一个好的做法。
以下是一些好的入门钱包;选择这些钱包并不意味着认可它们的质量或安全性。它们只是演示和测试的一个好的起点。以下所有钱包都是浏览器扩展钱包和移动钱包:
MetaMask
MetaMask 易于使用,并且便于测试,因为它能够连接到各种以太坊节点和测试区块链。
Rabby Wallet
Rabby 通常是新用户的一个不错的选择,因为它专为简单易用而设计。它内置了许多安全功能。
Phantom 是一个只能连接到以太坊以及其他非 EVM 链的钱包。
像以太坊这样的开放区块链之所以重要,是因为它们作为 去中心化 系统运行。这意味着很多事情,但一个关键方面是,以太坊的每个用户都可以——并且应该——控制自己的 私钥,私钥控制着对资金和智能合约的访问。我们有时将对资金和智能合约的访问的组合称为 账户 或 钱包。这些术语在功能上可能非常复杂,因此我们将在后面更详细地介绍这一点。然而,作为一个基本原则,它就像一个私钥等于一个“账户”一样简单。一些用户选择放弃对其私钥的控制权,而是使用第三方托管人,例如在线中心化交易所。在本书中,我们将教你如何控制和管理你自己的私钥。
伴随着控制权而来的是巨大的责任。如果你丢失了你的私钥,你将失去对你的资金和合约的访问权。没有人可以帮助你重新获得访问权——你的资金将被永远锁定。以下是一些帮助你管理这一责任的技巧:
不要临时抱佛脚。使用经过尝试和测试的标准方法。
账户越重要(例如,与你的总净资产相比,控制的资金价值越高),应采取的安全措施就越高。
最高安全级别之一来自于硬件钱包设备,但并非每个账户都需要此级别。
永远不要以纯文本形式存储你的私钥,尤其是在数字形式下。幸运的是,如今大多数用户界面甚至不会让你看到原始私钥,除非发出多个警告。
当提示你将密钥备份为助记词序列时,请使用纸和笔进行物理备份。不要将该任务“留到以后”;你会忘记的。如果你的系统上保存的所有数据丢失,或者你忘记或丢失了密码,这些备份可用于重建你的私钥。但是,攻击者也可以使用它们来获取你的私钥,因此切勿以数字方式存储它们,并且至少保留一份安全存储的物理副本。
在转移任何大量资金之前(尤其是在新地址上),首先进行一笔小额测试交易(例如,价值低于 1 美元),并等待收到确认。
创建新账户时,首先仅向新地址发送一笔小额测试交易。收到测试交易后,尝试再次从该账户发送回去。账户创建可能会出错有很多原因,如果出错,最好以小额损失来发现。如果测试有效,一切都很好(也可以使用测试网以避免任何类型的损失)。
公共区块浏览器是独立查看交易是否已被网络接受的一种简单方法;虽然此信息已在区块链上公开,但区块浏览器使访问它变得非常容易。但是,这种便利性对你的隐私有负面影响,因为你向区块浏览器公开了你的地址,区块浏览器可以跟踪你。
公共区块浏览器通常是可靠的,但并非总是如此——不要盲目信任它们。
不要将钱发送到本书中显示的任何地址。私钥已在本书中列出,并且有人可能会立即拿走这些钱。
现在我们已经介绍了一些关于密钥管理和安全性的基本最佳实践,让我们开始使用 MetaMask!
打开 Google Chrome 浏览器并导航到 Extensions。搜索“MetaMask”并点击狐狸的徽标。你应该会看到类似于图 2-1 的内容。

图 2-1. MetaMask Chrome 扩展程序的详细信息页面
验证你正在下载真正的 MetaMask 扩展程序非常重要,因为有时人们能够将恶意扩展程序偷偷地绕过 Google 的过滤器。真正的扩展程序执行以下操作:
在地址栏中显示 ID nkbihfbeogaeaoehlefnkodbefgpgknn
由 https://metamask.io 提供
拥有超过 5,400 条评论
拥有超过 1500 万用户
确认你正在查看正确的扩展程序后,点击“添加到 Chrome”进行安装。
安装 MetaMask 后,你应该会在浏览器的工具栏中看到一个新图标(狐狸的头部)。点击它以开始使用。你将被要求接受条款和条件,然后通过输入密码来创建你的新以太坊钱包(参见图 2-2)。

图 2-2. MetaMask Chrome 扩展程序的密码页面
提示
密码控制着对 MetaMask 的访问,这样任何有权访问你的浏览器的人都无法使用它。此密码仅适用于你的本地设备;如果攻击者获得对私钥或种子短语的访问权,他们将能够访问你的地址中的资金。如果攻击者拥有私钥或种子短语,则不需要密码。
设置密码后,MetaMask 将为你生成一个钱包并向你显示一个由 12 个英语单词组成的 助记词备份(参见图 2-3)。如果 MetaMask 或你的计算机出现问题,这些单词可以在任何兼容的钱包中使用,以恢复对你的资金的访问。你不需要密码进行此恢复;这 12 个单词就足够了。

图 2-3. MetaMask 创建的钱包的助记词备份
提示
将你的助记词(12 个单词)在纸上备份两次。将两个纸质备份存储在两个单独的安全位置,例如防火保险箱、锁定的抽屉或保险箱。像对待等同于你存储在以太坊钱包中的价值的现金一样对待纸质备份。任何有权访问这些单词的人都可以访问和窃取你的资金。我们将在第 5 章中更详细地介绍如何保护你的种子短语。
确认你已安全存储助记词后,你将能够看到你的以太坊账户的详细信息,如图 2-4 所示。

图 2-4. MetaMask 中的以太坊账户
注意
不要将任何资产发送到本书中显示的地址。种子短语是为教育目的而公开的,并且发送到这些地址的每个资产都可能会丢失。
你的帐户页面显示你的帐户名称(默认为“帐户 1”)、以太坊地址(在示例中为 0xaa529…f17f)以及一个彩色图标,可帮助你直观地区分此帐户与其他帐户。在帐户页面的顶部,你可以看到你当前正在使用的以太坊网络(在示例中为“主网络”)。
恭喜!你已经设置了你的第一个以太坊钱包。
正如你在 MetaMask 帐户页面上看到的那样,你可以在多个以太坊网络之间进行选择。默认情况下,MetaMask 将尝试连接到主网络。其他选择是公共测试网、你选择的任何以太坊节点或在你自己的计算机上运行私有区块链的节点(本地主机):
以太坊主网络
主要的公共以太坊区块链。真正的 ETH、真正的价值和真正的后果。
Sepolia 测试网络
Sepolia 于 2021 年 10 月由以太坊核心开发人员推出,作为一个权威证明网络,此后已过渡到 PoS 共识,镜像了以太坊的主网环境。
Holesky 测试网络
Holesky 测试网是以太坊用于质押、基础设施和协议开发的高级测试场所。
本地主机 8545
连接到与浏览器在同一台计算机上运行的节点。该节点可以是任何公共区块链(主网或测试网)或私有测试网的一部分。
自定义 RPC
允许你将 MetaMask 连接到任何具有与 Geth 兼容的远程过程调用 (RPC) 界面的节点。该节点可以是任何公共或私有区块链的一部分。
注意
你的 MetaMask 钱包在它连接的所有网络上使用相同的私钥和以太坊地址。但是,你在每个以太坊网络上的以太坊地址余额将有所不同。例如,如果你使用你的密钥在 Sepolia 测试网上发送以太币,则你在其他网络上的余额将保持不变。
你的首要任务是为你的钱包提供资金。你不会在主网络上执行此操作,因为真正的以太币需要花钱,并且处理它需要更多的经验。现在,你将使用一些测试网以太币来加载你的钱包。
通过点击左上角的以太坊图标将 MetaMask 切换到 Sepolia 测试网络;切换选项“显示测试网络”并点击 Sepolia,如图 2-5 所示。

图 2-5. MetaMask 网络
点击购买,然后导航到此列表中的其中一个水龙头。一旦你决定要使用哪个水龙头——它们几乎都是等效的——你就可以在测试网络上请求 ethers,如图 2-6 所示。

图 2-6. MetaMask Sepolia 测试水龙头
请求测试网 ether 的交易 ID 如下所示:
0x471273d9417e98e7f1adaae61e53a353b2d2313de2e71fc4b6184bf5a63fa0ae
只需几秒钟,Sepolia 网络就会处理新的交易,你的 MetaMask 钱包将显示 0.05 ETH 的余额(这取决于水龙头愿意发送多少以太币)。现在,点击浏览器扩展程序中的第一笔交易,然后点击“在区块浏览器上查看”,如图 2-7 所示。这将导航到一个 区块浏览器,这是一个允许你可视化和探索区块、地址和交易的网站。

图 2-7. 从 MetaMask 查看的交易
MetaMask 使用 Etherscan 区块浏览器,它是更流行的以太坊区块浏览器之一。包含来自 Sepolia 测试水龙头的付款的交易如图 2-8 所示。

图 2-8. Etherscan Sepolia 区块浏览器
该交易已记录在 Sepolia 区块链上,并且任何人都可以随时通过搜索交易 ID 来查看它。尝试将交易哈希输入到 sepolia.etherscan.io 网站 中,亲自查看:
0x471273d9417e98e7f1adaae61e53a353b2d2313de2e71fc4b6184bf5a63fa0ae
一旦你从 Sepolia 测试水龙头收到了你的第一个测试 ether,你就可以通过尝试将其发送回水龙头或任何其他地址来试验发送 ether。在此示例中,我们将尝试将一些测试网 ether 发送到 Vitalik Buterin,如图 2-9 所示。

图 2-9. 将 0.05 ether 发送到一个地址
哎呀!你可能注意到你无法完成交易——MetaMask 说你的余额不足。乍一看,这似乎令人困惑:你有 0.05 ETH,你想发送 0.05 ETH,那么为什么 MetaMask 说你的资金不足?
答案是因为 gas 的成本。每笔以太坊交易都需要支付费用,该费用由网络收取以验证交易。以太坊中的费用以一种称为 gas 的虚拟货币收取。你使用 ether 作为交易的一部分来支付 gas 费用。
注意
在测试网络上也需要付费。如果没有费用,测试网络的行为将与主网络不同,从而使其成为一个不足的测试平台。费用还可以保护测试网络免受 DoS 攻击和构造不良的合约(例如,无限循环)的攻击,就像它们保护主网络一样。
当你发送交易时,MetaMask 将计算最近成功交易的平均 gas 价格——例如,在 3 gwei 时,gwei 代表 gigawei。正如我们在“Ether 货币单位”中讨论的那样,Wei 是以太币的最小细分。gas 限制设置为发送基本交易的成本:21,000 个 gas 单位,这是可用于发送交易的最小 gas 量。因此,你将花费的最大 ETH 量为 3 × 21,000 gwei = 63,000 gwei = 0.000063 ETH。(请注意,平均 gas 价格可能会波动。我们将在后面的章节中看到如何增加或减少你的 gas 限制,以确保你的交易在需要时优先处理。)
所有这些都意味着进行 0.05 ETH 交易的成本为 0.050063 ETH。单击拒绝以取消此交易。让我们再试一次,这次发送 0.01 ETH。
到目前为止,你已经成为使用 MetaMask 发送和接收测试以太币的专家。你的钱包已经收到并发送了付款。你可以使用 sepolia.etherscan.io 区块浏览器查看所有这些交易。你可以复制你的钱包地址并将其粘贴到区块浏览器的搜索框中,也可以让 MetaMask 为你打开页面。在 MetaMask 中你的帐户图标旁边,你将看到一个显示三个点的按钮。单击它以显示与帐户相关的选项菜单(参见图 2-10)。

图 2-10. MetaMask 帐户上下文菜单
提示
MetaMask 的默认设置不是非常以隐私为中心。建议仔细分析“设置”→“安全和隐私”中的设置。熟悉 MetaMask 的工作方式后,还建议将以太坊主网络从默认网络更改为使用具有适合您需求的隐私设置的 RPC 的网络。最私有的解决方案是拥有自己的带有可以连接到的 RPC 的节点;我们将在第 3 章中看到如何执行此操作。
选择“在 Etherscan 上查看帐户”以在区块浏览器中打开一个网页,显示你的帐户的交易历史记录,如图 2-11 所示。

图 2-11. Etherscan 上的地址交易历史记录
在这里,你可以看到你的以太坊地址的整个交易历史记录。它显示了 Sepolia 区块链上记录的所有交易,其中你的地址是发送方或接收方。点击其中一些交易以查看更多详细信息。
警告
请注意,存在一种已知的攻击,称为 地址中毒,它可以在区块浏览器上显示带有欺骗地址的交易。区块浏览器应该用于快速检查,但显示的信息可能不准确。
你可以浏览任何地址的交易历史记录。查看 Sepolia 测试水龙头地址的交易历史记录(提示:它是列在发送到你的地址的最旧付款中的“发送方”地址)。你可以看到从水龙头发送给你的和发送给其他地址的所有测试以太币。你看到的每笔交易都可以将你引向更多的地址和更多的交易。不久之后,你就会迷失在相互连接的数据迷宫中。公共区块链包含大量的信息,所有这些信息都可以通过编程方式进行探索,正如我们将在以后的示例中看到的那样。
你现在已经创建了一个钱包并发送和接收了以太币。到目前为止,我们将以太坊视为一种加密货币。但以太坊远不止于此。事实上,加密货币功能是从属于以太坊作为去中心化世界计算机的功能的。以太币旨在用于支付运行 智能合约 的费用,智能合约是在一个名为 EVM 的模拟计算机上运行的计算机程序。
EVM 是一个全局单例,这意味着它的运行方式就像一个全局单实例计算机,在任何地方都在运行。以太坊网络上的每个节点都运行 EVM 的本地副本,以验证合约的执行,而以太坊区块链记录了这个世界计算机在处理交易和智能合约时不断变化的 状态。我们将在第 14 章中更详细地讨论这个问题。
你在 MetaMask 钱包中创建的帐户类型称为 外部拥有帐户 (EOA)。EOA 是那些拥有私钥的帐户;拥有私钥意味着控制对资金或合约的访问。
你可能在猜测还有另一种帐户类型。另一种帐户类型是 合约帐户。合约帐户具有智能合约代码,这是简单的 EOA 无法拥有的。此外,合约帐户没有私钥。相反,它由其智能合约代码的逻辑拥有(和控制):该软件程序记录在以太坊区块链上,在合约帐户创建时由 EVM 执行。
合约具有地址,就像 EOA 一样。合约也可以发送和接收以太币,就像 EOA 一样。但是,当交易目的地是合约地址时,它会导致该合约在 EVM 中 运行,使用交易——以及交易的数据——作为其输入。除了以太币之外,交易还可以包含 数据,指示要运行合约中的哪个特定函数以及要将哪些参数传递给该函数。通过这种方式,交易可以 调用 合约中的函数。
请注意,由于合约帐户没有私钥,因此它不能 发起 交易。只有 EOA 可以发起交易,但是合约可以通过调用其他合约来 响应 交易,从而构建复杂的执行路径。
在接下来的几节中,我们将编写我们的第一个合约。然后,你将学习如何使用你的 MetaMask 钱包和 Sepolia 测试网络上的测试以太币来创建、资助和使用该合约。
以太坊有几种不同的高级语言,所有这些语言都可以用于编写合约和生成 EVM 字节码。你可以在第 7 章中阅读最突出和最有趣的语言。一种高级语言是智能合约编程的绝对主导选择:Solidity。Solidity 由 Gavin Wood 创建,并且已成为以太坊(及其他地区)中使用最广泛的语言。我们将使用 Solidity 编写我们的第一个合约。
对于我们的第一个示例(示例 2-1),我们将编写一个控制水龙头的合约。你已经使用水龙头在 Sepolia 测试网络上获得测试以太币。 水龙头 相对简单:它将以太币分发给任何请求的地址,并且可以重新填充。
pragma solidity 0.8.26;
// SPDX-License-Identifier: GPL-3.0
// 我们的第一个合约是一个水龙头!
contract Faucet {
// 向任何提出要求的人提供 ether
function withdraw(uint256 _withdrawAmount, address payable _to) public {
// 限制提款金额
require(_withdrawAmount <= 1000000000000);
// 将金额发送到请求它的地址
_to.transfer(_withdrawAmount);
}
// 接收 Ether 的函数。msg.data 必须为空
receive() external payable {}
// 当 msg.data 不为空时调用 Fallback 函数
fallback() external payable {}
}
这是一个非常简单的合约,它几乎和我们可以做到的最简单。它也是一个 有缺陷的 合约,展示了许多不良做法和安全漏洞。我们将在后面的章节中通过检查它的许多缺陷来学习。但是现在,让我们逐行查看此合约的作用以及其工作原理。你将很快注意到 Solidity 的许多元素与现有的编程语言(例如 JavaScript、Java 或 C++)相似。
第一行是 pragma 语句:
pragma solidity 0.8.26;
通过在 Solidity 源文件的顶部包含此行,你可以确保代码使用 Solidity 编译器的 0.8.26 版本进行编译,从而确保兼容性并避免因使用不同的编译器版本而可能出现的问题。
接下来是一个注释,表明该智能合约已获得 GPL-3.0 许可的许可:
// SPDX-License-Identifier: GPL-3.0
这对于法律和合规性原因非常重要,因为它告知用户和开发人员关于他们在使用和分发代码方面的权利和义务。
注释供人类阅读,不包含在可执行的 EVM 字节码中。我们通常将它们放在我们试图解释的代码的前一行,或者有时放在同一行上。注释以两条正斜杠开头://。从第一条斜杠到该行末尾的所有内容都被视为与空行相同,并被忽略。
这也是一条注释:
// 我们的第一个合约是一个水龙头!
下一行是我们的实际合约开始的地方:
contract Faucet {
此行声明一个 contract 对象,类似于其他面向对象语言中的 class 声明。合约定义包括花括号 ({}) 之间的所有行,这些行定义一个 范围,很像花括号在许多其他编程语言中的使用方式。
接下来,我们声明 Faucet 合约的第一个函数:
function withdraw(uint256 _withdrawAmount, address payable _to) public {
该函数名为 withdraw,它接受一个名为 _withdrawAmount 的无符号整数 (uint256) 和一个名为 _to 的 address payable。它被声明为一个公共函数,这意味着它可以被其他合约调用。函数定义如下,在花括号之间。withdraw 函数的第一部分设置了提款限制:
require(_withdrawAmount <= 1000000000000);
它使用内置的 Solidity 函数 require 来测试一个前提条件:_withdrawAmount 小于或等于 1,000,000,000,000 wei,这是以太币的基本单位(参见表 2-1),相当于 0.000001 以太币。如果在调用 withdraw 函数时 withdraw_amount 大于该金额,则此处的 require 函数将导致合约执行停止并失败并出现 异常。请注意,语句需要在 Solidity 中以分号结尾。
合约的这部分是我们水龙头的主要逻辑。它通过限制提款来控制资金从合约中流出。这是一个非常简单的控制,但可以让你一窥可编程区块链的强大之处:去中心化的软件控制资金。
这里我们有合约的第一个设计缺陷。这不是一个安全缺陷,但最好始终在 require 语句中添加一条错误消息。这样,当用户的交易由于 require 语句而失败时,原因就很清楚了。
更正后的 require 语句是:
require(_withdrawAmount <= 1000000000000, "请求的金额太大,请尝试较小的金额!");
接下来是实际的提款:
_to.transfer(_withdrawAmount);
这里发生了一些有趣的事情。函数 transfer 是一个内置函数,它将以太币从当前合约转移到另一个指定的地址——在本例中为 _to 地址。transfer 函数以金额作为其唯一参数。我们传递作为几行之前声明的 withdraw 函数的参数的 _withdrawAmount 值。
这是可能的,因为 _to 地址被定义为 payable。内置函数 transfer 和 send 只能在 payable 地址上调用。这是代码中的第二个缺陷:虽然如果 EOA 调用 withdraw 函数,transfer 绝对没有问题,但如果另一个合约触发此函数,则会变得有问题。在这种情况下,交易可能会失败,因为 transfer 函数最多只能使用 2,300 个 gas,并且多次合约调用很可能超过此限制。要解决此问题,可以使用内置的 call 函数而不是 transfer 和 send。但是,需要正确处理此内置函数,以避免安全缺陷。目前,我们将内置的 transfer 函数保持原样。
紧接着的一行是右花括号,指示我们的 withdraw 函数的定义结束。
接下来,我们声明另外两个函数:
receive() external payable {}
fallback() external payable {}
这些函数是 fallback 和 receive 函数,如果在触发合约的交易中没有命名合约中声明的任何函数,或者根本没有命名任何函数,或者不包含数据,则会调用这些函数。合约可以具有这些函数,并且通常是接收以太币的函数。当 msg.data 为空时,将触发 receive 函数;当 msg.data 不为空时,将触发 fallback 函数。
在我们 fallback 函数的正下方是最后的右花括号,它关闭了合约 Faucet 的定义。就这样!
现在我们有了我们的第一个示例合约,我们需要使用 Solidity 编译器将 Solidity 代码转换为 EVM 字节码,以便它可以由区块链本身的 EVM 执行。
Solidity 编译器作为独立的可执行文件提供,作为各种框架的一部分提供,并且捆绑在 IDE 中。为了保持简单,我们将使用更流行的 IDE 之一:Remix。
使用你的 Chrome 浏览器(带有你之前安装的 MetaMask 钱包)导航到 Remix IDE。
当你第一次加载 Remix 时,它将从一个名为 Storage.sol 的示例合约开始。我们不需要它,所以点击选项卡角上的 x 将其关闭,如图 2-12 所示。

图 2-12. 关闭默认示例标签
现在,创建一个新文件,如图 2-13 所示。将新文件命名为 Faucet.sol。

图 2-13. 创建一个新合约
打开新标签后,复制并将代码从我们的示例 Faucet.sol 粘贴进去,如图 2-14 所示。

图 2-14. 将 Faucet 示例代码复制到新合约中
将 Faucet.sol 合约加载到 Remix IDE 后,导航到 Remix 的编译部分并点击 编译 Faucet.sol。如果一切顺利,你将看到一个绿色框(参见图 2-15)。

图 2-15. Remix 成功编译 Faucet.sol 合约
如果出现问题,最可能的问题是 Remix IDE 使用的 Solidity 编译器版本与 0.8.26 不同。在这种情况下,我们的 pragma 指令将阻止 Faucet.sol 编译。要更改编译器版本,请转到“编译器”选项卡,将版本设置为 0.8.26,然后重试。
Solidity 编译器现在已将我们的 Faucet.sol 编译为 EVM 字节码。如果你好奇,字节码如下所示:
6080604052348015600e575f80fd5b506101af8061001c5f395ff3fe608060405260043610610020575f3560
e01c8062f714ce1461002957610027565b3661002757005b005b348015610034575f80fd5b5061004f600480
360381019061004a919061013b565b610051565b005b64e8d4a51000821115610062575f80fd5b8073ffffff
ffffffffffffffffffffffffffffffffff166108fc8390811502906040515f60405180830381858888f19350
5050501580156100a5573d5f803e3d5ffd5b505050565b5f80fd5b5f819050919050565b6100c0816100ae56
5b81146100ca575f80fd5b50565b5f813590506100db816100b7565b92915050565b5f73ffffffffffffffff
ffffffffffffffffffffffff82169050919050565b5f61010a826100e1565b9050919050565b61011a816101
00565b8114610124575f80fd5b50565b5f8135905061013581610111565b92915050565b5f80604083850312
15610151576101506100aa565b5b5f61015e858286016100cd565b925050602061016f85828601610127565b
915050925092905056fea26469706673582212207de2f4d88c747c9332dceef5dcd739f3380ec8a8c2167a29
2ba64ee24fa32a8a64736f6c634300081a0033
你是否很高兴你使用像 Solidity 这样的高级语言而不是直接用 EVM 字节码进行编程?我们也是!Remix 将构建特殊的“创建”交易,MetaMask 会要求你批准它,如图 2-17 所示。你会注意到合约创建交易中没有以太币,但它有一些数据字节(已编译的合约),并且会消耗一些 Gwei 的 gas。单击“提交”以批准它。

图 2-17. MetaMask 显示合约创建交易
现在你必须等待。合约在 Sepolia 上处理大约需要 15-30 秒。Remix 似乎没有做什么,但请耐心等待。
合约创建完成后,它会出现在“运行”选项卡的底部(参见图 2-18)。

图 2-18. Faucet 合约已启动!
请注意,Faucet 合约现在有自己的地址:Remix 将其显示为“Faucet at 0x4E7…6EA46”(虽然你的地址——随机字母和数字——会有所不同)。
让我们回顾一下到目前为止所学的内容。以太坊合约是控制资金的程序,它在名为 EVM 的虚拟机中运行。它们由一个特殊的交易创建,该交易提交它们的字节码以记录在区块链上。一旦它们在区块链上创建,它们就拥有一个以太坊地址,就像钱包一样。任何时候有人向合约地址发送交易,都会导致合约在 EVM 中运行,并将该交易作为其输入。发送到合约地址的交易可能包含以太币或数据,或两者都包含。如果它们包含以太币,则将其“存入”合约余额。如果它们包含数据,则数据可以指定合约中的命名函数并调用它,并将参数传递给该函数。
我们现在有一个记录在区块链上的合约,我们可以看到它有一个以太坊地址。让我们在 sepolia.etherscan.io 区块浏览器 中查看它,看看合约是什么样子的。在 Remix IDE 中,通过单击其名称旁边的图标来复制合约的地址(参见图 2-19)。

图 2-19. 从 Remix 复制合约地址
保持 Remix 处于打开状态;我们稍后会回到它。现在,在浏览器中导航到 sepolia.etherscan.io 并将地址粘贴到搜索框中。你应该看到合约的以太坊地址历史记录,如图 2-20 所示。

图 2-20. 在 Etherscan 区块浏览器中查看 Faucet 合约地址
目前,合约的历史记录中只有一个交易:合约创建交易。正如你所看到的,合约也没有以太币(零余额)。那是因为我们没有在创建交易中向合约发送任何以太币,即使我们可以发送。
我们的 faucet 需要资金!我们的第一个项目是使用 MetaMask 向合约发送以太币。你的剪贴板中应该仍然有合约的地址(如果没有,请再次从 Remix 复制它)。打开 MetaMask 并向其发送 0.01 以太币,就像你向任何其他以太坊地址发送一样(参见图 2-21)。

图 2-21. 向合约地址发送 0.01 以太币
稍等片刻,如果你重新加载 Etherscan 区块浏览器,它将显示到合约地址的另一个交易和 0.01 以太币的更新余额。
还记得我们的 Faucet.sol 代码中的 receive 函数吗?它看起来像这样:
receive() external payable {}
当你向合约地址发送交易,而没有指定要调用哪个函数的数据时,它会调用此 receive 函数。你的交易导致合约在 EVM 中运行,更新其余额。你已经资助了你的 faucet!
接下来,让我们从 faucet 中提取一些资金。要提取资金,我们必须构建一个调用 withdraw 函数的交易,并将一个 _withdrawAmount 和一个 _to 参数传递给它。为了现在使事情简单,Remix 将为我们构建该交易,MetaMask 将提交它以供我们批准。
返回到 Remix 选项卡,查看“运行”选项卡上的合约。你应该看到一个标有“withdraw”的红色框,其中有一个标有“uint256 _withdrawAmount, address _to”的字段条目(参见图 2-22)。

图 2-22. Remix 中 Faucet.sol 的 withdraw 函数
这是合约的 Remix 接口。它允许我们构建调用合约中定义的函数的交易。我们将输入一个 _withdrawAmount 和一个 _to 地址,然后单击 withdraw 按钮来生成交易。
首先,让我们计算出 _withdrawAmount。我们想尝试提取 0.000001 以太币,这是我们的合约允许的最大金额。请记住,以太坊中的所有货币值在内部都以 wei 为单位,并且我们的 withdraw 函数也希望 _withdrawAmount 以 wei 为单位。我们想要的金额是 0.000001 以太币,即 1,000,000,000,000 wei(一个 1 后面跟着 12 个零)。
对于 _to 地址,我们将只使用 MetaMask 中的 Account 1。
提示
由于 JavaScript 中的一个限制,Remix 无法处理像 10^17^ 这么大的数字。相反,我们将它用引号括起来,以允许 Remix 将它作为字符串接收并将其作为
BigNumber进行操作。如果我们不用引号将其括起来,Remix IDE 将无法处理它并显示“Error encoding arguments: Error: Assertion failed.”
将 "1000000000000"(带引号)输入到 _withdrawAmount 框中,从 MetaMask 复制粘贴你的 Account 1 地址,然后单击 transact 按钮。(你可能会看到它是 withdraw 按钮。图 2-23 显示了该函数的展开视图;如果你的视图未展开,则该按钮将被称为“withdraw”。)

图 2-23. 在 Remix 中单击 transact 以创建提款交易
MetaMask 将弹出一个交易窗口供你批准。单击“提交”以将你的提款调用发送到合约(参见图 2-24)。

图 2-24. MetaMask 交易调用 withdraw 函数
等待一分钟,然后重新加载 Etherscan 区块浏览器,以在 Faucet 合约地址历史记录中看到该交易(参见图 2-25)。

图 2-25. Etherscan 显示调用 withdraw 函数的交易
我们现在看到一个新交易,其中合约地址为目的地,值为 0 以太币。合约余额已更改,现在为 0.009999 以太币,因为它按请求向我们发送了 0.000001 以太币。
但是我们在合约地址历史记录中没有看到“OUT”交易。外发提款在哪里?合约的地址历史记录页面上出现了一个名为“Internal Transactions”的新选项卡。由于 0.000001 以太币的转移源自合约代码,因此它是一个内部交易(也称为消息)。单击该选项卡以查看它(参见图 2-26)。
此“内部交易”由合约在此行代码中发送(来自 Faucet.sol 中的 withdraw 函数):
_to.transfer(_withdrawAmount);

图 2-26. Etherscan 显示将以太币从合约中转出的内部交易
回顾一下:你从你的 MetaMask 钱包发送了一个交易,其中包含调用 withdraw 函数的数据指令,其中 _withdrawAmount 参数为 0.000001 以太币和一个地址。该交易导致合约在 EVM 中运行。当 EVM 运行 Faucet 合约的 withdraw 函数时,它首先调用 require 函数并验证请求的金额小于或等于允许的最大提款额 0.000001 以太币。然后,它调用 transfer 函数向你发送以太币。运行 transfer 函数生成一个内部交易,该交易从合约余额中将 0.000001 以太币存入你的钱包地址。这就是 Etherscan 中“Internal Transactions”选项卡上显示的交易。
在本章中,你使用 MetaMask 设置了一个钱包,并使用 Sepolia 测试网络上的 faucet 为其提供资金。你将以太币接收到你的钱包的以太坊地址中,然后你将以太币发送到另一个地址。
接下来,你用 Solidity 编写了一个 Faucet 合约。你使用 Remix IDE 将合约编译成 EVM 字节码,然后使用 Remix 形成一个交易并在 Sepolia 区块链上创建了 Faucet 合约。创建后,Faucet 合约有了一个以太坊地址,你向它发送了一些以太币。最后,你构建了一个交易来调用 withdraw 函数并成功请求了 0.000001 以太币。合约检查了请求并通过内部交易向你发送了 0.000001 以太币。
这看起来可能不多,但你刚刚成功地与在去中心化世界计算机上控制资金的软件进行了交互。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!