第2章:智能合约基础回顾:Solidity语法速览、Remix IDE使用、合约编译与部署

好,咱们直接进入正题。这一章,我带你快速过一遍Solidity的核心语法,以及怎么用Remix这个IDE把合约跑起来。说白了,就是给你一把趁手的工具,再告诉你螺丝怎么拧。

2.1 Solidity语法速览:够用就行

Solidity这门语言,跟JavaScript有点像,但它是静态类型、编译型的。你不需要精通所有细节,但下面这几个核心概念,必须刻在脑子里。

2.1.1 状态变量与数据类型

合约里存的数据,就是状态变量。它们会永久保存在区块链上。我见过不少新手把局部变量当状态变量用,结果数据丢了,找都找不回来。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract SimpleStorage {
    // 状态变量,存储在链上
    uint256 public storedData;
    address public owner;
    bool public isActive;

    // 构造函数,部署时执行一次
    constructor() {
        owner = msg.sender;
        isActive = true;
    }

    function set(uint256 x) public {
        storedData = x;
    }

    function get() public view returns (uint256) {
        return storedData;
    }
}

这里要注意几个点:

  • uint256 是无符号整数,范围0到2^256-1。别用 int 除非你真的需要负数。
  • address 是账户地址,20字节。 msg.sender 是调用者地址,这个很常用。
  • public 关键字会自动生成一个getter函数,方便外部读取。
我的习惯: 状态变量尽量用 public,除非有特殊原因要隐藏。这样调试和前端对接都方便。

2.1.2 函数修饰符:控制访问权限

函数修饰符是Solidity的一大特色。你可以把它理解成「门禁卡」。只有持卡人才能进门。

contract AccessControl {
    address public admin;

    constructor() {
        admin = msg.sender;
    }

    // 自定义修饰符
    modifier onlyAdmin() {
        require(msg.sender == admin, "Not admin");
        _;  // 继续执行原函数
    }

    function sensitiveAction() public onlyAdmin {
        // 只有admin能调用
    }
}

嗯,这里有个坑。我曾经在项目里写了一个修饰符,忘了加 _;,结果函数体永远不执行。调试了半天才发现。你写的时候一定要检查这个分号。

2.1.3 事件与日志

事件是合约与外部世界沟通的桥梁。前端可以监听事件,获取链上状态变化。

event DataStored(uint256 indexed value, address indexed caller);

function set(uint256 x) public {
    storedData = x;
    emit DataStored(x, msg.sender);
}

为什么用事件?因为直接读状态变量很贵。事件是廉价的日志,而且可以索引(indexed),方便查询。我建议你每个重要的状态变更都emit一个事件,后面审计和调试会省很多事。

2.2 Remix IDE使用:从零到部署

Remix是个浏览器里的IDE,不需要安装任何东西。你打开 remix.ethereum.org 就能用。我个人觉得它是学习Solidity最好的起点。

2.2.1 界面布局

Remix的界面分三块:

  • 左侧文件浏览器: 管理你的.sol文件。可以创建、重命名、删除。
  • 中间编辑器: 写代码的地方。有语法高亮和自动补全。
  • 右侧功能区: 编译、部署、调试、测试都在这里。
重要: 每次修改代码后,记得先编译再部署。不然你部署的还是旧版本。

2.2.2 编译合约

在右侧「Solidity Compiler」面板:

  1. 选择编译器版本(建议用最新稳定版,比如0.8.x)。
  2. 点击「Compile xxx.sol」按钮。
  3. 如果编译成功,会显示绿色对勾。如果有错误,会显示红色错误信息。

编译完成后,你可以点击「ABI」和「Bytecode」查看生成的接口定义和字节码。这些是部署合约时需要的。

避坑指南: 我曾经因为编译器版本选错,导致合约部署后无法正常调用。Solidity 0.8.x 引入了很多安全特性(比如溢出检查),建议优先使用。

2.2.3 部署合约

在「Deploy & Run Transactions」面板:

  1. 环境选择: 选「Remix VM」是本地模拟,免费且快速。选「Injected Provider - MetaMask」就是连到真实网络。
  2. 合约选择: 从下拉列表里选你要部署的合约。
  3. 参数填写: 如果构造函数有参数,在这里填。
  4. 点击「Deploy」: 等待交易确认。

部署成功后,下方会出现合约实例。你可以直接调用它的函数,查看状态变量。

2.3 合约编译与部署:命令行方式

虽然Remix很方便,但真实项目里,我们一般用命令行工具。比如 trufflehardhat 或者 foundry。这里我以 hardhat 为例,给你演示一下。

2.3.1 安装与初始化

mkdir my-dao
cd my-dao
npm init -y
npm install --save-dev hardhat
npx hardhat init

选择「Create an empty hardhat.config.js」。然后你的项目就初始化好了。

2.3.2 编写编译脚本

hardhat.config.js 里配置编译器版本:

module.exports = {
  solidity: "0.8.20",
};

然后运行:

npx hardhat compile

编译后的产物在 artifacts/contracts/ 目录下。你会看到 .abi.bin 文件。

2.3.3 部署脚本

创建一个 scripts/deploy.js

const hre = require("hardhat");

async function main() {
  const SimpleStorage = await hre.ethers.getContractFactory("SimpleStorage");
  const contract = await SimpleStorage.deploy();
  await contract.deployed();
  console.log("合约部署地址:", contract.address);
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

运行部署:

npx hardhat run scripts/deploy.js --network localhost
我的建议: 开发阶段用本地网络(hardhat内置的),测试阶段用测试网(Goerli、Sepolia),上线前一定要在主网测试网跑一遍完整流程。

2.4 本章小结

这一章,我们快速过了一遍Solidity的核心语法,包括状态变量、函数修饰符、事件。然后手把手带你用Remix编译部署了一个合约。最后,我展示了用Hardhat进行命令行编译部署的流程。

你想想看,这些基础操作,其实就是你以后写DAO合约的「脚手架」。后面每一章,我们都会在这个基础上添砖加瓦。下一章,我们会深入DAO的核心——投票机制。到时候,你会看到这些基础语法是怎么组合成复杂逻辑的。

嗯,今天就到这里。记得动手敲一遍代码,光看是学不会的。


公众号:蓝海资料掘金营,微信deep3321