ERC-7936 版本化代理:合约升级不再强迫所有人用最新代码 图 1
ERC-7936 版本化代理:合约升级不再强迫所有人用最新代码 · 图 1

ERC-7936 版本化代理:升级不再强迫所有人用最新代码

“合约升级”是 NFT 持有人最没有安全感的时刻:代理指向新实现的那一刻,无论你是否同意,所有人用的都是同一份新代码。ERC-7936 提出一个改良的代理模式——代理合约同时登记多个版本的实现地址,调用方可以在发起调用时点名要用哪个版本。2026 年 9 月 9 日在 ethereum/ERCs 仓库核对,该提案处于 Review 状态,2025 年 4 月创建。

把”最新版本”变成”默认版本”

传统透明代理或 UUPS 代理只保存一个实现地址,升级即替换。ERC-7936 的代理维护一张版本登记表:registerVersion(bytes32 version, address implementation) 登记一个版本标识到实现地址的映射,removeVersionsetDefaultVersion 管理登记表和默认指向,查询侧有 getImplementation(version)getDefaultVersiongetVersions()。真正的关键在 executeAtVersion(bytes32 version, bytes calldata data):调用者把想要的版本号和原本要调用的数据一起交进来,代理按指定版本转发。

这套结构解决三类具体痛点。第一是接口断裂:新版实现改了函数签名,老集成方可以钉在旧版本上继续工作而不是立刻崩掉。第二是渐进采用:不同市场、不同合约可以按各自节奏切换。第三,也是对持有人最有意义的一条——面对可疑升级,用户第一次有了”不退出协议但不用新代码”的中间选项:继续调用旧版本,观察新实现,而不是被迫在”全信”与”彻底离开”之间二选一。

权限视角的冷思考

版本登记表本身是权力和风险的新载体,读规范时要带着三个问题。谁来调用 registerVersion:登记权如果握在单一带外,恶意者可以登记一个钓鱼实现再诱导工具去解析它;合理配置通常是多签或治理,且登记与设为默认分开更稳。版本能否删除:removeVersion 的存在意味着”钉住旧版本”不是绝对保险——管理员可以把旧实现从表上摘掉,届时指定该版本的调用将失败。登记表完整性检查:链上调用 getVersions() 数一遍历史版本,与项目公告的升级史对得上吗,凭空多出的版本标识值得追问。

还要澄清一个容易夸大的点:ERC-7936 不提供”用户投票选版本”之类机制,默认版本仍由合约管理员设定;它给的是个体层面的选择权,且只有尊重显式版本参数的工具才用得上。如果某个市场永远用默认版本发起调用,你个人”钉住旧版”的意愿在这条路径上就不生效——选择权的实际半径取决于你的调用方式。

与常见升级方案的相处方式

版本化代理并非从零发明,而是站在熟悉的模式上走半步。把它放进谱系里看会更清楚:透明代理与 UUPS 把”当前实现”当成唯一事实,UUPS 还把升级逻辑塞进实现本身;钻石代理用选择器级路由分散实现,定位某个函数的归属本来就绕;ERC-1967 那一类则解决”用标准存储槽找实现地址”的可读性问题。ERC-7936 的定位介于其间——它不接管函数选择器的路由细节,而是显式地把”版本”提升为调用参数,把选择权交给发起方。对安全审计,它引入的新审计对象是登记表逻辑与默认版本切换逻辑,这两处是过去审计清单里没有的条目,翻代码时值得单独过一遍。

顺带一句对治理项目的提示:把”升级”改造成”发版”会改变治理动力学——旧版本继续可用意味着恶意或劣质升级的伤害半径收缩,但”回滚”也不再一劳永逸,因为总有调用者钉在出事的那一版上。升级预案要相应改写:通知链上登记新版本、标记不推荐版本、给出迁移指引,一套都不能少。

持有人怎么利用这个结构

如果你持有的合集用版本化代理部署,值得做三件一次性工作:查代理地址上的 getVersions() 与默认版本,确认当前默认实现地址与官方公示一致;把每个版本号对应的实现地址记进持仓档案,日后升级纠纷时能精确指认”事故发生在第几版”;留意 removeVersion 事件的授权地址,那实质上就是这份合约的生死开关持有人之一。

对开发者,采纳这个标准还带来一个副产品:测试网与主网可以共用代理逻辑做多版本回归。对普通用户,不必因为它降低了升级焦虑就忽略更基本的事实——能升级的合约,风险大头永远在”谁有权升级、往哪个方向改”,版本可选只是把被动挨刀改成了多看一眼再走。本文为机制科普,不构成投资建议;提案状态以 ethereum/ERCs 仓库为准(核验时间 2026 年 9 月 9 日)。