如何在纯Yul代码中使用setimmutable与loadimmutable?
在Yul中使用setimmutable和loadimmutable实现燃气高效的immutable变量
Yul的setimmutable和loadimmutable是专门用于处理部署后不可修改、读取燃气成本极低的immutable变量的内置指令。这类变量的值在合约部署阶段设置,运行时直接从代码段加载,无需访问存储(SLOAD),能大幅降低读取操作的燃气消耗。
核心用法说明
setimmutable(key, value):仅能在合约部署阶段(构造函数)调用,将value绑定到唯一的key(通常是字符串标识),存入immutable存储。loadimmutable(key):运行时调用,通过key读取之前设置的immutable变量值,燃气成本远低于存储读取。
使用Yul对象表示法的完整示例
下面是一个实现immutable owner地址的合约示例,采用Yul标准对象表示法分离构造函数和运行时代码:
object "ImmutableOwnerContract" { // 构造函数代码:部署阶段执行 code { // 获取合约部署者地址 let deployer := caller() // 将deployer地址绑定到"owner"这个key,设置为immutable变量 setimmutable("owner", deployer) // 返回运行时代码(Runtime子对象的内容) return(0, datasize("Runtime")) } // 运行时代码:部署后合约执行的逻辑 object "Runtime" { code { // 复制调用数据到内存 calldatacopy(0, 0, calldatasize()) // 提取函数选择器(前4字节) let selector := calldataload(0) // 匹配getOwner()函数的选择器:0x2f865bd9 if eq(selector, 0x2f865bd900000000000000000000000000000000000000000000000000000000) { // 读取immutable的owner变量 let owner := loadimmutable("owner") // 将owner地址写入内存,准备返回 mstore(0, owner) // 返回32字节的地址数据 return(0, 32) } // 处理不匹配的函数调用,直接回退 revert(0, 0) } } }
代码解析
- 外层对象:
ImmutableOwnerContract作为根对象,包含构造函数代码和运行时子对象。 - 构造函数逻辑:部署时获取调用者地址,用
setimmutable将其设置为immutable变量,然后返回运行时代码替换合约的可执行逻辑。 - 运行时逻辑:处理外部函数调用,当匹配
getOwner()的选择器时,用loadimmutable读取预存的owner地址并返回,全程无需访问存储。
关键注意事项
- immutable变量仅能在部署阶段设置,运行时无法修改,
setimmutable在运行时调用会直接报错。 key是区分不同immutable变量的唯一标识,建议使用语义化的字符串(如"owner"、"feeRate"),避免冲突。- Yul对象表示法将构造函数和运行时代码分离,确保部署后链上仅保留运行时逻辑,优化合约字节码大小。
内容的提问来源于stack exchange,提问作者Ricsson Ngo
相关产品推荐
相关产品推荐

