第一个Solidity合约 #
一、Hello World合约 #
1.1 完整代码 #
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract HelloWorld {
string public greet = "Hello, World!";
function setGreet(string memory _greet) public {
greet = _greet;
}
function getGreet() public view returns (string memory) {
return greet;
}
}
1.2 代码解析 #
1. SPDX许可证声明
solidity
// SPDX-License-Identifier: MIT
- 每个Solidity文件必须以SPDX许可证声明开头
- MIT是最常用的开源许可证
- 如果不想指定,可以使用
UNLICENSED
2. 编译器版本声明
solidity
pragma solidity ^0.8.0;
pragma:指示编译器如何处理代码^0.8.0:使用0.8.x版本(不包含0.9.0)- 推荐使用最新稳定版本
3. 合约定义
solidity
contract HelloWorld {
// 合约内容
}
contract:关键字,定义一个合约HelloWorld:合约名称- 合约类似于面向对象语言中的类
4. 状态变量
solidity
string public greet = "Hello, World!";
string:数据类型,字符串public:可见性修饰符,公开可访问greet:变量名- 状态变量永久存储在区块链上
5. 函数定义
solidity
function setGreet(string memory _greet) public {
greet = _greet;
}
function:函数关键字setGreet:函数名string memory _greet:参数,memory表示临时存储public:公开可调用
6. view函数
solidity
function getGreet() public view returns (string memory) {
return greet;
}
view:只读函数,不修改状态returns:返回值类型声明
二、合约结构详解 #
2.1 完整合约结构 #
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract ContractName {
// 1. 状态变量
uint256 public count;
address public owner;
// 2. 事件
event CountChanged(uint256 newCount);
// 3. 修饰器
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
// 4. 构造函数
constructor() {
owner = msg.sender;
}
// 5. 函数
function increment() public {
count++;
emit CountChanged(count);
}
// 6. 接收函数
receive() external payable {}
// 7. 回退函数
fallback() external payable {}
}
2.2 各部分说明 #
| 组成部分 | 说明 | 示例 |
|---|---|---|
| SPDX声明 | 许可证标识 | // SPDX-License-Identifier: MIT |
| pragma | 编译器版本 | pragma solidity ^0.8.0; |
| import | 导入其他文件 | import "./Other.sol"; |
| 状态变量 | 永久存储数据 | uint256 public count; |
| 事件 | 日志记录 | event Transfer(...); |
| 修饰器 | 函数修饰 | modifier onlyOwner() {...} |
| 构造函数 | 初始化执行 | constructor() {...} |
| 函数 | 业务逻辑 | function foo() {...} |
| 接收函数 | 接收ETH | receive() external payable {} |
| 回退函数 | 未知调用 | fallback() external payable {} |
三、在Remix中部署 #
3.1 创建文件 #
- 打开 https://remix.ethereum.org
- 点击左侧文件浏览器中的"Create New File"
- 命名为
HelloWorld.sol - 粘贴合约代码
3.2 编译合约 #
- 点击左侧"SOLIDITY COMPILER"图标
- 选择编译器版本
0.8.x - 点击"Compile HelloWorld.sol"
- 确认编译成功(绿色勾号)
3.3 部署合约 #
- 点击左侧"DEPLOY & RUN TRANSACTIONS"图标
- 选择环境:
- Remix VM:本地虚拟机,快速测试
- Injected Provider:连接MetaMask钱包
- Hardhat Provider:连接Hardhat节点
- 点击"Deploy"按钮
- 等待部署完成
3.4 交互测试 #
部署成功后:
- 展开"Deployed Contracts"
- 点击
greet按钮查看值 - 在
setGreet输入框输入新值 - 点击
setGreet按钮 - 再次点击
greet查看更新后的值
四、在Hardhat中部署 #
4.1 项目设置 #
bash
mkdir hello-hardhat
cd hello-hardhat
npm init -y
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox
npx hardhat init
4.2 编写合约 #
创建contracts/HelloWorld.sol:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract HelloWorld {
string public greet = "Hello, World!";
function setGreet(string memory _greet) public {
greet = _greet;
}
function getGreet() public view returns (string memory) {
return greet;
}
}
4.3 编译合约 #
bash
npx hardhat compile
4.4 编写部署脚本 #
创建scripts/deploy.js:
javascript
const hre = require("hardhat");
async function main() {
const HelloWorld = await hre.ethers.getContractFactory("HelloWorld");
const hello = await HelloWorld.deploy();
await hello.deployed();
console.log("HelloWorld deployed to:", hello.address);
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
4.5 部署到本地网络 #
bash
# 终端1:启动本地节点
npx hardhat node
# 终端2:部署合约
npx hardhat run scripts/deploy.js --network localhost
4.6 部署到测试网 #
修改hardhat.config.js:
javascript
require("@nomicfoundation/hardhat-toolbox");
module.exports = {
solidity: "0.8.20",
networks: {
sepolia: {
url: "https://sepolia.infura.io/v3/YOUR_INFURA_KEY",
accounts: ["YOUR_PRIVATE_KEY"]
}
}
};
部署命令:
bash
npx hardhat run scripts/deploy.js --network sepolia
五、在Foundry中部署 #
5.1 创建项目 #
bash
forge init hello-foundry
cd hello-foundry
5.2 编写合约 #
创建src/HelloWorld.sol:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract HelloWorld {
string public greet = "Hello, World!";
function setGreet(string memory _greet) public {
greet = _greet;
}
function getGreet() public view returns (string memory) {
return greet;
}
}
5.3 编写测试 #
创建test/HelloWorld.t.sol:
solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "../src/HelloWorld.sol";
contract HelloWorldTest is Test {
HelloWorld hello;
function setUp() public {
hello = new HelloWorld();
}
function testInitialGreet() public {
assertEq(hello.greet(), "Hello, World!");
}
function testSetGreet() public {
hello.setGreet("Hello, Foundry!");
assertEq(hello.greet(), "Hello, Foundry!");
}
}
5.4 运行测试 #
bash
forge test
输出:
text
Running 2 tests for test/HelloWorld.t.sol:HelloWorldTest
[PASS] testInitialGreet() (gas: 5234)
[PASS] testSetGreet() (gas: 12345)
Test result: ok. 2 passed; 0 failed; finished in 1.23s
5.5 部署合约 #
bash
forge create src/HelloWorld.sol:HelloWorld --rpc-url $RPC_URL --private-key $PRIVATE_KEY
六、Gas与交易 #
6.1 Gas概念 #
Gas是以太坊上执行操作的计算单位:
| 概念 | 说明 |
|---|---|
| Gas | 计算单位 |
| Gas Price | 每单位Gas的价格(Gwei) |
| Gas Limit | 交易最大Gas消耗 |
| Gas Used | 实际消耗的Gas |
6.2 查看Gas消耗 #
在Remix中:
- 展开交易详情
- 查看"transaction cost"和"execution cost"
solidity
// Gas消耗示例
function setGreet(string memory _greet) public {
greet = _greet; // SSTORE操作,消耗Gas
}
6.3 Gas优化建议 #
solidity
// 优化前:每次都存储
contract Bad {
string public greet;
function setGreet(string memory _greet) public {
greet = _greet; // 每次都消耗Gas
}
}
// 优化后:使用事件记录
contract Good {
string public greet;
event GreetChanged(string newGreet);
function setGreet(string memory _greet) public {
greet = _greet;
emit GreetChanged(_greet); // 事件更便宜
}
}
七、常见问题 #
7.1 编译错误 #
问题:版本不匹配
text
Error: Source file requires different compiler version
解决:确保pragma声明与编译器版本一致。
问题:语法错误
text
Error: Expected ';' but got '}'
解决:检查语法,确保每个语句以分号结尾。
7.2 部署错误 #
问题:Gas不足
text
Error: Transaction ran out of gas
解决:增加Gas Limit。
问题:网络连接失败
text
Error: could not detect network
解决:检查网络配置和RPC URL。
7.3 运行时错误 #
问题:调用失败
text
Error: call revert exception
解决:检查require条件和函数逻辑。
八、总结 #
第一个合约要点:
| 要点 | 说明 |
|---|---|
| SPDX声明 | 必须的许可证标识 |
| pragma | 指定编译器版本 |
| contract | 定义合约 |
| 状态变量 | 链上永久存储 |
| 函数 | 业务逻辑实现 |
开发流程:
text
编写合约 → 编译 → 测试 → 部署 → 交互
下一步,让我们学习Solidity基础语法!
最后更新:2026-03-27