创建自己的代币是学习智能合约开发的重要实践。本文通过实现一个完整的ERC20代币合约,详细介绍代币的发行、转账、授权等核心功能,帮助开发者掌握代币合约的开发。
一、什么是代币
1. 基本概念
代币(Token)是基于区块链发行的数字资产,可以代表价值、权益或功能。ERC20是以太坊上最常用的代币标准,定义了代币的基本接口和功能。
2. 代币的特点
标准化
- 遵循ERC20标准
- 兼容各种钱包和交易所
- 统一的接口规范
- 易于集成
可编程
- 自定义发行规则
- 实现特殊功能
- 灵活的权限控制
- 丰富的应用场景
去中心化
二、ERC20标准
1. 标准接口
必需函数
1 2 3 4 5 6 7 8 9 10 11
| 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); } `标准事件:`solidity event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value);
|
2. 可选功能
元数据
- name:代币名称
- symbol:代币符号
- decimals:小数位数
其他功能
三、如何实现代币
1. 基础实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| 简单代币: pragma solidity ^0.8.0;
contract SimpleToken { string public name = "My Token"; string public symbol = "MTK"; uint8 public decimals = 18; uint256 public totalSupply; java mapping(address => uint256) public balances; mapping(address => mapping(address => uint256)) public allowances;
javascript constructor(uint256 _initialSupply) { totalSupply = _initialSupply * 10decimals;
balances[msg.sender] = totalSupply; emit Transfer(address(0), msg.sender, totalSupply);
|
}
1 2 3
| function balanceOf(address account) public view returns (uint256) { return balances[account];
|
}
1 2 3 4 5 6 7 8 9
| function transfer(address to, uint256 amount) public returns (bool) { require(balances[msg.sender] >= amount, "Insufficient balance");
balances[msg.sender] -= amount;
balances[to] += amount; emit Transfer(msg.sender, to, amount); return true;
|
}
1 2 3 4
| function approve(address spender, uint256 amount) public returns (bool) { allowances[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount);
|
}
1 2 3
| function allowance(address owner, address spender) public view returns (uint256) { return allowances[owner][spender];
|
}
1 2 3 4 5 6 7 8 9 10
| function transferFrom(address from, address to, uint256 amount) public returns (bool) { require(balances[from] >= amount, "Insufficient balance"); require(allowances[from][msg.sender] >= amount, "Insufficient allowance"); python
allowances[from][msg.sender] -= amount; balances[from] -= amount;
emit Transfer(from, to, amount);
|
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
| #### 2. 完整实现
功能完整代币: contract MyToken { string public name string public symbol uint8 public decimals
address public owner bool public paused
mapping(address => bool) public blacklisted
event Mint(address indexed to, uint256 amount) event Burn(address indexed from, uint256 amount) event Paused(address account) event Unpaused(address account)
modifier onlyOwner() { require(msg.sender == owner, "Not owner") _ }
modifier whenNotPaused() { require(!paused, "Token is paused") _ }
modifier notBlacklisted(address account) { require(!blacklisted[account], "Account is blacklisted") _ }
constructor( string memory _name, string memory _symbol, uint8 _decimals, uint256 _initialSupply ) { name = _name symbol = _symbol decimals = _decimals owner = msg.sender }
}
// 转账函数:包含暂停和黑名单检查 function transfer(address to, uint256 amount) public whenNotPaused notBlacklisted(msg.sender) notBlacklisted(to) returns (bool) { }
function approve(address spender, uint256 amount) { }
}
function transferFrom(address from, address to, uint256 amount) notBlacklisted(from) {
}
// 增发代币:只有owner可以调用 function mint(address to, uint256 amount) public onlyOwner { totalSupply += amount emit Mint(to, amount) emit Transfer(address(0), to, amount) }
// 销毁代币:用户销毁自己的代币 function burn(uint256 amount) public { totalSupply -= amount emit Burn(msg.sender, amount) emit Transfer(msg.sender, address(0), amount) }
// 暂停代币:只有owner可以调用 function pause() public onlyOwner { paused = true emit Paused(msg.sender) }
// 恢复代币:只有owner可以调用 function unpause() public onlyOwner { paused = false emit Unpaused(msg.sender) }
// 加入黑名单:只有owner可以调用 function addToBlacklist(address account) public onlyOwner { blacklisted[account] = true }
// 移除黑名单:只有owner可以调用 function removeFromBlacklist(address account) public onlyOwner { blacklisted[account] = false }
|
四、如何使用代币
1. 部署代币
部署脚本
1 2 3 4 5 6 7 8 9 10
| const MyToken = await ethers.getContractFactory("MyToken"); const token = await MyToken.deploy( "My Token", "MTK", 18, 1000000 ); await token.deployed(); console.log("Token address:", token.address);
|
2. 转账操作
1 2 3 4 5 6 7 8 9 10
| 直接转账: await token.transfer(recipientAddress, ethers.utils.parseEther("100"))
授权转账: // 1. 授权:允许spender使用100个代币 await token.approve(spenderAddress, ethers.utils.parseEther("100"))
// 2. 被授权者转账:从owner账户转账给recipient await token.transferFrom(ownerAddress, recipientAddress, ethers.utils.parseEther("100"))
|
3. 查询信息
1 2 3
| 查询余额: const balance = await token.balanceOf(userAddress) console.log("Balance:", ethers.utils.formatEther(balance), "MTK")
|
查询授权:
const allowance = await token.allowance(ownerAddress, spenderAddress);
console.log(“Allowance:”, ethers.utils.formatEther(allowance), “MTK”);
五、应用场景
1. 项目代币
ICO/IDO:
治理代币:
2. 功能代币
游戏代币:
积分系统:
3. 稳定币
锚定资产:
六、功能扩展
1. 税费机制
交易税费**:
uint256 public taxRate = 100; // 1%
address public taxRecipient;
// 带税费的转账函数
// 计算税费
uint256 tax = amount * taxRate / 10000;
// 计算实际转账金额
uint256 transferAmount = amount - tax;
balances[to] += transferAmount;
// 税费转入指定账户
balances[taxRecipient] += tax;
emit Transfer(msg.sender, to, transferAmount);
emit Transfer(msg.sender, taxRecipient, tax);
}
时间锁:
mapping(address => uint256) public lockTime;
mapping(address => uint256) public lockedAmount;
// 锁仓函数:锁定代币一段时间
function lock(uint256 amount, uint256 duration) public {
lockedAmount[msg.sender] += amount;
// 设置解锁时间
lockTime[msg.sender] = block.timestamp + duration;
// 解锁函数:时间到了才能解锁
function unlock() public {
require(block.timestamp >= lockTime[msg.sender], “Still locked”);
uint256 amount = lockedAmount[msg.sender];
lockedAmount[msg.sender] = 0;
balances[msg.sender] += amount;
3. 销毁机制
自动销毁:
// 转账时自动销毁一部分代币
uint256 burnAmount = amount / 100; // 1% 销毁
uint256 transferAmount = amount - burnAmount;
// 减少总供应量
totalSupply -= burnAmount;
emit Transfer(msg.sender, address(0), burnAmount);
}
1 2 3 4 5 6 7 8 9 10 11
| ## 七、最佳实践
#### 1. 安全考虑
#### 溢出保护
- 使用0.8.0+版本 - 自动检查溢出 - 无需SafeMath
|
重入保护:
bool private locked;
// 防止重入攻击的修改器
modifier nonReentrant() {
require(!locked, “Reentrant call”);
locked = true;
locked = false;
2. Gas优化
批量操作:
// 批量转账:减少交易次数
function batchTransfer(address[] memory recipients, uint256[] memory amounts) public {
require(recipients.length == amounts.length, “Arrays length mismatch”);
for (uint256 i = 0; i < recipients.length; i++) {
transfer(recipients[i], amounts[i]);
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #### 3. 标准兼容
#### 遵循ERC20
- 实现所有必需函数 - 发出标准事件 - 返回正确的值 - 处理边界情况
## 八、总结
创建代币是掌握智能合约开发的重要实践。关键要点:
#### 核心功能
- 转账功能 - 授权机制 - 余额查询
#### 标准实现
- 实现必需函数 - 兼容各种应用
#### 功能扩展
- 锁仓机制
通过实现代币合约,可以深入理解ERC20标准,掌握智能合约的核心功能,为开发更复杂的DeFi应用打下基础。
|
本文标题: Solidity编程实战创建代
发布时间: 2023年04月11日 00:00
最后更新: 2026年09月16日 05:40
原始链接: https://haoxiang.eu.org/b4b33b79/
版权声明: 本文著作权归作者所有,均采用CC BY-NC-SA 4.0许可协议,转载请注明出处!