EIP-6968 解析:在 EVM 系 L2 上实现 Contract Secured Revenue(合约担保收入)
【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs
导读
EIP-6968(Contract Secured Revenue on an EVM based L2)提出了一套让智能合约开发者按比例分享用户交易手续费收入的协议机制:通过修改 EIP-1559 的费用模型,将每单位 gas 中的一部分基础费按实际 gas 消耗比例重新分配给交易中执行过的合约。本文以 EIPS/eip-6968.md 为骨架,结合仓库内 EIP-1559 的参考实现与 EIP-150 的 gas 规则,逐层拆解其费用分配模型、gas 追踪算法、SETREVENUERECIPIENT新指令的设计,以及它对 L2 生态(开发者收入、公共物品融资、dapp 迁移激励)的潜在价值,读完后你将完整掌握 CSR 协议的核心机制与实现要点。
一、背景与动机:为什么是 L2,而不是 L1
1.1 什么是 Contract Secured Revenue
Contract Secured Revenue(CSR,合约担保收入)的核心思想非常直接:允许智能合约开发者认领用户与他们的合约交互时所支付交易费用中的一定比例。传统模式下,用户支付的 gas 费用被矿工(优先级费)和协议(燃烧的基础费)瓜分,而创造实际价值的合约开发者一无所获;CSR 试图改变这一分配格局。
1.2 明确的范围边界
EIP-6968 有一个重要的立场声明:它不主张对现有以太坊 L1 做任何改动。原文明确指出:
Using protocol rewards of an L1 to fund smart contract development would be a big change to the way the current market works. This EIPdoes notadvocate for any changes to the existing Ethereum L1.
它只是倡导 L2 网络可以把 CSR 作为一种实验手段,用于达成三个目标:
- 为智能合约开发者创造新的收入来源;
- 创造一种为公共物品(public goods)融资的新方式;
- 创造激励,吸引开发者将自己的 dapp 部署到该网络上。
从经济逻辑看,这三点是自洽的:L2 需要流动性与应用生态,而应用开发者需要收入激励;把一部分协议收入让渡给合约开发者,相当于用「开发者分红」换取生态繁荣,是一种以协议收入补贴供给侧的市场策略。
1.3 与现有费用模型的关系
CSR 并非推翻 EIP-1559,而是在其基础费分配逻辑之上做增量修改。理解这一点需要先回顾 eip-1559.md 的关键机制:
- 每笔交易支付
base_fee_per_gas(基础费)与priority_fee_per_gas(优先级费)两部分; - 基础费被协议销毁(burn),不归矿工所有——这是 EIP-1559 确保 ETH 价值锚定、降低 MEV 风险、去除矿工操纵费用动机的关键设计;
- 矿工只能保留优先级费;
- 基础费随区块拥堵程度上下浮动:区块 gas 用量高于目标值时上调、低于目标值时下调。
EIP-6968 正是看中了基础费被销毁这一「资金池」:既然这笔钱不归属任何人,那么在 L2 上将其中的一部分按比例再分配给合约,就构成了一种新的收入流,而不与矿工/排序者的既有激励直接冲突。
二、核心规范:参数与费用分配机制
2.1 参数定义
| 常量 | 值 |
|---|---|
REVENUE_SHARE_QUOTIENT | 5 |
这是整个 CSR 协议唯一引入的协议级常量,含义是:每单位 gas 中,基础费的1/5(即 20%)被重新分配给交易中执行过的合约。
2.2 费用机制的修改
规范对 EIP-1559 费用行为的修改如下:
header.base_fee_per_gas * REVENUE_SHARE_QUOTIENTper gas is reallocated proportionally, based on gas used, to each contract executed during the transaction.
原文写的是base_fee_per_gas * REVENUE_SHARE_QUOTIENT,结合REVENUE_SHARE_QUOTIENT = 5以及后文分散收入的公式gas_used * (header.base_fee_per_gas // REVENUE_SHARE_QUOTIENT),可以确定其实际语义为:每单位 gas 提取基础费的1/5,按该地址在本笔交易中消耗的 gas 比例分配(//为向下取整的整数除法,这一记号与 eip-1559.md 参考实现中base_fee_per_gas_delta的计算保持一致)。
分配有一个隐含推论:没有任何收入会被分配给外部拥有账户(EOA)。因为分配对象是「交易中执行过的合约」,纯 EOA 转账(无合约调用)天然不产生任何分配,这也意味着 CSR 不改变 EOA 之间的普通转账经济。
2.3 分配发生在基础费而非优先级费上
值得强调的是,被再分配的资金来源是基础费部分。优先级费(priority fee)仍然全额归区块生产者(L1 为矿工、L2 为排序器),基础费在销毁前先切出 20% 进入 CSR 分配池。这样既保留了 EIP-1559 的拥堵定价功能,又为合约创造了收入,且不侵蚀验证/排序激励。
三、Gas 追踪:按地址精确计量消耗
3.1 交易级 gas 追踪映射
要「按比例」公平分配,就必须知道每笔交易中每个合约地址消耗了多少 gas。为此,规范定义了一个交易级(transaction-wide)的追踪结构:
- 执行区块时维护映射
gas_used_by_address:address -> uint64; - 记录每个地址在本笔交易中累计消耗的 gas。
3.2 非新帧指令:直接累加
对于**不会实例化新执行帧(execution frame)**的 EVM 指令——如CALL、CALLCODE、DELEGATECALL、STATICCALL、CREATE、CREATE2之外的普通指令——处理方式最简单:将指令本身的 gas 成本直接累加到当前执行地址的累计值上。这里需要仔细区分:CALL家族指令虽然会跳转执行目标合约代码,但它们本身属于「调用发起方」的执行帧,其基础成本仍记在发起方名下。
3.3 新帧指令:成本 = 总成本 − 传递给子帧的 gas
对于会实例化新帧的指令(CALL、CALLCODE、DELEGATECALL、STATICCALL、CREATE、CREATE2),需要更精细地界定「对调用方帧的代价」。规范给出的定义是:
该指令对调用方的成本 = 该操作的总成本 − 传递给子帧的 gas 量
而「传递给子帧的 gas」由 EIP-150(Tangerine Whistle 分叉引入的 63/64 规则)确定。回顾 eip-150.md 的规范:
- 定义「N 的除六十四分之一之外的全部」为
N - floor(N / 64); - 若调用请求的 gas 超过最大值(父帧剩余 gas 减去调用及内存扩展成本),不返回 OOG 错误;若请求超过「除六十四分之一之外的全部」,则以
max_call_gas(gas) = gas - (gas // 64)执行; CREATE只向子调用提供父帧 gas 的 63/64。
这意味着:调用方实际「交给」子帧的 gas 是min(请求值, 调用方剩余 gas 的 63/64)(CREATE 则恒为 63/64)。CSR 的 gas 追踪正是利用这一确定性的数量关系,把「传给子帧的部分」从调用指令总成本中扣除——被扣除的部分将归属于被调用合约的执行帧,而非调用方。
3.4 边界与异常规则
规范还明确了三条边界规则,确保追踪的完整性:
- 地址不存在于映射时:其累计 gas 用量视为
0(惰性初始化的等价语义,无需为每个地址预先分配槽位); - 指令抛出 OOG(out-of-gas)错误时:执行帧中剩余的全部 gas都累加到该地址的累计用量中——因为 OOG 意味着整个剩余 gas 都被耗尽;
- 其他类型的异常停机(exceptional halt):不把剩余 gas 计入发生停机地址的计数器——只有 OOG 有这种「清算剩余额度」的待遇。
这条设计的精妙之处在于:OOG 是「gas 被实际烧掉」的明确信号,将剩余 gas 计入该地址,恰好与实际发生的费用消耗吻合;而其他异常停机(如无效操作码、栈溢出)不应扭曲分配结果。
四、设置收入接收方:SETREVENUERECIPIENT指令
4.1 收益接收方映射
CSR 引入第二个交易级映射revenue_recipient:address -> address,记录每个合约地址的收入接收方。其默认值是键本身:
除非显式设置,否则键
0xdead...beef映射到值0xdead...beef。
也就是说,默认情况下合约收入归合约自己(即部署该合约的开发者所控制的合约地址)。
4.2 新指令规格
若要改变收入接收方,规范引入了一条新 EVM 指令:
- 指令名:
SETREVENUERECIPIENT - 操作码:
0x49 - 栈行为:取
1个栈元素作为输入,输出0个栈元素 - 语义:输入栈元素的低 20 个字节(最不显著的 20 字节)即为调用者(caller)的新收入接收方地址;
revenue_recipient中调用者的条目被更新为该地址 - gas 成本:
3gas
低 20 字节截断的处理方式与 EVM 中地址相关指令的惯例一致:栈元素本身是 256 位宽,地址只占低 160 位,高位被忽略。这使得开发者可以用一条指令、极低的成本,在合约内动态指定收入去向——例如把收入指向某个金库合约、DAO 或公共物品基金。
4.3 与「先设置后收取」的关系
由于收入分配发生在交易完成后(见下一节),而SETREVENUERECIPIENT在交易执行期间生效,因此同一笔交易内先调用SETREVENUERECIPIENT、再被其他合约调用,即可让本笔交易的收入流入新指定的地址——这为「分账合约」「收入路由」等模式提供了实现空间。
五、收入分散:交易完成后的清算
5.1 分配公式
交易执行完毕后,对gas_used_by_address中的每一个条目(addr, gas_used):
将
revenue_recipient[addr]的余额增加gas_used * (header.base_fee_per_gas // REVENUE_SHARE_QUOTIENT)
即每个合约地址获得的收入 = 该地址在本笔交易中消耗的 gas ×(本区块基础费 ÷ 5)。由于base_fee_per_gas是区块级常量、REVENUE_SHARE_QUOTIENT是协议常量,二者只计算一次,然后按各地址的 gas 用量线性放大,整个清算过程是纯算术操作,不涉及状态读取以外的复杂逻辑。
5.2 一个直观的计算示例
假设某 L2 区块的base_fee_per_gas = 50 gwei,则base_fee_per_gas // REVENUE_SHARE_QUOTIENT = 10 gwei。若某笔交易中合约 A 消耗 100,000 gas、合约 B 消耗 50,000 gas,则交易结束后:
- 合约 A 的接收方获得
100,000 × 10 gwei = 0.001 ETH; - 合约 B 的接收方获得
50,000 × 10 gwei = 0.0005 ETH。
整笔交易中,用户为这 150,000 gas 支付的基础费为150,000 × 50 gwei = 0.0075 ETH,其中 20%(0.0015 ETH)进入 CSR 分配,其余 80%(0.006 ETH)仍按 EIP-1559 逻辑销毁(或由各 L2 自定)。
5.3 生命周期小结
CSR 的完整数据流可以概括为四个阶段:
- 执行前:初始化交易级映射
gas_used_by_address与revenue_recipient(后者默认值为键自身); - 执行中:逐指令累计各地址 gas 用量;合约可通过
SETREVENUERECIPIENT(操作码0x49)重定向自己的收入接收方; - 执行后:按
gas_used × (base_fee_per_gas // 5)为每个地址的接收方增加余额; - 区块级:上述过程对区块内每笔交易重复执行,形成区块收入分配。
六、设计权衡(Rationale):为什么这样做
6.1 为什么按比例追踪 gas,而不是把整笔收入给to
一个更简单的方案是:把整笔交易的收入全部发送给交易的to地址。规范明确否定了这一方案,理由有二:
- 无法准确奖励合约组合:现代 dapp 交易往往由多个合约协作完成(路由、池子、适配器等),把全部收入给
to无法反映各合约的真实贡献; - 与智能合约钱包不兼容:合约钱包(smart contract wallets)常常本身就是交易的第一个目的地,若按
to分配,钱包地址会拿走大部分收入,而真正执行业务逻辑的合约反而一无所获。
而维护交易级 gas 追踪,能够把收入分配给真正被重度使用的合约,与「按实际使用付费」的直觉一致。
6.2 为什么接收方映射是「临时(ephemeral)」的
表面上,每笔交易都临时构造revenue_recipient映射看起来低效——毕竟接收方大概率长期不变,即便要变,也可以由接收方合约内部自行转发。但规范指出:把接收方持久化存储对 EVM 的侵入性要大得多:
- 接收方值必须存在某处,这要求修改状态树中的账户结构(account structure in the state trie);
- 接收方值必须在某个时点被初始化,这要求要么修改
CREATE*系列操作码,要么像SETREVENUERECIPIENT这样引入一条由 initcode 调用的「初始化接收方」的新指令。
两相对比,交易级临时映射虽然每笔交易都重建,但完全不需要改动状态树结构,实现成本与共识风险都更低,是一种以计算换取协议简洁性的务实取舍。
七、安全考量
7.1 区块大小与复杂度的增加
EIP-6968 明确承认,与 EIP-1559 一样,必须考虑该机制对区块大小的影响:
取决于实现方式,若大量合约选择接入 CSR,区块最大尺寸可能增大。
具体而言,为完成收入分配,区块执行引擎需要在交易与区块级别维护映射、并在执行后进行余额更新,这会增加状态写入量与内存占用;当大量合约「选择接入」CSR 时,区块处理复杂度的上限会被推高。这一节是规范作者主动暴露的风险提示:任何 L2 采纳该协议时,都需要在区块 gas 上限与实现路径(例如是否以收据/日志方式结算、是否将分配池化处理)上做额外评估。
7.2 其他值得注意的实现边界
结合规范全文可以归纳出实现者需额外注意的几点:
- 整数除法方向:
base_fee_per_gas // REVENUE_SHARE_QUOTIENT必须统一为向下取整,避免不同客户端因舍入差异产生状态分歧; - OOG 剩余 gas 清算:只有 OOG 会把剩余 gas 计入地址计数器,实现时需确保异常处理路径与该规则一致;
- EOA 豁免:分配池只覆盖合约执行,实现应保证纯 EOA 交易不产生任何分配,避免非预期铸币。
八、状态与生态意义
8.1 提案状态
EIP-6968 当前状态为Stagnant(停滞)。依据 eip-1.md 的定义:处于 Draft/Review/Last Call 状态的 EIP 若超过 6 个月无活动,将被移至 Stagnant;作者或 EIP 编辑可将其移回 Draft 或更早状态以「复活」。因此该提案属于已提出但未激活的标准轨道提案(Standards Track / Core 类别),其价值更多体现在为 L2 提供了一套可参考、可实验的协议设计蓝图。
8.2 对 L2 生态的三重价值
回到动机部分,CSR 对 L2 的吸引力在于它同时击中三个痛点:
- 开发者收入:合约开发者不再依赖发币或抽成,而是直接从用户交互产生的协议收入中获得稳定分成;
- 公共物品融资:开发者(或协议)可以把
SETREVENUERECIPIENT指向公共物品基金,形成「使用即捐赠」的自持续融资流; - 生态竞争工具:对尚在争夺开发者的 L2 而言,CSR 是一种差异化的「开发者分红」政策,可降低 dapp 迁移的机会成本。
8.3 与 EIP-1559 的协同关系
最后再次强调本提案的定位:它不修改EIP-1559 的定价与燃烧机制,只在基础费销毁前切出固定比例(1/REVENUE_SHARE_QUOTIENT = 20%)进入合约分配池。eip-1559.md 中Block.base_fee_per_gas、priority_fee_per_gas的计算与校验逻辑(见其参考实现validate_block中基础费调整公式)在 CSR 下原样保留,L2 实现者只需在「执行交易 → 清算费用」之间插入 CSR 的追踪与分配阶段即可。
结语
EIP-6968 用极简的参数(一个常量、两个交易级映射、一条新指令)勾勒出了一套完整的「合约收入分成」协议:按 gas 消耗比例分配基础费收入的 20%,通过SETREVENUERECIPIENT允许合约自主路由收入去向,并以 OOG 清算与 63/64 规则保证计量的公平与确定性。虽然该提案目前处于 Stagnant 状态、并未在任何 L1 生效,但它为 EVM 系 L2 提供了一份可直接借鉴的机制设计范本——对研究费用经济学、设计 L2 激励模型或实现自定义费用分成的开发者而言,eip-6968.md 是一份值得精读的规范原文。
【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考