4. ERC-20代币标准:从接口到DAO实战
ERC-20,说白了就是以太坊上的代币通用语言。我刚开始接触智能合约时,觉得这玩意儿就是个转账工具。后来在DAO项目里踩过坑才明白——ERC-20是DAO的经济血脉,设计不好,整个组织都可能瘫痪。
今天咱们就把它拆开揉碎了讲。从接口定义到销毁机制,再到DAO里的实际玩法,一步到位。
4.1 ERC-20接口详解:每个函数都是钱
ERC-20的核心接口其实就6个函数。嗯,别被文档吓到,咱们一个个过。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IERC20 {
// 查询总供应量
function totalSupply() external view returns (uint256);
// 查询某地址的余额
function balanceOf(address account) external view returns (uint256);
// 转账
function transfer(address to, uint256 amount) external returns (bool);
// 查询授权额度
function allowance(address owner, address spender) external view returns (uint256);
// 授权
function approve(address spender, uint256 amount) external returns (bool);
// 从授权地址转账
function transferFrom(address from, address to, uint256 amount) external returns (bool);
// 事件
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
这里有个坑,我当年就栽过。transfer和transferFrom的区别,很多人搞混。简单说:transfer是你自己掏钱给别人;transferFrom是别人授权你,你从他的钱包里掏钱。DAO里的工资发放、提案执行,全得靠transferFrom。
核心要点:ERC-20的approve/transferFrom模式,是DAO自动化操作的基础。没有这个,智能合约就没法替你管钱。
4.2 代币发行与铸造:别把总量写死
代币发行,我见过最蠢的做法是把总量写死在构造函数里。你想想看,DAO是要发展的,未来可能需要增发激励新成员,总量锁死等于自断后路。
我个人习惯的做法是:
contract DAOToken is IERC20 {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
address public owner;
// 只有owner可以铸造
modifier onlyOwner() {
require(msg.sender == owner, "Not owner");
_;
}
function mint(address to, uint256 amount) external onlyOwner {
_totalSupply += amount;
_balances[to] += amount;
emit Transfer(address(0), to, amount);
}
// 铸造时检查上限
uint256 public maxSupply = 1_000_000 ether;
function mint(address to, uint256 amount) external onlyOwner {
require(_totalSupply + amount <= maxSupply, "Exceed max supply");
_totalSupply += amount;
_balances[to] += amount;
emit Transfer(address(0), to, amount);
}
}
为什么要设maxSupply?我曾经参与过一个DAO,创始人说「无限增发,永不增发」,结果半年后偷偷铸了10倍代币,社区直接炸了。设个硬顶,至少给成员一个心理安全垫。
实战技巧:铸造权限一定要用多签钱包或时间锁控制。单地址owner权限,等于把DAO的命脉交给一个人。我见过太多因为私钥泄露导致代币被无限铸造的惨案。
4.3 代币销毁与总量控制:通缩的艺术
销毁,就是把代币从流通中永久移除。为什么需要销毁?说白了就是控制通胀,甚至制造通缩。
销毁有两种常见方式:
- 主动销毁:用户或合约主动调用burn函数
- 被动销毁:交易手续费的一部分自动销毁
function burn(uint256 amount) external {
require(_balances[msg.sender] >= amount, "Insufficient balance");
_balances[msg.sender] -= amount;
_totalSupply -= amount;
emit Transfer(msg.sender, address(0), amount);
}
// 带手续费的销毁模式
function transferWithFee(address to, uint256 amount) external returns (bool) {
uint256 fee = amount / 100; // 1%手续费
uint256 netAmount = amount - fee;
_balances[msg.sender] -= amount;
_balances[to] += netAmount;
_totalSupply -= fee; // 手续费直接销毁
emit Transfer(msg.sender, to, netAmount);
emit Transfer(msg.sender, address(0), fee);
return true;
}
这里要注意:销毁地址address(0)是合法的,但千万别把代币转到address(0)就以为销毁了。我见过有人把代币转到黑洞地址,结果合约里还记录着余额,搞得账目对不上。正确的做法是:销毁必须同时减少_totalSupply。
警告:销毁操作不可逆。一旦销毁,代币就永远消失了。DAO在做销毁提案时,一定要经过充分的社区讨论和投票。我曾经见过一个DAO因为误操作销毁了国库30%的代币,差点导致组织解散。
4.4 代币在DAO中的应用:不只是投票工具
很多人以为DAO里的代币就是用来投票的。其实远不止这些。我总结了几种核心应用场景:
| 应用场景 | 实现方式 | 我的经验 |
|---|---|---|
| 投票权重 | 根据代币余额计算投票权 | 注意防范「闪电贷攻击」,建议用快照机制 |
| 国库管理 | 代币作为国库资产,通过提案分配 | 国库代币最好用多签+时间锁双重保护 |
| 激励分配 | 根据贡献铸造代币奖励 | 铸造权限要分散,避免单点控制 |
| 会员资格 | 持有一定数量代币才能加入 | 门槛要动态调整,防止早期成员垄断 |
| 分红机制 | 根据代币持有比例分配收益 | 分红逻辑要写在合约里,别用手动转账 |
举个实际例子。我之前设计过一个创作者DAO,代币除了投票,还能用来:
- 质押获得平台收益分成
- 作为内容付费的流通媒介
- 解锁高级功能(比如数据分析工具)
- 参与社区治理提案的发起权(需要质押一定数量)
你想想看,如果代币只有投票功能,那它就是个政治工具。一旦代币有了实际用途,它就成了经济引擎。DAO的活力,很大程度上取决于代币的经济模型设计。
核心原则:代币在DAO中要同时扮演「治理权」和「经济权」两个角色。只重治理不重经济,DAO会变成空谈俱乐部;只重经济不重治理,DAO会变成投机市场。
嗯,关于ERC-20在DAO中的应用,今天就先聊到这儿。下一章咱们会深入讲ERC-721(NFT)在DAO里的玩法,那个更有意思——毕竟,谁不想拥有一个独一无二的数字身份呢?