本文详细介绍了如何在不同的区块链上通过 CREATE2
指令部署智能合约,并确保它们使用相同的地址。文中提供了具体的实施步骤,包括项目初始化、RPC URL 的获取、智能合约的编写及部署脚本的编写,适合对智能合约和多链部署感兴趣的开发者。
我们都熟悉智能合约,并理解如何在区块链上部署一个智能合约。如果你觉得上述说法有些难以理解,可以阅读我的文章 如何与你的智能合约进行交互和部署
每当我们在区块链上部署一个新的智能合约时,我们会收到一个唯一的合约地址。智能合约地址的生成是基于一个适当的机制,该机制受到几个因素的影响,其中之一就是部署合约的钱包地址的 nonce
。
考虑到这一点,如果你在不同的链(例如 Polygon 和 Ethereum 主网络)上,在不同的时间段部署任何合约,SOLO方式使得在这两条链上可以获得相同的地址就是当两条链上的部署者地址具有相同的 Nonce 时。
通常情况下,在不同链上维持相同的 nonce 是困难的。
虽然这并不会破坏任何东西,但通常 dApp 倾向于采取一种方法,即在不同链上部署相同的合约在相同的地址上。
例如:
如上所示,Uniswap Factory
在上述提到的链上以相同的地址部署。
使用 opCode CREATE2
可以在相同地址上部署合约,使用:
来源:Alchemy
让我们考虑一个 create2 的例子 👇
1.1 打开终端,按照下面提供的代码创建一个新文件夹并使用 NPM 初始化它。
mkdir deploying-with-create2 && cd deploying-with-create2
npm init -y
1.2 安装 hardhat 和项目所需的其他依赖项
npm install --save-dev hardhat @nomiclabs/hardhat-ethers 'ethers@^5.0.0' dotenv
1.3 创建一个新的 hardhat 项目,并选择 ‘Create an empty hardhat.config.js’
1.4 创建两个文件夹; contracts 和 scripts。在根目录中使用以下代码:
mkdir contracts && mkdir scripts
1.5 最后,在根目录中创建一个 “.env” 文件,用于存储所有的 API 和私钥。并存储以下值。
BUILDBEAR_API_URL1 = "{YOUR_BUILDBEAR_API_URL1}"
BUILDBEAR_API_URL2 = "{YOUR_BUILDBEAR_API_URL1}"
PRIVATE_KEY = "{YOUR_PRIVATE_KEY}"
对于主网和 Polygon API URL,我们将使用 BuildBear。
你问为什么选择 BuildBear?请看这里:当 Localhost 失败时 和 使用 BuildBear Testnet 的分析赢得 Web3 黑客松
2.1 在 BuildBear 上创建一个私人测试网络 🐻❄️
2.1.1: 访问 BuildBear 应用程序。一旦用你的 Github 账号登录,你将看到一页类似于下面图片的内容
在这里我们必须创建一个简单的节点以获得 RPC URL,所以我们将点击 create an endpoint,然后我们将被重定向到节点配置页面。
我们将有 3 个选项:Forking Options、Hardhat Options 和 EVM Options
我们将从 Polygon 主网进行分叉,为此,我们必须提供 Polygon RPC,即:https://polygon-rpc.com。
然后,我们只需点击页面底部的 create
按钮。
恭喜!🎉 你已创建了私人测试网络节点!
你的页面应该更新为类似于以下内容:
点击 RPC URL(复制或点击查看)以获取你的私人测试网络的 RPC。
2.2: 为了执行交易,我们需要来自水龙头的资金。别担心!我们不必寻找随机水龙头来获取测试以太。
点击 Open Faucet 选项并选择你的账户。
之后,点击水龙头页面右上角的 Add to Metamask 选项。
你的 metamask 会立即提供 1,000 BB ETH。
注意:为了我们的当前教程,你需要再创建一个节点,从 Ethereum 主网进行分叉,使用这个 RPC:https://eth-rpc.gateway.pokt.network
2.3: 将 hardhat.config.js
更新为以下内容:
我们将使用两个独立的网络来展示 create2 特性。为此,我们将从 polygon 和 mainnet 进行分叉。
在网络中,我们创建了 2 个网络:
然后添加 metamask 账户的私钥(请不要把你的私钥暴露给任何人)。
现在我们的配置准备好了!让我们编写我们的智能合约。
在合同目录下创建一个新文件,命名为 DeterministicDeployFactory.sol
3.1 初始化你的合约,并定义编译器版本。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;contract DeterministicDeployFactory { }
3.2 在 DeterministicDeployFactory 合约内,我们将首先创建一个函数 deployUsingCreate2()并传入 bytecode 和 salt 作为参数。
function deployUsingCreate2(bytes memory bytecode, string memory _salt) external returns (address) {
}
在该函数内,我们将定义一个变量 addr 用于存储地址,并使用汇编与 EVM 进行低级交互。
在汇编语句中,我们可以使用 Yul 调用 create2 并指示 EVM 部署我们合约的字节码。
你的最终函数应如下所示:
function deployUsingCreate2(bytes memory bytecode, string memory _salt) external returns (address) {
address addr;
assembly {
addr := create2(0, add(bytecode, 0x20), mload(bytecode), _salt)
if iszero(extcodesize(addr)) {
revert(0, 0)
}
}
3.3 最后,我们将创建一个事件 Deploy 以在每次调用该函数时发出已部署合约地址的信号。
你的最终合约应看起来如下:
现在,我们还将创建另一个合约以使用 deployUsingCreate2 函数。
3.4 在合同目录下创建一个新文件,命名为 HelloWorld.sol
这是一个简单的合约,将打印字符串 “Hello World!”
在 HelloWorld.sol
文件中使用以下代码:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.9;contract HelloWorld { function greeting() public pure returns (string memory) {
return "Hello World!";
}
}
我们将部署这个 HelloWorld 合约以测试 create2 特性。
4.1 我们在这里部署 DeterministicDeployFactory 合约
(a) 对于 Polygon Fork → https://explorer.buildbear.io/node/fervent-bhaskara-f86fad/address/0xd3E4baaBdbD3F764ac1b96907196De35C29d3D7c
(b) 对于主网 Fork → https://explorer.buildbear.io/node/nervous-clarke-611206/address/0xd3E4baaBdbD3F764ac1b96907196De35C29d3D7c
4.2: 我们将使用 create2 函数来测试其特性。
要使用 create2 函数部署 HelloWorld 合约,我们将编写一个脚本,类似于以下代码:
const { ethers } = require("hardhat");
const fs = require('fs/promises');const main = async () => {
const Factory = await ethers.getContractFactory("DeterministicDeployFactory"); const factoryAddress = (JSON.parse(await fs.readFile('./addresses/address.json'))).factory; const factory = await Factory.attach(factoryAddress);
const HW = await ethers.getContractFactory("HelloWorld");
const byteCode = HW.bytecode; await factory.deployUsingCreate2(byteCode,"buildbear"); factory.once("Deploy", async (address) => {
const helloWorldContract = HW.attach(address);
console.log("hello world contract has been deployed at ", address);
const greeting = await helloWorldContract.greeting();
console.log(greeting);
})
}main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
在代码中,你可以看到,我们使用 DeterministicDeployFactory 合约来部署 HelloWorld 合约,以使用 create2 函数。
使用以下命令在两个链上部署 HelloWorld 合约。
npx hardhat run scripts/deployHelloWorld.js --network buildBear_polygonfork
npx hardhat run scripts/deployHelloWorld.js --network buildBear_mainnetfork
一旦部署合约,你将注意到 HelloWorld 合约在这两个链上都以相同的地址部署。
这是通过 create2 函数实现的。
你可以看到两个合约分别在 polygon-forked-chain 和 mainnet-forked-chain 上部署。
这是一个如何在多条链上使用相同合约地址进行部署的简要概述!
告诉我们你对 Create2 的看法!!
GitHub 链接 → https://github.com/BuildBearLabs/Tutorials
如果你欣赏我们正在做的工作,请在 Twitter 上关注我们,并加入我们的 Telegram 群组,如果你还没有这样做。
如果你喜欢我们的工作,请给我们点赞 👏。
Pari Tomar ( Twitter || LinkedIn),始终欢迎反馈和学习。
顺便说一下,如果你认识任何希望与 BuildBear 合作的人。请查看 这里!!!
- 原文链接: medium.com/buildbear/lea...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!