ERC20:同质化代币标准
ERC20 是以太坊上最广泛使用的代币标准,用于创建同质化代币(每个代币都是相同的、可互换的)。
ERC20 应用场景
- DeFi 协议代币:Uniswap (UNI)、Compound (COMP)
- 稳定币:USDC、USDT、DAI
- 治理代币:用于 DAO 投票和治理
- 实用代币:平台内的功能性代币
ERC721:非同质化代币标准
ERC721 用于创建非同质化代币(NFT),每个代币都是独一无二的,不可替换。
ERC1155:多代币标准
ERC1155 是一个革命性的标准,允许在单个合约中管理多种类型的代币(同质化和非同质化)。
三种标准的对比分析
特征 | ERC20 | ERC721 | ERC1155 |
---|
代币类型 | 同质化 | 非同质化 | 多类型支持 |
可替换性 | 完全可替换 | 不可替换 | 根据类型决定 |
批量操作 | 不支持 | 不支持 | 原生支持 |
Gas 效率 | 中等 | 低 | 高 |
存储成本 | 低 | 高 | 中等 |
应用场景 | 货币、代币 | 艺术品、收藏品 | 游戏道具、多资产 |
Gas 成本比较
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // 铸造100个不同的代币
// ERC721方式:需要100次交易
for(uint i = 0; i < 100; i++) {
nft.mint(to, i, uri); // ~50,000 gas 每次
}
// 总计:~5,000,000 gas
// ERC1155方式:只需1次交易
uint256[] memory ids = new uint256[](100);
uint256[] memory amounts = new uint256[](100);
// ... 填充数组
multiToken.mintBatch(to, ids, amounts, types, uris); // ~500,000 gas
// 总计:~500,000 gas (节省90%!)
|
实际应用场景
1. DeFi 协议设计
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| // 组合使用不同标准的DeFi协议
contract DeFiProtocol {
IERC20 public governanceToken; // 治理代币
IERC721 public membershipNFT; // 会员NFT
IERC1155 public rewardAssets; // 奖励资产
function stakingReward(address user, uint256 amount) external {
// 基于ERC721会员等级和ERC20质押量计算奖励
uint256 memberLevel = getMemberLevel(user);
uint256 rewardId = calculateRewardType(amount, memberLevel);
rewardAssets.safeTransferFrom(
address(this),
user,
rewardId,
amount,
""
);
}
}
|
2. 游戏资产管理
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
| contract GameEconomy {
IERC1155 public gameAssets;
// 定义不同类型的游戏道具
uint256 public constant GOLD_COIN = 1; // 同质化货币
uint256 public constant SWORD_COMMON = 100; // 普通武器
uint256 public constant SWORD_RARE = 101; // 稀有武器
uint256 public constant UNIQUE_PET = 1000; // 独特宠物(NFT)
function craftItem(uint256[] memory materials, uint256[] memory amounts) external {
// 销毁材料
gameAssets.safeBatchTransferFrom(
msg.sender,
address(0), // 销毁地址
materials,
amounts,
""
);
// 创造新道具
uint256 newItemId = calculateCraftResult(materials);
gameAssets.safeTransferFrom(
address(this),
msg.sender,
newItemId,
1,
""
);
}
}
|
3. NFT 市场优化
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
| contract OptimizedMarketplace {
struct Listing {
address seller;
uint256 price;
bool active;
}
mapping(address => mapping(uint256 => Listing)) public listings;
// 支持ERC721和ERC1155的统一接口
function listItem(
address tokenContract,
uint256 tokenId,
uint256 amount,
uint256 price,
bool isERC1155
) external {
if (isERC1155) {
require(
IERC1155(tokenContract).balanceOf(msg.sender, tokenId) >= amount,
"Insufficient balance"
);
require(
IERC1155(tokenContract).isApprovedForAll(msg.sender, address(this)),
"Not approved"
);
} else {
require(
IERC721(tokenContract).ownerOf(tokenId) == msg.sender,
"Not owner"
);
require(amount == 1, "ERC721 amount must be 1");
}
listings[tokenContract][tokenId] = Listing({
seller: msg.sender,
price: price,
active: true
});
}
}
|
最佳实践和安全考虑
1. 重入攻击防护
重入攻击是指: 攻击者在合约执行 call(或 transfer)向外部地址发送 ETH 时,外部合约在接收到 ETH 的回调中再次调用当前合约的函数,从而重复提取资产。
1
2
3
4
5
6
7
8
| import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract SecureToken is ReentrancyGuard {
function transfer(address to, uint256 amount) external nonReentrant returns (bool) {
// 转账逻辑
return true;
}
}
|
2. 整数溢出防护
1
2
3
4
5
6
7
8
9
10
| // 使用SafeMath或Solidity 0.8+的内置检查
contract SafeToken {
using SafeMath for uint256; // 对于0.8以下版本
function transfer(address to, uint256 amount) external returns (bool) {
balanceOf[msg.sender] = balanceOf[msg.sender].sub(amount);
balanceOf[to] = balanceOf[to].add(amount);
return true;
}
}
|
3. 访问控制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| import "@openzeppelin/contracts/access/Ownable.sol";
contract ControlledToken is Ownable {
bool public paused = false;
modifier whenNotPaused() {
require(!paused, "Contract is paused");
_;
}
function pause() external onlyOwner {
paused = true;
}
function unpause() external onlyOwner {
paused = false;
}
}
|
4. 元数据标准化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| contract StandardizedNFT {
// 遵循OpenSea元数据标准
function tokenURI(uint256 tokenId) public view returns (string memory) {
return string(abi.encodePacked(baseURI, tokenId.toString(), ".json"));
}
// 元数据结构示例:
// {
// "name": "Item Name",
// "description": "Item Description",
// "image": "https://example.com/image.png",
// "attributes": [
// {"trait_type": "Rarity", "value": "Legendary"},
// {"trait_type": "Power", "value": 100}
// ]
// }
}
|
5. Gas 优化策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| contract GasOptimizedContract {
// 使用packed结构体节省存储
struct PackedData {
uint128 amount; // 而不是uint256
uint64 timestamp;
uint32 tokenId;
uint32 reserved;
}
// 批量操作减少gas消耗
function batchMint(address[] calldata recipients, uint256[] calldata amounts) external {
require(recipients.length == amounts.length, "Length mismatch");
uint256 length = recipients.length;
for (uint256 i = 0; i < length;) {
_mint(recipients[i], amounts[i]);
unchecked { ++i; } // Gas优化
}
}
}
|
总结
ERC20、ERC721 和 ERC1155 各有其独特的应用场景和优势:
- ERC20 适合创建货币类代币,如治理代币、实用代币和稳定币
- ERC721 专门用于独特的数字资产,如艺术品、域名和身份证明
- ERC1155 提供了最大的灵活性,特别适合需要管理多种资产类型的应用
选择合适的标准需要考虑以下因素:
- 应用需求:同质化 vs 非同质化 vs 混合
- Gas 效率:ERC1155 在批量操作中表现最佳
- 开发复杂度:ERC20 最简单,ERC1155 最复杂
- 生态兼容性:考虑与现有 DeFi、钱包的兼容性