EIP 笔记合集

简介 EIP(Ethereum Improvement Proposal)是以太坊改进提案 任何人都能提交的标准化文档 驱动以太坊从创世区块到今天的唯一正式机制 ERC只是EIP的应用层子集 所有硬分叉升级Layer2变革账户抽象都源于EIP 好的,下面是不含任何表情、按 EIP 状态与类型分类整理的中文笔记版,适合课堂笔记、复习或写作使用。 EIP 状态 EIP(Ethereum Improvement Proposal,以太坊改进提案)在提出、讨论和落地过程中,会经历以下生命周期状态 Idea(想法阶段) 处于预草案阶段,仅是初步构想 不会被记录在官方 EIP 仓库中 通常在论坛、Issue 或社区中进行非正式讨论 Draft(草案阶段) 正式进入 EIP 生命周期的第一个阶段 按 EIP 模板规范化后,由 EIP Editor 合并进仓库 处于持续开发和修改中 Review(评审阶段) 作者认为提案已较为成熟 主动请求社区或同行进行技术评审 重点关注规范完整性、可行性与兼容性 Last Call(最终审查阶段) 进入最终审查窗口,通常为 14 天 由 EIP Editor 指定并设置 last-call-deadline 若发现需要进行规范性修改,将退回 Review 状态 Final(最终状态) 成为正式标准 进入终态,不再进行实质性修改 仅允许修正勘误或补充非规范性说明 Stagnant(停滞状态) Draft 或 Review 状态下,连续 6 个月无实质进展 会被标记为停滞 作者或 Editor 可重新激活并移回 Draft Withdrawn(撤回) 作者主动撤回提案 该状态具有终结性 EIP 编号不可再次使用,重新提出需新编号 Living(持续更新) ...

August 16, 2024 · 2 min · 280 words · Guangyang Zhong

EIP-7702

摘要 引入一种新的EIP-2718交易类型,允许外部拥有账户(EOA)为其账户设置代码。这是通过在交易中附加授权元组列表来实现的,每个元组的格式为[chain_id, address, nonce, y_parity, r, s]。对于每个元组,授权账户的代码将被写入委托指示符0xef0100 || address。所有代码执行操作都必须加载并执行委托指向的代码 动机 尽管智能合约钱包生态系统取得了巨大进步,但EOA阻碍了用户体验改进在整个应用栈中的广泛采用。因此,本EIP重点为EOA添加短期功能改进,使UX改进能够渗透到整个应用栈。本EIP设计的三个特定功能是: 批处理:允许同一用户在单个原子交易中执行多个操作 赞助:账户X代表账户Y支付交易费用 权限降级:用户可以签署子密钥并赋予其特定权限 规范 参数 参数 值 SET_CODE_TX_TYPE 0x04 MAGIC 0x05 PER_AUTH_BASE_COST 12500 PER_EMPTY_ACCOUNT_COST 25000 设置代码交易 引入新的EIP-2718交易类型"设置代码交易",其中: TransactionType为SET_CODE_TX_TYPE TransactionPayload是以下字段的RLP序列化: rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, value, data, access_list, authorization_list, signature_y_parity, signature_r, signature_s]) authorization_list = [[chain_id, address, nonce, y_parity, r, s], ...] 外部交易的字段遵循EIP-4844语义 签名基于keccak256(SET_CODE_TX_TYPE || TransactionPayload) 授权列表长度不能为零 授权元组中的字段必须符合特定边界 行为 在交易执行开始前(发送方nonce递增后)处理授权列表: 对于每个[chain_id, address, nonce, y_parity, r, s]元组: 验证chain ID为0或当前链的ID 验证nonce小于2⁶⁴ - 1 使用ecrecover恢复授权地址 验证签名符合EIP-2标准 将授权地址添加到accessed_addresses 验证授权账户的代码为空或已委托 验证授权账户的nonce匹配 如果授权账户非空,添加gas退款 将授权账户的代码设置为0xef0100 || address(委托指示符) 如果address为全零地址,则清除账户代码 将授权账户的nonce加1 如果任何步骤失败,停止处理当前元组并继续下一个 ...

August 16, 2025 · 1 min · 199 words · Guangyang Zhong

