GitHub 回购:- https://github.com/PradhumnaPancholi/Figbot
嘿大家!不久前,我正在学习Dapp 工具,因为它具有用于开发和审计智能合约的出色工具。虽然我喜欢这种体验,但我很快就知道它正处于秘密发展阶段。这意味着临时/个人用户不能依赖维护者的支持和更新。
然后我偶然发现了Foundry 。它拥有 Dapp Tools 提供的一切,除了内置的符号执行(这对我来说不是问题,因为我使用Manticor e by Trail of Bits )。这是与审计相关的,因此无论如何都不会成为智能合约开发的障碍。
在与 Foundry 合作了一段时间后,我很享受这段经历,并想与他人分享。因此,这篇文章。
本文将介绍 Foundry 的好处、安装过程、开发 NFT(因为每个人都对此感兴趣)、测试合约以及使用Figment Datahub部署它。
Foundry 是用 Rust 编写的用于以太坊应用程序开发的极快、可移植和模块化的工具包。
Foundry由三个部分组成:
今天的重点将放在Forge 上。但我将在接下来的几周内发布有关 Caste and Anvil 的深入文章。
有许多智能合约开发工具,例如 Truffle、Hardhat 和 Brownie。但我首先研究 Dapp Tools 的主要原因之一是原生 Solidity 测试。在 Hardhat 和 Brownie 等框架之间切换时,编写智能合约并不难。它们是带有插件的令人难以置信的工具,但需要精通 JavaScript/TypeScript 和 Python 才能执行测试。
Foundry 允许我们在 Solidity 中本地编写测试。这可以节省大量新开发人员的入职时间,并使流程更加顺畅。根据我帮助人们进入智能合约开发的经验,我了解到初级开发人员参与 DAO/社区维护项目的最佳和最有效的方式是编写测试和了解代码库本身。我记得Scupy Trooples曾经提到他们在Bankless上开发 Alchemix Finance 时使用了相同的方法。
除此之外,内置的模糊测试、作弊码、Cast 和 Anvil 使其成为测试智能合约的可靠套件。很快就会有关于这些组件的更详细的文章。 【易集成静态分析仪】
让我们现在开始构建一个 NFT 项目。
如果你在 Mac 或 Linux 上,你需要做的就是运行两个命令:
curl -L https://foundry.paradigm.xyz | bash
foundryup
确保在运行foundryup
之前关闭终端。
瞧!你们都完成了。
对于 Windows,您需要安装 Rust,然后:
cargo install --git https://github.com/foundry-rs/foundry --locked
在本文中,我们将创建一个名为 Figbots 的简单 NFT 项目。
首先创建一个名为“Figbots”的目录。进入目录后运行forge init
。此命令将为您创建一个初始化git
的铸造项目。
让我们快速看一下文件夹结构。您有三个主要文件夹,即 src、lib 和 test。这里非常不言自明,您在src
中编写合约,在 test 中编写test
,并且lib
包含您安装的所有库,例如 OpenZeppelin。除此之外,如果您使用过这些框架,您还会获得包含所有配置的foundry.toml
,就像hardhat.config.js
和brownie-config.yaml
一样。另一个好东西是 .github,您可以在其中编写您的 Github Actions。我发现在团队中工作时它对测试非常有帮助。
让我们开始建造吧!我们将创建一个名为 Figbot 的简单 NFT,其供应量、成本(用于铸币)和提款都是有限的。通过这种方法,我们可以覆盖不同测试的边缘。首先,将Contract.sol
和test/Contract.t.sol
分别重命名为Figbot.sol
和Figbot.t.sol
。现在,如果没有 Openzeppelin,我们就无法编写智能合约,不是吗?
使用 Foundry 安装库与 Hardhat 和 Brownie 略有不同。我们没有 npm 或 pip 包。我们直接从 Foundry 的源代码(GitHub 存储库)安装库。
forge install Openzeppelin/openzeppelin-contracts
现在我们可以导入 ERC721URIStorage.sol 扩展来创建我们的 NFT。为了检查一切是否正常,我们可以运行命令forge build
,它将编译我们的项目。如果有什么问题,编译器就会对你大喊大叫。否则,您将获得成功的编译。
就像任何其他包管理器一样,Forge 允许您使用forge install <lib>,
forge remove <lib>
和forge update <lib>
来管理您的依赖项。
我们将使用 Openzeppelin 的三个合约。计数器、ERC721URIStorage 和 Ownable。是时候使用Pinata将我们的资产上传到 IPFS 了。我们使用 Ownable 合约来设置部署地址的owner
,并且可以访问onlyOwner
修饰符以只允许所有者提取资金。 Counters
帮助我们处理代币 ID 和ERC721URIStorage
,以保持 NFT 合约的简单性。
设置状态变量:
MAX_SUPPLY
至 100COST
为 0.69 以太币TOKEN_URI
到 CID,我们从 Pinata 收到使用 Counter 获取令牌 ID:
using Counters for Counters.Counter;
Counters.Counter private tokenIds;
ERC721 构造函数:
constructor() ERC721(“Figbot”, “FBT”) {}
薄荷功能:
msg.value
是否大于COST
tokenIds.current()
是否大于或等于MAX_SUPPLY
_safeMint
和_setTokenURI
提现功能:
function withdrawFunds() external onlyOwner { uint256 balance = address(this).balance; require(balance > 0, "No ether left to withdraw"); (bool success, ) = (msg.sender).call{value: balance}(""); require(success, "Withdrawal Failed"); emit Withdraw(msg.sender, balance); }
TotalSupply 函数:
function totalSupply() public view returns (uint256) { return _tokenIds.current(); }
众所周知,测试我们的智能合约非常重要。在本节中,我们将编写一些测试来深入了解forge test
并习惯于在原生 Solidity 中编写测试。我们将使用三个Foundry 作弊码(我喜欢它们!)来管理帐户状态以适应我们的测试场景。
我们将针对以下场景进行测试:
因为我们的智能合约中可以有复杂的逻辑。并且它们的行为会根据状态、用于调用的帐户、时间等而有所不同。为了应对这种情况,我们可以使用作弊码来管理区块链的状态。我们可以使用vm
实例来使用这些作弊码,它是 Foundry 的Test
库的一部分。
我们将在测试中使用三个作弊码:
startPrank
:为所有后续调用设置msg.sender
,直到调用stopPrank
。
stopPrank
:
停止由startPrank
启动的活动恶作剧,将msg.sender
和tx.origin
重置为调用startPrank
之前的值。
deal
:将地址提供地址的余额设置为给定余额。
Foundry 带有一个内置的测试库。我们首先导入这个测试库、我们的合约(我们要测试的那个)、定义测试、设置变量和setUp
函数。
pragma solidity ^0.8.13; import"forge-std/Test.sol"; import "../src/Figbot.sol"; contract FigbotTest is Test { Figbot figbot; address owner = address(0x1223); address alice = address(0x1889); address bob = address(0x1778); function setUp() public { vm.startPrank(owner); figbot = new Figbot(); vm.stopPrank(); } }
对于状态变量,我们创建了一个figbot
类型的变量Figbot
。这也是我喜欢定义用户帐户的地方。在 Foundry 中,您可以使用语法address(0x1243)
来描述地址。您可以为此使用任意四个字母数字字符。我分别创建了名为 owner、Alice 和 bob 的帐户。
现在我们的setUp
函数。这是在 Foundry 中编写测试的要求。这是我们进行所有部署和这种性质的事情的地方。我使用作弊码startPrank
将用户切换为“所有者”。默认情况下,Foundry 使用特定地址来部署测试合约。但这使得测试具有诸如withdrawFunds
等特权的函数变得更加困难。因此,我们切换到此部署的“所有者”帐户。
从一个简单的断言测试开始学习 Foundry 约定。按照惯例,所有的测试函数都必须有前缀test
。我们使用assertEq
来测试两个值是否相等。
我们调用MaxSupply
函数并测试结果值是否为 100,正如我们在合同中描述的那样。我们使用forge test
来运行我们的测试。
瞧!我们通过了测试。
现在我们已经编写了一个简单的测试,让我们用作弊码编写一个。我们合约的主要功能。
balanceOf
Alice 是否为 1 我们有另一个测试函数用于我们预计会失败的测试。用于此类测试的前缀是testFail
。如果调用者资金不足,我们将测试mint
函数是否恢复。
balanceOf
Bob 是否为 1 因为 mint 没有通过,Bob 的余额不会是 1。因此,它会失败,这正是我们使用testFail
的原因。因此,当您运行forge test
时,它将通过。
在这里,我们将测试一个只有“所有者”才能成功执行的功能。对于这个测试,我们将:
withdrawFunds
功能(如果成功,它应该使所有者的余额0.69 ether)现在我们已经测试了我们的合约,是时候部署它了。我们需要一个钱包的私钥(带有一些 Rinkeby 测试 ETH)和一个 RPC URL。对于我们的 RPC URL,我们将使用Figment DataHu 。
Figment DataHub 为我们提供了在 Web 3 上开发的基础设施。它支持多个链,如 Ethereum、Celo、Solana、Terra 等。
您可以从“协议”选项卡下获取 Rinkeby 的 RPC URL。
打开您的终端以将这两个内容作为环境变量输入。
export FIG_RINKEBY_URL=<Your RPC endpoint> export PVT_KEY=<Your wallets private key>
一旦我们有了环境变量,我们就可以部署了
forge create Figbot --rpc-url=$FIG_RINKEBY_URL --private-key=$PVT_KEY
我们差不多完成了。到目前为止,我们已经使用 Foundry 和 Figment DataHub 编写、测试和部署了智能合约。但我们还没有完全完成。我们现在要验证我们的合同。我们需要为此设置我们的Etherscan API 密钥。
export ETHERSCAN_API=<Your Etherscan API Key>
现在我们可以验证我们的智能合约了。
forge verify-contract --chain-id <Chain-Id> --num-of-optimizations 200 --compiler-version <Compiler Version> src/<Contract File>:<Contract> $ETHERSCAN_API
恭喜!现在,您可以使用 Foundry 编写、测试和部署智能合约。我希望你喜欢这篇文章并从中学习。我确实很喜欢写这个。随时让我知道您对此的想法。