乐闻世界logo
搜索文章和话题

什么是以太坊改进提案(EIP)?请解释EIP-1559、ERC-20和ERC-721等重要提案

2月21日 14:16

以太坊改进提案(Ethereum Improvement Proposals, EIPs)是以太坊生态系统中提出新功能、标准或流程改进的正式机制。以下是EIP的全面解析:

EIP的基本概念

EIP是向以太坊社区提出新想法、收集反馈并达成共识的标准化流程。类似于比特币的BIP(Bitcoin Improvement Proposals)。

EIP类型

1. 标准跟踪(Standards Track)

影响大多数或所有以太坊实现的提案,包括网络协议、区块/交易验证规则等。

子类型:

  • Core:核心协议变更(如EIP-1559)
  • Networking:网络协议变更
  • Interface:客户端API变更
  • ERC:应用层标准(如ERC-20、ERC-721)

2. 元EIP(Meta EIP)

改变EIP流程本身的提案。

例子:

  • EIP-1:EIP流程本身

3. 信息性EIP(Informational EIP)

设计问题或通用指南,不提出新功能。

例子:

  • EIP-1:EIP流程指南

EIP流程

1. 提案阶段

markdown
# EIP-XXXX: Title ## Simple Summary 简短描述提案内容 ## Abstract 详细描述提案 ## Motivation 为什么需要这个提案 ## Specification 技术规范 ## Rationale 设计决策的理由 ## Backwards Compatibility 向后兼容性分析 ## Test Cases 测试用例 ## Implementations 实现列表 ## Security Considerations 安全考虑 ## Copyright 版权声明

2. 审查阶段

  • 社区讨论
  • 技术审查
  • 安全审计

3. 最后调用(Last Call)

  • 最终审查
  • 收集最后反馈

4. 合并阶段

  • 合并到协议
  • 部署实施

著名EIP解析

1. EIP-1559:以太坊交易费用市场改革

solidity
// EIP-1559交易结构 struct EIP1559Transaction { uint256 chainId; // 链ID uint256 nonce; // 交易序号 uint256 maxPriorityFeePerGas; // 小费 uint256 maxFeePerGas; // 最大Gas费用 address to; // 接收者 uint256 value; // 转账金额 bytes data; // 交易数据 uint256 accessListLength; // 访问列表长度 AccessListEntry[] accessList; // 访问列表 } // Gas费用计算 function calculateGasFee( uint256 baseFee, uint256 maxPriorityFeePerGas, uint256 maxFeePerGas ) public pure returns (uint256) { uint256 effectivePriorityFeePerGas = min( maxPriorityFeePerGas, maxFeePerGas - baseFee ); return baseFee + effectivePriorityFeePerGas; } function min(uint256 a, uint256 b) internal pure returns (uint256) { return a < b ? a : b; }

特点:

  • 基础费用(Base Fee)自动调整
  • 小费(Tip)激励矿工/验证者
  • 更可预测的交易费用
  • EIP-1559交易类型

2. EIP-20:代币标准

solidity
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; interface IERC20 { event Transfer(address indexed from, address indexed to, uint256 value); event Approval(address indexed owner, address indexed spender, uint256 value); 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); } contract ERC20 is IERC20 { string public name; string public symbol; uint8 public decimals = 18; uint256 public totalSupply; mapping(address => uint256) public balanceOf; mapping(address => mapping(address => uint256)) public allowance; constructor(string memory _name, string memory _symbol, uint256 _totalSupply) { name = _name; symbol = _symbol; totalSupply = _totalSupply; balanceOf[msg.sender] = _totalSupply; emit Transfer(address(0), msg.sender, _totalSupply); } function transfer(address to, uint256 amount) external returns (bool) { _transfer(msg.sender, to, amount); return true; } function approve(address spender, uint256 amount) external returns (bool) { allowance[msg.sender][spender] = amount; emit Approval(msg.sender, spender, amount); return true; } function transferFrom(address from, address to, uint256 amount) external returns (bool) { uint256 currentAllowance = allowance[from][msg.sender]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); allowance[from][msg.sender] = currentAllowance - amount; _transfer(from, to, amount); return true; } function _transfer(address from, address to, uint256 amount) internal { require(balanceOf[from] >= amount, "ERC20: transfer amount exceeds balance"); balanceOf[from] -= amount; balanceOf[to] += amount; emit Transfer(from, to, amount); } }

3. EIP-721:非同质化代币标准

