开发智能合约 - OpenZeppelin 文档

本文介绍了如何使用 Hardhat 设置 Solidity 项目,编译 Solidity 源代码,添加更多合约,以及如何使用 OpenZeppelin Contracts。内容涵盖了Solidity 语言的基础知识,并提供了以太坊和智能合约的工作原理,包括使用Hardhat进行智能合约的开发、测试和部署。

开发智能合约

欢迎来到激动人心的的智能合约开发世界!本指南将通过以下内容让你开始编写Solidity合约:

关于Solidity

本指南不会涵盖诸如语法或关键字之类的语言概念。为此,你需要查看以下精选内容,其中包含适用于新手和经验丰富的开发人员的优秀学习资源:

  • 为了全面了解以太坊和智能合约的工作方式,官方网站有一个了解以太坊部分,其中包含大量适合初学者的内容。

  • 如果你是这门语言的新手,官方Solidity文档是一个很好的参考资源。查看他们的安全建议,其中很好地介绍了区块链和传统软件平台之间的区别。

  • Consensys的最佳实践非常广泛,包括可以学习的经过验证的模式和需要避免的已知陷阱

  • Ethernaut基于Web的游戏将让你在智能合约中寻找细微的漏洞,随着你通过难度越来越大的关卡。

说完这些,让我们开始吧!

设置一个项目

创建一个项目后的第一步是安装开发工具。

以太坊最流行的开发框架是HardhatFoundry。 每个都有自己的优势,并且熟练使用所有这些工具都很有用。

在这些指南中,我们将展示如何使用Hardhat开发、测试和部署智能合约,并且我们将介绍它与ethers.js最常见的用法。

要开始使用Hardhat,我们将其安装在我们的项目目录中。

$ npm install --save-dev hardhat

安装完成后,我们可以运行 npx hardhat。 这将在我们的项目目录中创建一个 Hardhat 配置文件(hardhat.config.js)。

$ npx hardhat
888    888                      888 888               888
888    888                      888 888               888
888    888                      888 888               888
8888888888  8888b.  888d888 .d88888 88888b.   8888b.  888888
888    888     "88b 888P"  d88" 888 888 "88b     "88b 888
888    888 .d888888 888    888  888 888  888 .d888888 888
888    888 888  888 888    Y88b 888 888  888 888  888 Y88b.
888    888 "Y888888 888     "Y88888 888  888 "Y888888  "Y888

👷 Welcome to Hardhat v2.22.12 👷‍

✔ What do you want to do? · Create an empty hardhat.config.js
配置文件已创建

第一个合约

我们将Solidity源文件(.sol)存储在contracts目录中。 这相当于你可能从其他语言中熟悉的src目录。

我们现在可以编写我们的第一个简单的智能合约,称为Box:它将允许人们存储一个可以稍后检索的值。

我们将此文件另存为contracts/Box.sol。 每个.sol文件都应包含单个合约的代码,并以其命名。

// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Box {
    uint256 private _value;

    // Emitted when the stored value changes
    // 当存储的值更改时发出
    event ValueChanged(uint256 value);

    // Stores a new value in the contract
    // 在合约中存储一个新值
    function store(uint256 value) public {
        _value = value;
        emit ValueChanged(value);
    }

    // Reads the last stored value
    // 读取最后存储的值
    function retrieve() public view returns (uint256) {
        return _value;
    }
}

编译Solidity

以太坊虚拟机(EVM)无法直接执行Solidity代码:我们首先需要将其编译为EVM字节码。

我们的 Box.sol 合约使用 Solidity 0.8,因此我们需要首先配置 Hardhat 以使用适当的 solc 版本

我们在 hardhat.config.js 中指定一个 Solidity 0.8 solc 版本。

// hardhat.config.js

/**
 * @type import('hardhat/config').HardhatUserConfig
 */
 module.exports = {
  solidity: "0.8.24",
};

然后可以通过运行单个编译命令来实现编译:

如果你不熟悉 npx 命令,请查看我们的Node 项目设置指南
$ npx hardhat compile
Compiled 1 Solidity file successfully (evm target: paris).
成功编译 1 个 Solidity 文件(EVM 目标:巴黎)。

compile 内置任务将自动查找contracts目录中的所有合约,并使用Solidity编译器使用hardhat.config.js中的配置来编译它们。

你会注意到创建了一个artifacts目录:它保存了已编译的artifacts(字节码和元数据),这些是.json文件。 最好将此目录添加到你的.gitignore中。

添加更多合约

