本节摘要:智能合约是 Web3 把"规则"变成"代码"的核心机制。本节讲清楚它和普通程序的区别、为什么"代码即法律"既是优势也是风险、以及编写和部署一个合约的真实流程。读完你能理解为什么 DeFi 被盗动辄上亿美金——不是黑客多厉害,是合约写错代价太大。
智能合约是部署在区块链上、由链上交易触发自动执行的程序。
它和普通程序的关键区别有三点:
"代码即法律"(Code is Law)是智能合约的核心哲学——规则写成代码,代码怎么执行结果就是什么,没有"我本意不是这样"的申辩空间。
优势:规则透明、执行确定、无人能干预。DeFi 借贷合约规定抵押率低于 150% 就清算,那不管借款人是散户还是巨鲸,触线就清算,没有"通融一下"。
风险:代码写错了也"即法律"。2016 年 The DAO 被盗 360 万 ETH,因为合约里有个递归调用漏洞,黑客按"代码逻辑"合法地提走了钱。社区最后靠硬分叉把钱追回,但这违背了"代码即法律"原则——说明完全靠代码也不现实。

用 Solidity(以太坊上最主流的合约语言)写一个最简的代币合约:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract SimpleToken { string public name = "MyToken"; mapping(address => uint256) public balances; uint256 public totalSupply; // 铸造代币给调用者 function mint(uint256 amount) public { totalSupply += amount; balances[msg.sender] += amount; } // 转账 function transfer(address to, uint256 amount) public { require(balances[msg.sender] >= amount, "余额不足"); balances[msg.sender] -= amount; balances[to] += amount; } }
注意几个要点:
msg.sender 是自动可用的,代表调用者地址,合约不需要也不应该让用户传入自己的地址(防伪造)。require 是断言,不满足就回滚整笔交易,状态不变,已消耗的 Gas 不退。mapping 是键值存储,相当于持久化的字典,记在链上。合约运行在 EVM(以太坊虚拟机)里,有几个硬约束决定了它能做什么不能做什么:
1. 不能主动运行。 合约没有"定时任务",必须有人发交易触发。要做定时任务得靠链外服务(Chainlink Keepers、Gelato)发触发交易。
2. 不能访问外部数据。 EVM 是沙箱,不能直接 HTTP 请求。要拿链外数据(股价、天气、比赛结果)得用预言机(Chainlink)把数据喂进来。
3. 不能产生真随机数。 EVM 执行要确定性(所有节点算出同样结果),真随机会让节点结果不一致。要用链上随机得用 VRF(可验证随机函数)。
4. 计算受 Gas 限制。 每个操作消耗 Gas,单笔交易 Gas 有上限,复杂循环可能跑不完。这逼着合约写得高效。
合约一旦部署,漏洞就在那等着被发现。历史上几次大案:
| 事件 | 年份 | 损失 | 漏洞类型 |
|---|---|---|---|
| The DAO | 2016 | 360万ETH | 递归调用 |
| Parity 多签钱包 | 2017 | 15万ETH | 库合约未初始化 |
| Poly Network | 2021 | 6.1亿美金 | 跨链权限校验缺失 |
| Wormhole | 2022 | 3.2亿美金 | 签名验证绕过 |
| Euler Finance | 2023 | 2亿美金 | 抵押计算错误 |
共同点不是黑客多天才,而是合约逻辑里漏了一个边界检查。一个 require 写错位置,几亿美金就没了。
防御手段:
完全不可改的合约发现 bug 只能等死,所以出现了可升级模式。最常见的是代理模式:用户调用代理合约,代理把调用委托给逻辑合约,升级时只换逻辑合约地址,代理地址不变,用户无感。
// 代理合约核心:delegatecall contract Proxy { address public logic; // 逻辑合约地址 function upgrade(address newLogic) public onlyOwner { logic = newLogic; // 换逻辑合约=升级 } fallback() external { address impl = logic; assembly { calldatacopy(0, 0, calldatasize()) let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0) returndatacopy(0, 0, returndatasize()) switch result case 0 { revert(0, returndatasize()) } default { return(0, returndatasize()) } } } }
可升级是双刃剑:方便修 bug,但也意味着团队能改规则,违背"代码即法律"。所以成熟项目给升级加时间锁(如 48 小时延迟),让社区有时间否决恶意升级。
⚠️ 最大风险:合约部署前务必多次审计。一旦上链,漏洞就在那等着。很多项目方图快省了审计,结果上线几天被掏空。审计费几万美金,被盗几亿美金,这笔账要算清。
💡 关键直觉:智能合约把规则变成不可单方篡改的代码,这是 Web3 信任转移的基础。但"不可改"也是双刃剑——写错没法偷偷修,所以部署前审计、上线后赏金、必要时可升级+时间锁,是务实的平衡。