本文档为 Solidity 智能合约的部署指南, 详细介绍了部署智能合约到区块链的步骤、环境配置、合约编写、测试、网络配置、部署脚本、测试网部署、合约验证、 Gas 优化以及主网部署的注意事项,同时还包括部署后任务、常见问题解决方案以及高级部署模式。
在 LinkedIn 上关注我,获取更多区块链开发内容。
部署你的第一个Solidity合约可能会感到不知所措,但一旦你了解了关键步骤,实际上这是一个简单的过程。无论你是构建一个简单的token合约还是一个复杂的DeFi协议,本指南都将引导你了解将智能合约上线区块链所需的一切。
在我们深入部署之前,请确保你已具备:
成功合约部署的基础始于一个坚实的开发环境。我们将使用Hardhat,它已成为以太坊开发的黄金标准。
首先,创建一个新的项目目录并初始化它:
mkdir my-contract-project
cd my-contract-project
npm init -y
安装Hardhat和必要的依赖项:
npm install --save-dev hardhat @nomiclabs/hardhat-ethers ethers @nomiclabs/hardhat-waffle ethereum-waffle chai
初始化你的Hardhat项目:
npx hardhat
选择“Create a basic sample project”并按照提示操作。这将创建一个具有contracts、scripts和test目录的项目结构。
让我们创建一个简单但实用的例子——一个ERC20 token合约。创建一个新文件contracts/MyToken.sol
:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";contract MyToken is ERC20, Ownable {
constructor(
string memory name,
string memory symbol,
uint256 totalSupply
) ERC20(name, symbol) {
_mint(msg.sender, totalSupply * 10**decimals());
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
}
安装OpenZeppelin合约以获得安全、经过审计的代码:
npm install @openzeppelin/contracts
没有经过全面测试,永远不要部署。创建test/MyToken.test.js
:
const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("MyToken", function () {
let myToken;
let owner;
let addr1; beforeEach(async function () {
[owner, addr1] = await ethers.getSigners();
const MyToken = await ethers.getContractFactory("MyToken");
myToken = await MyToken.deploy("My Token", "MTK", 1000000);
await myToken.deployed();
}); it("Should have correct initial supply", async function () {
const totalSupply = await myToken.totalSupply();
expect(totalSupply).to.equal(ethers.utils.parseEther("1000000"));
}); it("Should allow owner to mint tokens", async function () {
await myToken.mint(addr1.address, ethers.utils.parseEther("1000"));
const balance = await myToken.balanceOf(addr1.address);
expect(balance).to.equal(ethers.utils.parseEther("1000"));
});
});
运行你的测试:
npx hardhat test
更新你的hardhat.config.js
文件以包含网络配置:
require("@nomiclabs/hardhat-waffle");
require("dotenv").config();
module.exports = {
solidity: "0.8.19",
networks: {
sepolia: {
url: `https://sepolia.infura.io/v3/${process.env.INFURA_PROJECT_ID}`,
accounts: [process.env.PRIVATE_KEY]
},
goerli: {
url: `https://goerli.infura.io/v3/${process.env.INFURA_PROJECT_ID}`,
accounts: [process.env.PRIVATE_KEY]
},
mainnet: {
url: `https://mainnet.infura.io/v3/${process.env.INFURA_PROJECT_ID}`,
accounts: [process.env.PRIVATE_KEY]
}
}
};
为你的环境变量创建一个.env
文件:
INFURA_PROJECT_ID=your_infura_project_id
PRIVATE_KEY=your_wallet_private_key
ETHERSCAN_API_KEY=your_etherscan_api_key
安全警告:永远不要将你的.env
文件提交到版本控制。立即将其添加到你的.gitignore
中。
创建一个部署脚本scripts/deploy.js
:
const { ethers } = require("hardhat");
async function main() {
const [deployer] = await ethers.getSigners();
console.log("Deploying contracts with the account:", deployer.address);
console.log("Account balance:", (await deployer.getBalance()).toString());
const MyToken = await ethers.getContractFactory("MyToken");
const myToken = await MyToken.deploy("My Token", "MTK", 1000000);
await myToken.deployed();
console.log("MyToken deployed to:", myToken.address);
console.log("Transaction hash:", myToken.deployTransaction.hash);
}main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});
始终首先部署到测试网。Sepolia目前是推荐的以太坊测试网:
npx hardhat run scripts/deploy.js --network sepolia
此命令将:
合约验证使你的代码公开可读,并允许通过区块浏览器进行交互。安装Etherscan插件:
npm install --save-dev @nomiclabs/hardhat-etherscan
添加到你的hardhat.config.js
:
require("@nomiclabs/hardhat-etherscan");
module.exports = {
// ... other config
etherscan: {
apiKey: process.env.ETHERSCAN_API_KEY
}
};
验证你部署的合约:
npx hardhat verify --network sepolia CONTRACT_ADDRESS "My Token" "MTK" 1000000
Gas成本可能很高,尤其是在主网上。以下是关键的优化策略:
对于部署后不会更改的变量,使用 immutable
和 constant
关键字:
contract MyToken {
address public immutable owner;
uint256 public constant MAX_SUPPLY = 1000000 * 10**18;
constructor() {
owner = msg.sender;
}
}
通过按大小对变量进行排序来有效地打包结构体:
struct User {
uint128 balance; // 16 bytes
uint128 rewards; // 16 bytes
address wallet; // 20 bytes (but packed in 32-byte slot)
bool isActive; // 1 byte (packed with address)
}
对于你不需要从合约中查询的数据,使用事件而不是存储:
event TokenMinted(address indexed to, uint256 amount);
function mint(address to, uint256 amount) external {
_mint(to, amount);
emit TokenMinted(to, amount);
}
在部署到主网之前,请验证:
一旦你在测试网上进行了彻底的测试,主网部署遵循相同的过程:
npx hardhat run scripts/deploy.js --network mainnet
主网的重要注意事项:
成功部署后:
Gas不足错误:增加部署脚本中的gas限制,或将复杂的构造函数分解为较小的初始化函数。
Nonce过低:当交易发送得太快时会发生这种情况。在交易之间添加延迟或手动设置nonce。
替换交易价格过低:提高卡住交易的gas价格,或使用具有更高gas价格的eth_sendRawTransaction
。
合约创建代码存储 Gas 不足:你的合约可能太大。考虑使用代理模式或在多个合约之间拆分功能。
对于生产应用程序,请考虑以下高级模式:
代理合约用于可升级合约:
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
CREATE2 部署用于确定性地址:
const salt = ethers.utils.keccak256(ethers.utils.toUtf8Bytes("my-salt"));
const factory = await ethers.getContractFactory("MyToken");
const deployTx = await factory.getDeployTransaction("My Token", "MTK", 1000000);
多重签名部署,用于增强生产环境中的安全性。
部署Solidity合约是任何区块链开发人员的关键技能。成功部署的关键在于彻底的测试、仔细的配置以及遵循安全最佳实践。从测试网开始,验证你的合约,优化gas效率,并始终制定部署后计划。
请记住,部署仅仅是开始。智能合约一旦部署就不可更改,因此请花时间在进入主网之前把一切都做对。有了这些工具和实践,你将充满信心地部署合约。
- 原文链接: coinsbench.com/how-to-de...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!