以太坊作为全球领先的区块链平台,其核心魅力之一在于智能合约——一种运行在区块链上、自动执行合约条款的计算机程序,无论是创建代币、去中心化应用(DApp)还是实现复杂的商业逻辑,智能合约都扮演着至关重要的角色,本教程将带你一步步了解以太坊智能合约的开发、部署与交互全过程。
什么是智能合约?
智能合约是“在计算机网络上可执行的、以数字形式定义的承诺协议”,它与传统合约的区别在于:
开发前的准备
在开始编写智能合约之前,你需要准备以下环境和工具:
钱包:
以太坊测试网 ETH:
开发环境:
Solidity 基础:
Solidity 是以太坊智能合约的主要编程语言,语法类似 JavaScript,你需要了解其基本语法、数据类型、函数修饰符、事件等,建议先阅读 Solidity 官方文档或相关教程。
编写你的第一个智能合约
我们以一个简单的“存储合约”为例,该合约允许用户存储和读取一个数字。
安装 Truffle:
npm install -g truffle
创建新项目:
mkdir my-first-contract cd my-first-contract truffle init
truffle init 会创建一个标准的项目结构,contracts 目录用于存放智能合约代码。
编写合约代码:
在 contracts 目录下创建一个名为 Storage.sol 的文件,并写入以下代码:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Storage {
uint256 private storedData;
// 存储一个值
function set(uint256 x) public {
storedData = x;
}
// 读取存储的值
function get() public view returns (uint256) {
return storedData;
}
}
编译合约: 在项目根目录下运行:
truffle compile
如果成功,会在 build/contracts 目录下生成编译后的 JSON 文件,包含了合约的 ABI(应用程序二进制接口)和字节码。
测试智能合约
测试是保证合约质量的关键步骤,Truffle 支持 JavaScript 和 Solidity 测试。
创建测试文件:
在 test 目录下创建一个 storage.test.js 文件:
const Storage = artifacts.require("Storage");
contract("Storage", (accounts) => {
it("should store the value 89.", async () => {
const storageInstance = await Storage.deployed();
await storageInstance.set(89, { from: accounts[0] });
const storedData = await storageInstance.get();
assert.equal(storedData, 89, "The value 89 was not stored.");
});
});
运行测试:
truffle test
确保所有测试通过,再进行下一步。
部署智能合约到测试网
配置网络:
在 truffle-config.js 文件中,配置你要部署的测试网信息(以 Goerli 为例):
module.exports = {
networks: {
development: {
host: "127.0.0.1",
port: 7545,
network_id: "*", // Match any network id
},
goerli: {
provider: () => new HDWalletProvider(mnemonic, `https://goerli.infura.io/v3/YOUR_INFURA_PROJECT_ID`),
network_id: 5, // Goerli's id
gas: 5500000, // Gas limit
confirmations: 2, // # of confs to wait between deployments
timeoutBlocks: 200, // # of blocks before a deployment times out
skipDryRun: true // Skip dry run before migrations? (default: false)
}
},
compilers: {
solc: {
version: "0.8.0", // Fetch exact version from solc-bin (default: truffle's version)
settings: { // See the solidity docs for advice about optimization and evmVersion
optimizer: {
enabled: true,
runs: 200
}
}
}
}
};
mnemonic:你的 MetaMask 钱包助记词(建议使用环境变量存储,不要直接写在代码里)。YOUR_INFURA_PROJECT_ID:在 Infura 注册后创建的项目 ID。创建迁移脚本:
在 migrations 目录下创建一个 2_deploy_contracts.js 文件:
const Storage = artifacts.require("Storage");
module.exports = function (deployer) {
deployer.deploy(Storage);
};
部署合约: 确保你的 MetaMask 已经切换到对应的测试网络(如 Goerli),并且有足够的测试 ETH。
truffle migrate --network goerli
部署成功后,你会在控制台看到合约的地址,MetaMask 会显示交易记录。
与已部署的智能合约交互
通过 Truffle Console:
truffle console --network goerli
在控制台中输入:
let storageInstance = awaitStorage.deployed(); await storageInstance.set(42); // 调用 set 函数 let storedValue = await storageInstance.get(); // 调用 get 函数 console.log(storedValue.toString()); // 输出存储的值
通过 Web3.js 或 Ethers.js(在 DApp 中): 这是最常见的交互方式,以 Ethers.js 为例:
npm install ethers
import { ethers } from "ethers";
// 合约地址和 ABI(从 build/contracts/Storage.json 中复制) const contractAddress = "YOUR_DEPLOYED_CONTRACT_ADDRESS"; const contractABI = [/ 这里是 Storage 合约的 ABI 数组 /];
// 创建提供者(连接到以太坊网络,MetaMask 提供者) const provider = new ethers.BrowserProvider(window.ethereum); const signer = await provider.getSigner(); // 获取签名者(当前账户) const storageContract = new ethers.Contract(contractAddress, contractABI, signer);
// 调用合约函数 const setValue = async () => { const tx = await storageContract.set(100); await tx.wait(); // 等待交易确认 console.log("Value set to 100"); };
const getValue = async () => { const value = await storageContract.get(); console.log("Stored value:", value.toString()); };
// 调用 setValue() 和 getValue() 来与合约交互
重要注意事项与最佳实践