EIP-1967

摘要 委托代理合约被广泛用于可升级性和节省 Gas。这些代理合约依赖于一个逻辑合约(也称为实现合约或主拷贝),通过 delegatecall 进行调用。这使得代理可以保持持久状态(存储和余额),同时将代码执行委托给逻辑合约 为避免代理和逻辑合约之间的存储使用冲突,逻辑合约的地址通常保存在一个特定的存储槽中(例如,OpenZeppelin 合约中的 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc),该槽位保证永远不会被编译器分配。本 EIP 提议一组标准存储槽来保存代理信息。这使得区块浏览器等客户端能够正确提取并向最终用户展示此信息,同时也允许逻辑合约据此执行操作 动机 委托代理被广泛使用,作为支持升级和降低部署 Gas 成本的手段。这类代理的例子可见于 OpenZeppelin Contracts、Gnosis、AragonOS、Melonport、Limechain、WindingTree、Decentraland 等众多项目 一个典型的例子是区块浏览器。最终用户希望与底层逻辑合约交互,而不是代理本身。拥有从代理检索逻辑合约地址的通用方法,允许区块浏览器展示逻辑合约的 ABI 而非代理的 ABI。浏览器通过检查合约在特定存储槽的内容来判断它是否是一个代理,如果是,则同时展示代理和逻辑合约的信息。例如,Etherscan 上对地址 0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48 的展示就是如此 另一个例子是那些明确知晓自身正被代理的逻辑合约。这使得它们可以基于此事实,在其逻辑中触发代码更新。一个通用的存储槽使得这些用例可以独立于所使用的具体代理实现 规范 对代理的监控对许多应用的安全至关重要。因此,必须能够跟踪实现槽和管理员槽的变更。遗憾的是,跟踪存储槽的变更并不容易。因此,建议任何改变这些槽位的函数都应当 同时发出相应的事件。这包括从 0x0 到第一个非零值的初始化 以下是提议的用于存储代理特定信息的存储槽。后续可以根据需要通过其他 ERC 添加更多槽位 逻辑合约地址 存储槽:0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc(通过 bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1) 计算获得) 保存此代理委托调用的逻辑合约地址。如果使用信标,则此槽应当为空。此槽的变更应当通过以下事件通知: event Upgraded(address indexed implementation); 信标合约地址 存储槽:0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50(通过 bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1) 计算获得) 保存此代理所依赖的信标合约地址(作为后备)。如果直接使用逻辑地址,则此槽应当为空,并且仅在逻辑合约地址槽为空时才应考虑。此槽的变更应当通过以下事件通知: event BeaconUpgraded(address indexed beacon); 信标用于在单一位置维护多个代理的逻辑地址,允许通过修改单个存储槽来升级多个代理。信标合约必须实现以下函数: function implementation() returns (address) 基于信标的代理合约不使用逻辑合约地址槽。相反,它们使用信标合约地址槽来存储它们所连接的信标地址。为了了解信标代理所使用的逻辑合约,客户端应当: 从信标逻辑存储槽读取信标地址 调用该信标合约的 implementation() 函数 信标合约上 implementation() 函数的结果不应依赖于调用者 (msg.sender) 管理员地址 存储槽:0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103(通过 bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1) 计算获得) 保存允许为此代理升级逻辑合约地址的地址(可选)。此槽的变更应当通过以下事件通知: event AdminChanged(address previousAdmin, address newAdmin); 原理阐述 本 EIP 标准化了逻辑合约地址的存储槽,而不是在代理合约上提供公开方法。其原理在于,代理永远不应该向最终用户暴露任何可能与逻辑合约函数发生冲突的函数 ...

August 1, 2025 · 1 min · 120 words · Guangyang Zhong

EIP-4337