solidity
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; interface IERC721 { event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); function balanceOf(address owner) external view returns (uint256 balance); function ownerOf(uint256 tokenId) external view returns (address owner); function safeTransferFrom(address from, address to, uint256 tokenId) external; function transferFrom(address from, address to, uint256 tokenId) external; function approve(address to, uint256 tokenId) external; function getApproved(uint256 tokenId) external view returns (address operator); function setApprovalForAll(address operator, bool _approved) external; function isApprovedForAll(address owner, address operator) external view returns (bool); } contract ERC721 is IERC721 { string public name; string public symbol; mapping(uint256 => address) public ownerOf; mapping(address => uint256) public balanceOf; mapping(uint256 => address) public getApproved; mapping(address => mapping(address => bool)) public isApprovedForAll; constructor(string memory _name, string memory _symbol) { name = _name; symbol = _symbol; } function transferFrom(address from, address to, uint256 tokenId) external { require(_isApprovedOrOwner(msg.sender, tokenId), "ERC721: transfer caller is not owner nor approved"); _transfer(from, to, tokenId); } function approve(address to, uint256 tokenId) external { address owner = ownerOf[tokenId]; require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "ERC721: approve caller is not owner nor approved for all"); getApproved[tokenId] = to; emit Approval(owner, to, tokenId); } function setApprovalForAll(address operator, bool _approved) external { isApprovedForAll[msg.sender][operator] = _approved; emit ApprovalForAll(msg.sender, operator, _approved); } function _transfer(address from, address to, uint256 tokenId) internal { require(ownerOf[tokenId] == from, "ERC721: transfer from incorrect owner"); require(to != address(0), "ERC721: transfer to the zero address"); delete getApproved[tokenId]; ownerOf[tokenId] = to; balanceOf[from]--; balanceOf[to]++; emit Transfer(from, to, tokenId); } function _isApprovedOrOwner(address spender, uint256 tokenId) internal view returns (bool) { address owner = ownerOf[tokenId]; return (spender == owner || getApproved[tokenId] == spender || isApprovedForAll[owner][spender]); } }

4. EIP-1155:多代币标准

solidity
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; interface IERC1155 { event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value); event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); function balanceOf(address account, uint256 id) external view returns (uint256); function balanceOfBatch(address[] memory accounts, uint256[] memory ids) external view returns (uint256[] memory); function setApprovalForAll(address operator, bool approved) external; function isApprovedForAll(address account, address operator) external view returns (bool); function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes memory data) external; function safeBatchTransferFrom(address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) external; } contract ERC1155 is IERC1155 { mapping(uint256 => mapping(address => uint256)) public balanceOf; mapping(address => mapping(address => bool)) public isApprovedForAll; function balanceOf(address account, uint256 id) external view returns (uint256) { return balanceOf[id][account]; } function balanceOfBatch(address[] memory accounts, uint256[] memory ids) external view returns (uint256[] memory) { require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch"); uint256[] memory batchBalances = new uint256[](accounts.length); for (uint256 i = 0; i < accounts.length; i++) { batchBalances[i] = balanceOf[ids[i]][accounts[i]]; } return batchBalances; } function setApprovalForAll(address operator, bool approved) external { isApprovedForAll[msg.sender][operator] = approved; emit ApprovalForAll(msg.sender, operator, approved); } function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes memory data) external { require(from == msg.sender || isApprovedForAll[from][msg.sender], "ERC1155: caller is not owner nor approved"); require(to != address(0), "ERC1155: transfer to the zero address"); balanceOf[id][from] -= amount; balanceOf[id][to] += amount; emit TransferSingle(msg.sender, from, to, id, amount); } function safeBatchTransferFrom(address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data) external { require(from == msg.sender || isApprovedForAll[from][msg.sender], "ERC1155: caller is not owner nor approved"); require(to != address(0), "ERC1155: transfer to the zero address"); require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch"); for (uint256 i = 0; i < ids.length; i++) { balanceOf[ids[i]][from] -= amounts[i]; balanceOf[ids[i]][to] += amounts[i]; } emit TransferBatch(msg.sender, from, to, ids, amounts); } }

EIP最佳实践

1. 提案准备

  • 充分研究现有EIP
  • 与社区讨论想法
  • 准备详细的技术规范

2. 社区参与

  • 在Ethereum Magicians论坛讨论
  • 在GitHub提交PR
  • 参加社区会议

3. 技术审查

  • 寻求专家审查
  • 进行安全审计
  • 编写测试用例

4. 文档完善

  • 清晰的描述
  • 完整的规范
  • 示例代码

重要EIP列表

核心协议

  • EIP-155:简单重放攻击保护
  • EIP-1559:交易费用市场改革
  • EIP-2930:交易类型访问列表
  • EIP-3074:抽象账户

代币标准

  • EIP-20:ERC-20代币标准
  • EIP-721:ERC-721 NFT标准
  • EIP-1155:多代币标准
  • EIP-777:代币标准(兼容ERC-20)

应用层

  • EIP-137:ENS域名注册
  • EIP-191:签名数据
  • EIP-712:类型化结构化数据哈希和签名
  • EIP-165:标准接口检测

EIP是以太坊演进的重要机制,通过社区协作推动技术创新和标准化。

标签:以太坊