随着项目的增长,你将开始创建更多相互交互的合约:每个合约都应存储在其自己的 .sol 文件中。

要了解它的外观,让我们向我们的 Box 合约添加一个简单的访问控制系统:我们将在一个名为 Auth 的合约中存储一个管理员地址,并且只允许 BoxAuth 允许的那些帐户使用。

因为编译器会拾取contracts目录和子目录中的所有文件,所以你可以随意组织你的代码。 在这里,我们将 Auth 合约存储在 access-control 子目录中:

// contracts/access-control/Auth.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Auth {
    address private _administrator;

    constructor(address deployer) {
        // Make the deployer of the contract the administrator
        // 使合约的部署者成为管理员
        _administrator = deployer;
    }

    function isAdministrator(address user) public view returns (bool) {
        return user == _administrator;
    }
}

要从Box中使用此合约,我们使用import语句,通过其相对路径引用Auth

// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Import Auth from the access-control subdirectory
// 从access-control子目录导入Auth
import "./access-control/Auth.sol";

contract Box {
    uint256 private _value;
    Auth private _auth;

    event ValueChanged(uint256 value);

    constructor() {
        _auth = new Auth(msg.sender);
    }

    function store(uint256 value) public {
        // Require that the caller is registered as an administrator in Auth
        // 要求调用者在Auth中注册为管理员
        require(_auth.isAdministrator(msg.sender), "Unauthorized");

        _value = value;
        emit ValueChanged(value);
    }

    function retrieve() public view returns (uint256) {
        return _value;
    }
}

跨多个合约分离关注点是保持每个合约简单的好方法,并且通常是一个好的做法。

但是,这并不是将代码拆分为模块的唯一方法。 你还可以在Solidity中使用继承来进行封装和代码重用,正如我们接下来将看到的。

使用OpenZeppelin合约

可重用的模块和库是优秀软件的基石。OpenZeppelin Contracts包含许多有用的构建块,用于构建智能合约。 你可以放心地构建它们:它们已经过多次审计,其安全性和正确性经过了实战测试。

关于继承

库中的许多合约不是独立的,也就是说,你不应该按原样部署它们。 相反,你将使用它们作为起点,通过向其中添加功能来构建你自己的合约。 Solidity提供多重继承作为实现此目的的一种机制:有关更多详细信息,请查看Solidity文档

例如,Ownable合约将部署者帐户标记为合约的所有者,并提供一个名为onlyOwner的修饰符。 当应用于函数时,onlyOwner将导致所有不是来自所有者帐户的函数调用都恢复。 用于转移放弃所有权的函数也可用。

以这种方式使用时,继承成为一种强大的机制,允许模块化,而无需你部署和管理多个合约。

导入OpenZeppelin合约

可以通过运行以下命令下载OpenZeppelin Contracts库的最新发布版本:

$ npm install @openzeppelin/contracts
你应该始终使用这些已发布版本中的库:将库源代码复制粘贴到你的项目中是一种危险的做法,很容易在你的合约中引入安全漏洞。

要使用其中一个OpenZeppelin合约,请使用@openzeppelin/contracts作为其路径的前缀来import它。 例如,为了替换我们自己的Auth合约,我们将导入@openzeppelin/contracts/access/Ownable.sol以将访问控制添加到Box

// contracts/Box.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// Import Ownable from the OpenZeppelin Contracts library
// 从OpenZeppelin Contracts库导入Ownable
import "@openzeppelin/contracts/access/Ownable.sol";

// Make Box inherit from the Ownable contract
// 使Box继承自Ownable合约
contract Box is Ownable {
    uint256 private _value;

    event ValueChanged(uint256 value);

    constructor() Ownable(msg.sender) {}

    // The onlyOwner modifier restricts who can call the store function
    // onlyOwner修饰符限制了谁可以调用store函数
    function store(uint256 value) public onlyOwner {
        _value = value;
        emit ValueChanged(value);
    }

    function retrieve() public view returns (uint256) {
        return _value;
    }
}

OpenZeppelin Contracts文档是学习开发安全智能合约系统的好地方。 它包含指南和详细的API参考:例如,请参阅访问控制指南,以了解有关上述代码示例中使用的Ownable合约的更多信息。

下一步

编写和编译Solidity合约只是在以太坊网络上运行去中心化应用程序的第一步。 一旦你对此设置感到满意,你将需要继续执行更高级的任务:

← 设置一个Node项目

部署和交互 →

  • 原文链接: docs.openzeppelin.com/le...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
OpenZeppelin
OpenZeppelin
江湖只有他的大名,没有他的介绍。