摘要 引入 UserOperation:一种高层“伪交易对象”,替代直接在共识层提交交易 用户将 UserOperation 发送到单独的 mempool Bundler 将多个 UserOperation 打包,通过 handleOps 调用 EntryPoint 合约,再打包进区块 目标是在不修改以太坊底层协议的情况下,实现账户抽象 动机 实现账户抽象 允许使用智能合约账户作为主账户,支持任意验证逻辑。 用户无需拥有外部账户(EOA)。 去中心化与开放参与 任何 bundler 都可参与交易打包。 依赖公共 mempool,无需用户直接知晓 bundler 地址。 不增加信任假设。 无需共识层修改 避免协议层改动,提高快速部署的可能性。 支持更多应用场景 隐私保护型应用 原子多操作 使用 ERC-20 代币支付手续费或开发者代付 灵活的验证逻辑(不同签名方案、多签、恢复方案) 灵活的手续费支付(第三方支付、跨链支付) 批量操作与打包执行 总结:该提案通过 UserOperation、Bundler 和 EntryPoint 合约实现智能合约账户的完全抽象化,支持多签、代付和批量操作,同时无需修改以太坊共识层 规范 术语定义 术语 定义 UserOperation 一种描述“代表用户发起一笔交易”的数据结构。为避免与原生交易混淆,特意不叫“transaction”。像交易一样,它包含 to、calldata、maxFeePerGas、maxPriorityFeePerGas、nonce、signature。不像交易,它包含以下所述的几个其他字段。特别注意,signature 字段的使用不由协议定义,而是由智能合约账户实现定义 Sender 发起 UserOperation 的智能合约账户 EntryPoint 用于执行 UserOperation 批次的单例合约。Bundler 应白名单支持的 EntryPoint Bundler 一个节点(区块构建者),它能处理 UserOperation、创建有效的 entryPoint.handleOps() 交易,并在交易仍有效时将其添加到区块中。这可以通过多种方式实现:Bundler 可以自己充当区块构建者。如果 bundler 不是区块构建者,它应通过 mev-boost 等基础设施或其他提议者-构建者分离机制与区块构建者合作 Paymaster 同意代替 sender 支付交易费用的辅助合约 Factory 必要时负责部署新 sender 合约的辅助合约 Aggregator 也称为“授权合约” - 一个允许多个 UserOperation 共享一次验证的合约。此类合约的完整设计超出本提案范围 Canonical UserOperation mempool 一个去中心化、无许可的 P2P 网络,bundler 在其中交换符合同一套共享验证规则的合法 UserOperation。具体规则的完整规范超出本提案范围 Alternative UserOperation mempool 任何其他 P2P 内存池,其中 UserOperation 的有效性由不同于共享规则的规则决定,这些规则以任何方式应用于验证代码 Deposit Sender 或 Paymaster 合约向 EntryPoint 合约转入的一笔以太币(或任何 L2 原生货币),用于支付未来 UserOperation 的 gas 费用 UserOperation 结构定义 字段 类型 描述 sender address 发起 UserOperation 的账户 nonce uint256 防重放参数(详见“半抽象 Nonce 支持”) factory address 新账户的账户工厂 OR 0x7702 标志用于 EIP-7702 账户,否则 address(0) factoryData bytes 如果提供 factory,则为账户工厂的数据 OR EIP-7702 初始化数据,或空数组 callData bytes 在主要执行调用期间传递给 sender 的数据 callGasLimit uint256 为主要执行调用分配的 gas 量 verificationGasLimit uint256 为验证步骤分配的 gas 量 preVerificationGas uint256 额外 gas 用于支付 bundler maxFeePerGas uint256 最大 gas 费(类似于 EIP-1559 max_fee_per_gas) maxPriorityFeePerGas uint256 最大优先费(类似于 EIP-1559 max_priority_fee_per_gas) paymaster address paymaster 合约地址(或空,如果 sender 自己支付 gas) paymasterVerificationGasLimit uint256 为 paymaster 验证代码分配的 gas 量(仅当 paymaster 存在时) paymasterPostOpGasLimit uint256 为 paymaster 后操作代码分配的 gas 量(仅当 paymaster 存在时) paymasterData bytes paymaster 的数据(仅当 paymaster 存在时) signature bytes 传入 sender 以验证授权的数据 上链时部分字段会被打包,转变成 PackedUserOperation ...

July 1, 2025 · 7 min · 1476 words · Guangyang Zhong

EIP-2612

摘要 EIP-2612(又称 ERC-2612 / Permit extension for EIP-20)在 EIP-20 基础上新增 permit 接口,允许通过 EIP-712 typed signatures(secp256k1)来更改 allowance,从而无需由 msg.sender 发起 approve 交易 该扩展目的是最小化对现有 ERC-20 生态的入侵,同时解决用户必须持有 ETH 并且需发两笔交易(approve + action)的体验问题 动机 传统 ERC-20 的 approve 以 msg.sender 为准,要求用户必须用 EOA 发起第一次交互(或使用合约钱包)。 当用户要与智能合约交互(例如 deposit、swap 等),往往需要先 approve,再由合约调用 transferFrom:导致至少两笔链上交易、两次 gas 支付。 目标是引入最小、通用且兼容的解决方案,使用户能通过离线签名完成授权,从而可在不持有 ETH 的情况下参与某些操作或把批准与主动作合并成单笔链上交易(例如 depositWithPermit) 注意:合约钱包(contract wallets)也能解决部分问题,但在生态中采纳度较低且需要额外的 UI 适配;permit 方案能在不改动现有 UI 的前提下带来多数好处 规范 合规的实现需要在 ERC-20 基础上实现三项额外函数: function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; function nonces(address owner) external view returns (uint); function DOMAIN_SEPARATOR() external view returns (bytes32); permit 的成功条件: 当前区块时间 block.timestamp 必须 ≤ deadline owner ≠ address(0) nonces[owner](permit 调用前)必须等于消息里包含的 nonce。 v, r, s 必须构成来自 owner 的有效 secp256k1 签名(签名的数据按 EIP-712 的 DOMAIN_SEPARATOR 与 Permit 类型哈希构造) 如果以上任一不满足,permit 必须 revert。成功时应执行: ...

May 1, 2025 · 2 min · 350 words · Guangyang Zhong

EIP-2718

摘要 TransactionType || TransactionPayload 是一个有效的交易格式,TransactionType || ReceiptPayload 是一个有效的交易收据格式,其中: TransactionType 标识交易格式 *Payload 是交易/收据内容,由未来的EIP定义 动机 过去,当我们想要添加新的交易类型时,必须确保它们与所有其他交易向后兼容,这意味着只能根据编码后的有效载荷来区分它们,并且不可能存在匹配两种类型的交易。这在EIP-155中可以看到,新值被位打包到其中一个编码字段中 当前有多个提案正在讨论中,它们定义了新的交易类型,例如: 允许EOA账户直接在其上下文中执行代码的交易 允许msg.sender以外的人支付gas的交易 与第1层多签交易相关的提案 所有这些都需要以相互兼容的方式定义,这很快成为EIP作者和客户端的负担,因为他们现在必须遵循复杂的规则来区分交易类型 通过引入信封交易类型,我们只需要确保与现有交易的向后兼容性,之后我们只需要解决确保TransactionType之间没有编号冲突这个更简单的问题 规范 定义 || 是字节/字节数组连接运算符 交易 从FORK_BLOCK_NUMBER开始,区块头中的交易根必须是patriciaTrie(rlp(Index) => Transaction)的根哈希,其中: Index 是此交易在区块中的索引 Transaction 是以下之一: TransactionType || TransactionPayload LegacyTransaction TransactionType 是一个在0到0x7f之间的无符号8位正整数,表示交易类型 TransactionPayload 是一个不透明的字节数组,其解释取决于TransactionType并由未来的EIP定义 LegacyTransaction 是rlp([nonce, gasPrice, gasLimit, to, value, data, v, r, s]) 所有未来交易类型的签名应该将TransactionType作为签名数据的第一个字节。这样我们就不必担心一种交易类型的签名被用作另一种交易类型的签名 收据 从FORK_BLOCK_NUMBER开始,区块头中的收据根必须是patriciaTrie(rlp(Index) => Receipt)的根哈希,其中: Index 是此收据对应的交易在区块中的索引 Receipt 是以下之一: TransactionType || ReceiptPayload LegacyReceipt TransactionType 是一个在0到0x7f之间的无符号8位正整数,表示交易类型 ReceiptPayload 是一个不透明的字节数组,其解释取决于TransactionType并由未来的EIP定义 LegacyReceipt 是rlp([status, cumulativeGasUsed, logsBloom, logs]) 收据的TransactionType必须与具有匹配Index的交易的TransactionType相匹配 ...

January 1, 2025 · 1 min · 103 words · Guangyang Zhong

EIP-20

摘要 本标准允许在智能合约中实现一个标准化的代币API。它提供了转账代币的基本功能,并允许批准代币以便可以被其他链上第三方花费。 动机 一个标准化的接口允许以太坊上的任何代币被其他应用程序重复使用:从钱包到去中心化交易所 规范 代币 方法 注意: 以下规范使用 Solidity 0.4.17(或更高版本)的语法 调用者必须处理返回 false(bool success)的情况。调用者绝不能假定 >false 永远不会被返回! name 功能:返回代币的名称 - 例如 "MyToken" 可选性:此方法可用于提高可用性,但接口和其他合约绝不能期望这些值一定存在 function name() public view returns (string) symbol 功能:返回代币的符号。例如 "HIX" 可选性:此方法可用于提高可用性,但接口和其他合约绝不能期望这些值一定存在 function symbol() public view returns (string) decimals 功能:返回代币使用的小数位数 - 例如 8,表示将代币数量除以 100000000 以获得其用户表示形式 可选性:此方法可用于提高可用性,但接口和其他合约绝不能期望这些值一定存在 function decimals() public view returns (uint8) totalSupply 功能:返回代币总供应量 function totalSupply() public view returns (uint256) balanceOf 功能:返回地址 _owner 的账户余额 function balanceOf(address _owner) public view returns (uint256 balance) transfer ...

August 20, 2024 · 1 min · 205 words · Guangyang Zhong

EIP-712

摘要 这是一个用于对类型化结构化数据(而不仅仅是字节串)进行哈希和签名的标准。它包括: 理论框架:用于确保编码函数的正确性 结构化数据规范:与 Solidity 结构体类似且兼容 安全哈希算法:用于这些结构体的实例 安全纳入机制:将这些实例纳入可签名消息集合 可扩展的域分离机制 新的 RPC 调用:eth_signTypedData EVM 中哈希算法的优化实现(可选) 不包含重放攻击保护 动机 如果只关心字节串,数据签名是一个已解决的问题。但在现实世界中,我们关心的是复杂且有意义的消息。对结构化数据进行哈希处理并非易事,错误会导致系统安全属性的丧失 因此,“不要自己发明加密算法”(don‘t roll your own crypto)的格言在此适用。我们需要使用经过同行评审、充分测试的标准方法。本 EIP 旨在成为这个标准 本 EIP 旨在提高链下消息签名在链上使用的可用性。链下消息签名因其节省 Gas 和减少链上交易数量而被广泛采用。目前,已签名的消息对用户来说是一个不透明的十六进制字符串,几乎没有关于消息的上下文信息 本提案概述了一种编码数据及其结构的方案,允许在签名时向用户显示信息以供验证 本协议提出前的签名样式: 本协议提出后的签名样式 规范 明白,你是要 Markdown 语法的笔记,但内容保持学术/规范风格,不要花里胡哨。下面是 纯 Markdown、可直接粘到笔记里的版本。 可签名消息集合的扩展 以太坊原本支持对以下两类数据进行签名: 交易(𝕋) 任意字节串(𝔹⁸ⁿ) EIP-712 引入了结构化数据(𝕊)作为新的可签名对象,因此可签名消息集合扩展为: 𝕋 ∪ 𝔹⁸ⁿ ∪ 𝕊 不同类型消息的编码规则 为了便于哈希与签名,不同类型的消息在签名前会被编码为字节串。 1. 交易(𝕋) encode(transaction) = RLP_encode(transaction) 交易签名直接对交易的 RLP 编码结果进行签名,这是以太坊最基础的交易签名方式,用于转账和合约调用。 2. 普通字节串消息(𝔹⁸ⁿ) encode(message) = "\x19Ethereum Signed Message:\n" ‖ len(message) ‖ message 其中 len(message) 是消息字节长度的非零填充 ASCII 十进制编码 该编码方式对应 eth_sign / personal_sign,通过加入固定前缀,防止普通消息被误解释为交易数据 ...

August 20, 2024 · 4 min · 708 words · Guangyang Zhong